Maison  >  Article  >  base de données  >  descripteur python descripteur(1)

descripteur python descripteur(1)

黄舟
黄舟original
2016-12-23 17:37:181172parcourir

Les descripteurs Python sont un moyen de créer des propriétés gérées. Chaque fois qu'un attribut est interrogé, une action se produit. Cette action est par défaut obtenir, définir ou supprimer. Cependant, parfois, une application peut avoir

plus d'exigences et vous obliger à concevoir des actions plus complexes. La meilleure solution consiste à écrire une fonction qui effectue l'action souhaitée, puis à spécifier qu'elle s'exécute lors de l'accès à la propriété. Un objet

doté de cette fonctionnalité est appelé un descripteur. Les descripteurs constituent la base de l'implémentation des méthodes python, des méthodes liées, de super, PRperty, staticmethod et classmethod.

1. Protocole de descripteur

Un descripteur est un objet qui représente une valeur d'attribut en implémentant une ou plusieurs méthodes __get__, __set__, __delete__, le descripteur et les attributs sont accessibles par les hooks de mécanisme, et ces opérations peuvent également être personnalisées.

__get__(self, instance, own) : utilisé pour accéder aux attributs et renvoyer la valeur de l'attribut. Instance est l'objet instance utilisant le descripteur et own est la classe à laquelle appartient l'instance. Lors de l'accès à une propriété via une classe, l'instance est None.

__set__(self, instance, value) : définit la valeur de l'attribut.

__delete__(self,instance) : Supprimer la valeur de l'attribut.

2. Comment implémenter les descripteurs

class Descriptor(object):
def __get__(self, instance,owner):
print 'getting:%s'%self. _Name Return Self._name
DEF __SET __ (Self, Instance, nom):
Paramètres d'impression:%s'%name
Self._name = nom
position ):

Imprimer 'Deleting:%s'%Self._name
Del Self._name
Class Person (Object):
name = descriptionor ()

Un objet descripteur très simple est généré. Vous pouvez maintenant lire, définir et supprimer le nom d'attribut d'un objet Personne :

>>> p=Person()

>> del p.name

deleting:john



Remarque : les descripteurs ne peuvent être instanciés qu'au niveau de la classe et ne peuvent pas être créés pour chaque objet descripteur dans __init__() et dans d'autres méthodes de descripteur de création d'instance.

Les noms de propriétés utilisés par les classes avec des descripteurs ont une priorité plus élevée que les noms de propriétés stockés sur les instances. Pour qu'un descripteur stocke une valeur sur une instance, le descripteur doit choisir un nom différent de celui qu'il utilise lui-même.

Comme dans l'exemple ci-dessus, la fonction __init__ d'initialisation de la classe Person ne peut pas utiliser le nom pour définir les attributs de l'instance.

Descripteur de données et descripteur sans données :

Si __get__ et __set__ sont implémentés, c'est un descripteur de données, si seulement __get__ est implémenté, c'est un descripteur sans données. L'effet différent est que le descripteur de données remplace toujours l'implémentation de l'attribut dans une instance,

et que le descripteur de non-données n'a pas d'ensemble, lors de l'attribution de valeurs​​aux attributs via l'instance, comme ci-dessus p.name = 'hello', la méthode __set__ ne sera plus appelée et l'attribut d'instance p.name sera directement défini sur 'hello'.

Bien sûr, si vous déclenchez uniquement AttributeError dans __set__, vous obtiendrez toujours un descripteur non-données.

Mécanisme d'appel du descripteur :

Lors de l'interrogation de l'attribut a.attr d'un objet, si python découvre que attr est un objet descripteur, la façon de lire l'attribut dépend de l'objet a :

Appel direct : l'appel le plus simple consiste à utiliser directement le code pour appeler la méthode descripteur, attr.__get__(a)

Liaison d'instance : si a est un objet instance, appelez la méthode : type( a).__dict__ ['attr'].__get__(a,type(a))

Liaison de classe : si A est un objet de classe, appelez la méthode : A.__dict__['attr'].__get__( Aucun,A)

Super liaison : si a est une super instance, alors super(B,obj).m() trouve la classe de base A de B en interrogeant obj.__class__.__mro__, puis exécute A.__dict__ ['m' ].__get__(obj,obj.__class__)

3. Descripteur qui effectue la vérification du type d'attribut

class TypedProperty(object):
def __init__(self,name,attr_type,default=None):
self.name='_' name
self.type=attr_type
self. default=default si défaut else attr_type()
def __get__(self,instance,own):
return getattr(instance,self.name,self.default)
def __set__(self,instance,value) :
sinon isinstance(value,self.type):
raise TypeError,'Doit être %s'%self.type
setattr(instance,self.name,value)
def __delete__( self,instance):
raise AttributeError('Impossible de supprimer l'attribut')
class Foo(object):
name=TypedProperty('name',str)
num=TypedProperty('num' ,int,37)                                                                                                                                                                                                    

Le descripteur ci-dessus peut vérifier le type de l'attribut si l'attribut name. n'est pas défini sur le type str ou num n'est pas défini sur le type int, une erreur sera être signalé :

>>> f.name=21
TypeError : doit être

Et la suppression des attributs est interdite :

>>> del f.name
AttributeError : Impossible de supprimer l'attribut

f.name type d'appel invisible(f).__dict__['name' ].__get__ (f,Foo), c'est-à-dire Foo.name.__get__(f,Foo).

Le descripteur ci-dessus est en fait stocké sur l'instance. Le nom est stocké sur f._name via setattr(f,_name,value), et num est stocké sur f._num. C'est aussi la raison du soulignement.

Sinon, le nom du descripteur name entrera en conflit avec le nom de l'attribut d'instance et l'attribut de descripteur f.name écrasera l'attribut d'instance f.name.

Ce qui précède est le contenu du descripteur python (1). Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn