Question Comment fonctionne le décorateur @property?
Je voudrais comprendre comment la fonction intégrée property
travaux. Ce qui me trouble est que property
peut également être utilisé comme décorateur, mais il ne prend des arguments que lorsqu'il est utilisé comme fonction intégrée et non lorsqu'il est utilisé comme décorateur.
Cet exemple provient du 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.")
property
Les arguments de getx
, setx
, delx
et une chaîne de doc.
Dans le code ci-dessous property
est utilisé comme décorateur. L'objet en est le x
fonction, 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 les x.setter
et x.deleter
décorateurs créés?
Je suis confus.
660
2018-06-26 20:47
origine
Réponses:
le property()
fonction renvoie un spécial objet descripteur:
>>> property()
<property object at 0x10ff07940>
C'est cet objet qui a supplémentaire méthodes:
>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>
Ceux-ci agissent comme décorateurs aussi. Ils renvoient un nouvel objet de propriété:
>>> property().getter(None)
<property object at 0x10ff079f0>
c'est une copie de l'ancien objet, mais avec l'une des fonctions remplacées.
Rappelez-vous, que le @decorator
la syntaxe est juste du sucre syntaxique; la syntaxe:
@property
def foo(self): return self._foo
signifie vraiment la même chose que
def foo(self): return self._foo
foo = property(foo)
alors foo
la fonction est remplacée par property(foo)
, que nous avons vu ci-dessus est un objet spécial. Puis quand vous utilisez @foo.setter()
, ce que tu fais s'appelle ça property().setter
méthode que je vous ai montré ci-dessus, qui renvoie une nouvelle copie de la propriété, mais cette fois avec la fonction setter remplacée par la méthode décorée.
La séquence suivante crée également une propriété complète, en utilisant ces méthodes de décorateur.
D'abord, nous créons des fonctions et un property
objet avec juste un getter:
>>> def getter(self): print 'Get!'
...
>>> def setter(self, value): print 'Set to {!r}!'.format(value)
...
>>> def deleter(self): print 'Delete!'
...
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True
Ensuite, nous utilisons le .setter()
méthode pour ajouter un setter:
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
Dernier nous ajoutons un deleter avec le .deleter()
méthode:
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
Last but not least, le property
objet agit comme objet descripteur, donc il a .__get__()
, .__set__()
et .__delete__()
méthodes pour accrocher dans l'attribut d'instance obtenir, définir et supprimer:
>>> class Foo(object): pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
Le descripteur Howto comprend un implémentation d'un échantillon python pur du property()
type:
class Property(object):
"Emulate PyProperty_Type() in Objects/descrobject.c"
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(obj)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel, self.__doc__)
740
2018-06-26 20:54
La documentation dit C'est juste un raccourci pour créer des propriétés en lecture seule. Alors
@property
def x(self):
return self._x
est équivalent à
def getx(self):
return self._x
x = property(getx)
102
2018-06-26 20:52
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 un
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): ...
retourne une nouvelle propriété qui hérite tout de l'ancien x
plus le setter donné.
x.deleter
fonctionne de la même manière.
62
2018-06-26 20:53
Voici un exemple minimal de comment @property
peut être implémenté:
class Thing:
def __init__(self, my_word):
self._word = my_word
@property
def word(self):
return self._word
>>> print( Thing('ok').word )
'ok'
Autrement word
reste une méthode au lieu d'une propriété.
class Thing:
def __init__(self, my_word):
self._word = my_word
def word(self):
return self._word
>>> print( Thing('ok').word() )
'ok'
48
2018-02-15 00:46
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
24
2018-05-24 18:38
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 l'attribut "caché" password
en utilisant @property
ce qui déclenche AttributeError
assertion 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 en 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()
...
Attribut de notification password
cela vient d'un formulaire d'inscription lorsqu'un utilisateur remplit le formulaire. La confirmation du mot de passe se produit à l'avant avec EqualTo('password', message='Passwords must match')
(dans le cas où vous vous poseriez la question, mais c'est un sujet différent lié aux formes Flask).
J'espère que cet exemple sera utile
4
2018-03-23 14:47
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 à propriété fonction
- En utilisant le @propriété décorateur.
Vous pouvez jeter un oeil à quelques exemples sur lesquels j'ai écrit propriétés en python.
1
2017-07-13 09:20