我想了解内置函数属性是如何工作的。让我困惑的是,属性也可以用作装饰器,但它只在用作内置函数时接受参数,而在用作装饰器时不接受参数。
下面的例子来自文档:
class C:
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
属性的参数是getx, setx, delx和一个doc字符串。
在下面的代码中,属性被用作装饰器。它的对象是x函数,但在上面的代码中,参数中没有对象函数的位置。
class C:
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
在本例中,如何创建x.setter和x.deleter装饰器?
Property是@property装饰器后面的一个类。
你可以检查这个:
print(property) #<class 'property'>
我重写了help(property)中的示例,以显示@property语法
class C:
def __init__(self):
self._x=None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
c = C()
c.x="a"
print(c.x)
函数上与property()语法相同:
class C:
def __init__(self):
self._x=None
def g(self):
return self._x
def s(self, v):
self._x = v
def d(self):
del self._x
prop = property(g,s,d)
c = C()
c.x="a"
print(c.x)
正如你所看到的,我们如何使用这块土地并没有什么不同。
要回答这个问题,@property decorator是通过属性类实现的。
问题是稍微解释一下属性类。
这条线:
prop = property(g,s,d)
是初始化。我们可以这样重写:
prop = property(fget=g,fset=s,fdel=d)
fget、fset、fdel的含义:
| fget
| function to be used for getting an attribute value
| fset
| function to be used for setting an attribute value
| fdel
| function to be used for del'ing an attribute
| doc
| docstring
下一张图片显示了我们拥有的三胞胎,来自class属性:
__get__, __set__和__delete__将被覆盖。这是Python中描述符模式的实现。
通常,描述符是具有“绑定行为”的对象属性,其属性访问已被描述符协议中的方法覆盖。
我们还可以使用属性setter、getter和delete方法将函数绑定到属性。请看下一个例子。类C的方法s2将属性设置为double。
class C:
def __init__(self):
self._x=None
def g(self):
return self._x
def s(self, x):
self._x = x
def d(self):
del self._x
def s2(self,x):
self._x=x+x
x=property(g)
x=x.setter(s)
x=x.deleter(d)
c = C()
c.x="a"
print(c.x) # outputs "a"
C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x) # outputs "aa"
我读了这里所有的帖子,意识到我们可能需要一个现实生活中的例子。为什么要用@property?
因此,考虑一个使用身份验证系统的Flask应用程序。
在models.py中声明一个模型User:
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
...
@property
def password(self):
raise AttributeError('password is not a readable attribute')
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def verify_password(self, password):
return check_password_hash(self.password_hash, password)
在这段代码中,我们通过使用@property来“隐藏”属性密码,当你试图直接访问它时,它会触发AttributeError断言,而我们使用@property。Setter设置实际的实例变量password_hash。
现在在auth/views.py中,我们可以实例化一个User:
...
@auth.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
user = User(email=form.email.data,
username=form.username.data,
password=form.password.data)
db.session.add(user)
db.session.commit()
...
注意用户填写注册表单时来自注册表单的属性密码。密码确认发生在EqualTo的前端(' Password ', message='密码必须匹配')(如果你想知道,但这是一个与Flask表单相关的不同主题)。
我希望这个例子对大家有用
这之后:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
等于:
class C(object):
def __init__(self):
self._x = None
def _x_get(self):
return self._x
def _x_set(self, value):
self._x = value
def _x_del(self):
del self._x
x = property(_x_get, _x_set, _x_del,
"I'm the 'x' property.")
等于:
class C(object):
def __init__(self):
self._x = None
def _x_get(self):
return self._x
def _x_set(self, value):
self._x = value
def _x_del(self):
del self._x
x = property(_x_get, doc="I'm the 'x' property.")
x = x.setter(_x_set)
x = x.deleter(_x_del)
等于:
class C(object):
def __init__(self):
self._x = None
def _x_get(self):
return self._x
x = property(_x_get, doc="I'm the 'x' property.")
def _x_set(self, value):
self._x = value
x = x.setter(_x_set)
def _x_del(self):
del self._x
x = x.deleter(_x_del)
也就是:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x