python - with - Comment fonctionne le décorateur @property?




python property yield (5)

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

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.


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)






python-internals