python - with - Comment fonctionne le décorateur @property?
python property yield (5)
Je voudrais comprendre comment la property
fonction intégrée fonctionne. Ce qui me dérange, c'est que la property
peut également être utilisée comme décorateur, mais elle ne prend des arguments que lorsqu'elle est utilisée comme fonction intégrée et non lorsqu'elle est utilisée comme décorateur.
Cet exemple provient de la documentation :
class C(object):
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.")
Les arguments de la property
sont getx
, setx
, delx
et une chaîne doc.
Dans le code ci-dessous la property
est utilisée comme décorateur. L'objet en est la fonction x
, mais dans le code ci-dessus, il n'y a pas de place pour une fonction d'objet dans les arguments.
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
Et, comment sont x.deleter
décorateurs x.setter
et x.deleter
? Je suis confus.
Ce qui suit:
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
Est le même que:
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.")
Est le même que:
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)
Est le même que:
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)
Ce qui est le même que:
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
J'ai lu tous les messages ici et réalisé que nous pourrions avoir besoin d'un exemple réel, Pourquoi, en fait, nous avons @property? Donc, considérez une application Flask où vous utilisez un système d'authentification. Vous déclarez un utilisateur modèle dans models.py
:
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)
Dans ce code, nous avons "caché" l'attribut password
en utilisant @property
qui déclenche l'assertion AttributeError
lorsque vous essayez d'y accéder directement, alors que nous avons utilisé @ property.setter pour définir la variable d'instance réelle password_hash
.
Maintenant, dans auth/views.py
nous pouvons instancier un utilisateur avec:
...
@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()
...
Notez le password
attribut provenant d'un formulaire d'inscription lorsqu'un utilisateur remplit le formulaire. La confirmation du mot de passe se fait sur le frontal avec EqualTo('password', message='Passwords must match')
(au cas où vous vous poseriez la question, mais il s'agit d'un sujet différent).
J'espère que cet exemple sera utile
La première partie est simple:
@property
def x(self): ...
est le même que
def x(self): ...
x = property(x)
- qui, à son tour, est la syntaxe simplifiée pour créer une
property
avec juste un getter.
L'étape suivante consisterait à étendre cette propriété avec un setter et un deleter. Et cela arrive avec les méthodes appropriées:
@x.setter
def x(self, value): ...
renvoie une nouvelle propriété qui hérite de tout l'ancien x
plus le setter donné.
x.deleter
fonctionne de la même manière.
Une propriété peut être déclarée de deux façons.
- Création du getter, mise en place de méthodes pour un attribut, puis passage de celles-ci en tant qu'argument à la fonction de propriété
- En utilisant le décorateur @property .
Vous pouvez jeter un oeil à quelques exemples que j'ai écrits sur les propriétés en python .
documentation c'est juste un raccourci pour créer des propriétés readonly. Alors
@property
def x(self):
return self._x
est équivalent à
def getx(self):
return self._x
x = property(getx)