Je voudrais comprendre comment fonctionne la property
fonction intégrée . Ce qui m'embrouille, c'est qu'il 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 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.")
property
Les arguments « sont getx
, setx
, delx
et une chaîne de doc.
Dans le code ci property
- dessous est utilisé comme décorateur. Son objet est la x
fonction, mais dans le code ci-dessus, il n'y a pas de place pour une fonction 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 les décorateurs x.setter
et sont-ils x.deleter
créés? Je suis confus.
property
est en fait une classe (pas une fonction), bien qu'elle appelle probablement la__init__()
méthode lorsque vous créez un objet, bien sûr. L'utilisation àhelp(property)
partir du terminal est utile.help
est également une classe pour une raison quelconque.Réponses:
La
property()
fonction renvoie un objet descripteur spécial :C'est cet objet qui a des méthodes supplémentaires :
Ceux - ci agissent comme décorateurs aussi . Ils retournent un nouvel objet de propriété:
c'est une copie de l'ancien objet, mais avec l'une des fonctions remplacées.
Souvenez-vous que la
@decorator
syntaxe n'est que du sucre syntaxique; la syntaxe:signifie vraiment la même chose que
de sorte que
foo
la fonction est remplacée parproperty(foo)
, que nous avons vu ci-dessus est un objet spécial. Ensuite, lorsque vous utilisez@foo.setter()
, ce que vous faites, c'est appeler laproperty().setter
méthode que je vous ai montrée 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, à l'aide de ces méthodes de décoration.
Nous créons d'abord quelques fonctions et un
property
objet avec juste un getter:Ensuite, nous utilisons la
.setter()
méthode pour ajouter un setter:Enfin, nous ajoutons un deleter avec la
.deleter()
méthode:Last but not least, l'
property
objet agit comme un objet descripteur , il a donc.__get__()
,.__set__()
et les.__delete__()
méthodes de crochet en attribut d'instance d' obtenir, le réglage et la suppression:Le Descriptor Howto comprend un exemple d'implémentation Python pur du
property()
type:la source
Foo.prop = prop
vous pouvez faireFoo().prop = 5; pront Foo().prop; del Foo().prop
avec le résultat souhaité.type()
car l'accès aux attributs et aux méthodes sont destinés à être utilisés comme points d'extension par les fonctions et opérateurs standard.@human.name.getter
modifiait l'property
objet en place plutôt que de renvoyer un nouveau, l'human.name
attribut serait modifié, changeant le comportement de cette superclasse.La documentation indique que ce n'est qu'un raccourci pour créer des propriétés en lecture seule. Donc
est équivalent à
la source
@property
comme décorateur dans sa classe.Voici un exemple minimal de la façon dont
@property
peut être mis en œuvre:Sinon
word
reste une méthode au lieu d'une propriété.la source
self.word = my_word
print( Thing('ok').word ) = 'ok'
Thing('ok').word
appelle la fonction en interne lors de l'exécution?La première partie est simple:
est le même que
property
avec juste un getter.L'étape suivante serait d'étendre cette propriété avec un setter et un deleter. Et cela se produit avec les méthodes appropriées:
renvoie une nouvelle propriété qui hérite de tout de l'ancien
x
plus du setter donné.x.deleter
fonctionne de la même manière.la source
Ce qui suit:
Est le même que:
Est le même que:
Est le même que:
C'est la même chose que:
la source
Ci-dessous est un autre exemple sur la façon dont
@property
peut aider quand on doit refactoriser le code qui est pris à partir d' ici (je le résume seulement ci-dessous):Imaginez que vous avez créé une classe
Money
comme celle-ci:et un utilisateur crée une bibliothèque en fonction de cette classe où il / elle utilise par exemple
Supposons maintenant que vous décidiez de changer votre
Money
classe et de vous débarrasser des attributsdollars
etcents
mais décidez plutôt de suivre uniquement le montant total de cents:Si l'utilisateur mentionné ci-dessus essaie maintenant d'exécuter sa bibliothèque comme auparavant
cela entraînera une erreur
Cela signifie que maintenant, tous ceux qui s'appuient sur votre
Money
classe d' origine devraient changer toutes les lignes de code oùdollars
et quicents
sont utilisées, ce qui peut être très douloureux ... Alors, comment cela pourrait-il être évité? En utilisant@property
!Voilà comment:
quand nous appelons maintenant de notre bibliothèque
cela fonctionnera comme prévu et nous n'avons pas eu à changer une seule ligne de code dans notre bibliothèque! En fait, nous n'aurions même pas besoin de savoir que la bibliothèque dont nous dépendons a changé.
Aussi, ça
setter
marche bien:Vous pouvez
@property
également utiliser dans les classes abstraites; Je donne ici un exemple minimal .la source
self.dollar = dollars
? nous avons fait tellement de choses avec @property, mais il semble qu'aucune fonctionnalité d'extraction ne soit ajoutée.J'ai lu tous les articles ici et j'ai réalisé que nous pourrions avoir besoin d'un exemple réel. Pourquoi, en fait, nous avons @property? Considérez donc une application Flask dans laquelle vous utilisez un système d'authentification. Vous déclarez un utilisateur modèle dans
models.py
:Dans ce code, nous avons "caché" l'attribut
password
en utilisant@property
ce qui déclenche l'AttributeError
assertion lorsque vous essayez d'y accéder directement, tandis que nous avons utilisé @ property.setter pour définir la variable d'instance réellepassword_hash
.Maintenant,
auth/views.py
nous pouvons instancier un utilisateur avec:Remarquez l'attribut
password
qui provient d'un formulaire d'inscription lorsqu'un utilisateur remplit le formulaire. La confirmation du mot de passe se produit sur le front-end avecEqualTo('password', message='Passwords must match')
(au cas où vous vous poseriez la question, mais il s'agit d'un formulaire différent lié aux formulaires Flask).J'espère que cet exemple vous sera utile
la source
Ce point a été effacé par beaucoup de gens là-haut, mais voici un point direct que je cherchais. C'est ce qui me semble important pour commencer avec le décorateur @property. par exemple:-
L'appel de la fonction "get_config ()" fonctionnera comme ceci.
Si vous remarquez que je n'ai pas utilisé de crochets "()" pour appeler la fonction. C'est la chose de base que je cherchais pour le décorateur @property. Pour que vous puissiez utiliser votre fonction comme une variable.
la source
Commençons par les décorateurs Python.
Un décorateur Python est une fonction qui permet d'ajouter des fonctionnalités supplémentaires à une fonction déjà définie.
En Python, tout est un objet. Les fonctions en Python sont des objets de première classe, ce qui signifie qu'elles peuvent être référencées par une variable, ajoutées dans les listes, passées comme arguments à une autre fonction, etc.
Considérez l'extrait de code suivant.
Ici, nous pouvons dire que la fonction décorateur a modifié notre fonction say_hello et y a ajouté quelques lignes de code supplémentaires.
Syntaxe Python pour décorateur
Let's Conclu tout qu'avec un scénario de cas, mais avant cela, parlons de quelques principes Oups.
Les getters et setters sont utilisés dans de nombreux langages de programmation orientés objet pour garantir le principe de l'encapsulation des données (est considéré comme le regroupement des données avec les méthodes qui opèrent sur ces données.)
Ces méthodes sont bien sûr le getter pour récupérer les données et le setter pour changer les données.
Selon ce principe, les attributs d'une classe sont rendus privés pour les cacher et les protéger des autres codes.
Ouais , @property est fondamentalement une manière pythonique d'utiliser les getters et les setters.
Python a un grand concept appelé propriété qui rend la vie d'un programmeur orienté objet beaucoup plus simple.
Supposons que vous décidiez de créer une classe capable de stocker la température en degrés Celsius.
Code refactorisé, voici comment nous aurions pu le réaliser avec propriété.
En Python, property () est une fonction intégrée qui crée et renvoie un objet de propriété.
Un objet de propriété a trois méthodes, getter (), setter () et delete ().
Ici,
aurait pu être décomposé car,
Point à noter:
Vous pouvez maintenant accéder à la valeur de la température en écrivant.
Nous pouvons continuer et ne pas définir les noms get_temperature et set_temperature car ils sont inutiles et polluent l'espace de noms de classe.
La manière pythonique de traiter le problème ci-dessus consiste à utiliser @property .
Points à noter -
Comme vous pouvez le voir, le code est nettement moins élégant.
Maintenant, parlons d'un scénario pratique réel.
Disons que vous avez conçu une classe comme suit:
Supposons maintenant que notre classe est devenue populaire parmi les clients et qu'ils ont commencé à l'utiliser dans leurs programmes. Ils ont fait toutes sortes d'affectations à l'objet.
Et un jour fatidique, un client de confiance est venu vers nous et a suggéré que "x" doit être une valeur entre 0 et 1000, c'est vraiment un scénario horrible!
En raison des propriétés, c'est facile: nous créons une version de propriété de "x".
C'est super, n'est-ce pas: vous pouvez commencer avec l'implémentation la plus simple imaginable, et vous êtes libre de migrer plus tard vers une version de propriété sans avoir à changer l'interface! Les propriétés ne remplacent donc pas seulement les getters et les setter!
Vous pouvez vérifier cette implémentation ici
la source
property
est une classe derrière@property
décorateur.Vous pouvez toujours vérifier ceci:
J'ai réécrit l'exemple de
help(property)
pour montrer que la@property
syntaxeest fonctionnellement identique à la
property()
syntaxe:Il n'y a aucune différence sur la façon dont nous utilisons la propriété comme vous pouvez le voir.
Pour répondre à la question, le
@property
décorateur est implémenté via laproperty
classe.Donc, la question est d'expliquer
property
un peu la classe. Cette ligne:C'était l'initialisation. Nous pouvons le réécrire comme ceci:
Le sens de
fget
,fset
etfdel
:L'image suivante montre les triplets que nous avons, de la classe
property
:__get__
,__set__
Et__delete__
sont là pour être surchargée . Il s'agit de l'implémentation du modèle de descripteur en Python.Nous pouvons également utiliser la propriété
setter
,getter
et desdeleter
méthodes pour lier la fonction à la propriété. Vérifiez l'exemple suivant. La méthodes2
de la classeC
mettra la propriété doublée .la source
Une propriété peut être déclarée de deux manières.
Vous pouvez jeter un œil à quelques exemples que j'ai écrits sur les propriétés en python .
la source
La meilleure explication peut être trouvée ici: Python @Property expliqué - Comment utiliser et quand? (Exemples complets) par Selva Prabhakaran | Publié le 5 novembre 2018
Cela m'a aidé à comprendre POURQUOI non seulement COMMENT.
https://www.machinelearningplus.com/python/python-property/
la source
Voici un autre exemple:
Fondamentalement, le même que l'exemple C (objet), sauf que j'utilise x à la place ... Je n'initialise pas non plus dans __init - ... eh bien ... je le fais, mais il peut être supprimé car __x est défini comme faisant partie de la classe....
La sortie est:
et si je commente self.x = 1234 en init alors la sortie est:
et si je définit _default = None sur _default = 0 dans la fonction getter (car tous les getters devraient avoir une valeur par défaut mais elle n'est pas transmise par les valeurs de propriété de ce que j'ai vu afin que vous puissiez la définir ici, et ce n'est vraiment pas mauvais car vous pouvez définir la valeur par défaut une fois et l'utiliser partout) ie: def x (self, _default = 0):
Remarque: La logique getter est là juste pour que la valeur soit manipulée par elle pour s'assurer qu'elle est manipulée par elle - la même chose pour les instructions d'impression ...
Remarque: Je suis habitué à Lua et je peux créer dynamiquement 10+ assistants lorsque j'appelle une seule fonction et j'ai créé quelque chose de similaire pour Python sans utiliser de propriétés et cela fonctionne dans une certaine mesure, mais, même si les fonctions sont créées avant étant utilisé, il y a toujours des problèmes avec leur appel avant d'être créé, ce qui est étrange car il n'est pas codé de cette façon ... Je préfère la flexibilité des méta-tables Lua et le fait que je puisse utiliser de vrais setters / getters au lieu d'accéder directement à une variable ... j'aime la rapidité avec laquelle certaines choses peuvent être construites avec Python - par exemple les programmes gui. bien que celle que je conçois ne soit pas possible sans beaucoup de bibliothèques supplémentaires - si je la code dans AutoHotkey, je peux accéder directement aux appels dll dont j'ai besoin, et la même chose peut être faite en Java, C #, C ++,
Remarque: La sortie de code dans ce forum est cassée - j'ai dû ajouter des espaces à la première partie du code pour que cela fonctionne - lors du copier / coller, assurez-vous de convertir tous les espaces en onglets .... J'utilise des onglets pour Python car dans un fichier de 10 000 lignes, la taille du fichier peut être de 512 Ko à 1 Mo avec des espaces et de 100 à 200 Ko avec des tabulations, ce qui équivaut à une énorme différence de taille de fichier et à une réduction du temps de traitement ...
Les onglets peuvent également être ajustés par utilisateur - donc si vous préférez une largeur de 2 espaces, 4, 8 ou tout ce que vous pouvez faire, cela est utile pour les développeurs ayant des déficits de vue.
Remarque: Toutes les fonctions définies dans la classe ne sont pas mises en retrait correctement en raison d'un bogue dans le logiciel du forum - assurez-vous de le mettre en retrait si vous copiez / collez
la source
Une remarque: pour moi, pour Python 2.x,
@property
ne fonctionnait pas comme annoncé quand je n'ai pas hérité deobject
:mais a fonctionné quand:
pour Python 3, a toujours fonctionné.
la source
object
est une classe à l'ancienne et les classes à l'ancienne ne prennent pas en charge le protocole de descripteur (qui est ce quiproperty
implémente pour fonctionner comme il le fait). En Python 3, les classes à l'ancienne n'existent plus; toutes les classes sont ce que nous