Descriptor de Python ' -- python campo con descriptor camp Relacionados El problema

Python `descriptor`


0
vote

problema

Español

Una clase de descriptor es la siguiente:

  class Des(object):     def __get__(self, instance, owner): ...     def __set__(self, instance, value): ...     def __delete__(self, instance): ...  class Sub(object):     attr = Des()  X = sub()   

Pregunta

  1. No veo el punto de la existencia de owner , ¿cómo puedo usarlo?

  2. Para hacer una lectura de un ART, no deberíamos omitir __set__ , pero definirlo para atrapar las asignaciones y aumentar una excepción. Por lo que X.attr = 123 fallará, pero __set__6 's ARGENTOS NO CONTENIDO owner , lo que significa que todavía puedo hacer Sub.attr = 123 , ¿verdad?

Original en ingles

A descriptor class is as follows:

class Des(object):     def __get__(self, instance, owner): ...     def __set__(self, instance, value): ...     def __delete__(self, instance): ...  class Sub(object):     attr = Des()  X = sub() 

Question

  1. I don't see the point of the existence of owner, how can I use it?

  2. To make an attr read-only, we shouldn't omit __set__ but define it to catch the assignments and raise an exception. So X.attr = 123 will fail, but __set__'s arguments doesn't contain owner, which means I can still do Sub.attr = 123, right?

     

Lista de respuestas

4
 
vote

consulte http://docs.python.org/reference/datamodel.html # Descriptores de implementación :

owner es siempre la clase de propietario, mientras que instance es la instancia en la que se accedió al atributo, o ninguno cuando se accede al atributo a través del propietario

Un caso en el que usaría owner estaría creando un ClassProperty :

  class _ContentQueryProperty(object):     def __get__(self, inst, cls):         return Content.query.filter_by(type=cls.TYPE)   
 

See http://docs.python.org/reference/datamodel.html#implementing-descriptors:

owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner

A case where you would use owner would be creating a classproperty:

class _ContentQueryProperty(object):     def __get__(self, inst, cls):         return Content.query.filter_by(type=cls.TYPE) 
 
 
     
     
2
 
vote

Puedes experimentar con este ejemplo:

  # the descriptor protocol defines 3 methods: #    __get__() #    __set__() #    __delete__()  # any class implementing any of the above methods is a descriptor # as in this class class Trace(object):     def __init__(self, name):         self.name = name      def __get__(self, obj, objtype):         print "GET:" + self.name + " = " + str(obj.__dict__[self.name])         return obj.__dict__[self.name]      def __set__(self, obj, value):         obj.__dict__[self.name] = value         print "SET:" + self.name + " = " + str(obj.__dict__[self.name])  # define the attributes of your class (must derive from object) #  to be references to instances of a descriptor  class Point(object): # NOTES: # 1. descriptor invoked by dotted attribute access:  A.x or a.x # 2. descripor reference must be stored in the class dict, not the instance dict # 3. descriptor not invoked by dictionary access: Point.__dict__['x']      x = Trace("x")     y = Trace("y")      def __init__(self, x0, y0):         self.x = x0         self.y = y0      def moveBy(self, dx, dy):         self.x = self.x + dx     # attribute access does trigger descriptor         self.y = self.y + dy   # trace all getters and setters     p1 = Point(15, 25) p1.x = 20 p1.y = 35 result = p1.x p2 = Point(16, 26) p2.x = 30 p2.moveBy(1, 1)   
 

You can experiment with this example:

# the descriptor protocol defines 3 methods: #    __get__() #    __set__() #    __delete__()  # any class implementing any of the above methods is a descriptor # as in this class class Trace(object):     def __init__(self, name):         self.name = name      def __get__(self, obj, objtype):         print "GET:" + self.name + " = " + str(obj.__dict__[self.name])         return obj.__dict__[self.name]      def __set__(self, obj, value):         obj.__dict__[self.name] = value         print "SET:" + self.name + " = " + str(obj.__dict__[self.name])  # define the attributes of your class (must derive from object) #  to be references to instances of a descriptor  class Point(object): # NOTES: # 1. descriptor invoked by dotted attribute access:  A.x or a.x # 2. descripor reference must be stored in the class dict, not the instance dict # 3. descriptor not invoked by dictionary access: Point.__dict__['x']      x = Trace("x")     y = Trace("y")      def __init__(self, x0, y0):         self.x = x0         self.y = y0      def moveBy(self, dx, dy):         self.x = self.x + dx     # attribute access does trigger descriptor         self.y = self.y + dy   # trace all getters and setters     p1 = Point(15, 25) p1.x = 20 p1.y = 35 result = p1.x p2 = Point(16, 26) p2.x = 30 p2.moveBy(1, 1) 
 
 
1
 
vote

Me encontré con esta pregunta con una confusión similar, y después de haberlo respondiéndolo, parecía prudente informar mis hallazgos aquí para la prosperidad.

Como el ThiefMaster ya señaló, el parámetro "Propietario" hace posibles construcciones como un classproperty . A veces, desea que las clases tengan métodos enmascarados como atributos no metodos, y el parámetro __get__1 le permite hacerlo con descriptores normales.

Pero eso es solo la mitad de la pregunta. En cuanto al problema de "solo lectura", esto es lo que encontré:

Finalmente encontré la respuesta aquí: http: //martyalchin.com/2007/nov/23/python-descripts-part-1-of-2/ . No lo entendí al principio, y me tomó unos cinco minutos para envolver mi cabeza alrededor. Lo que finalmente me convenció estaba subiendo con un ejemplo.

Considere el descriptor más común: property . Utilicemos una clase de ejemplo trivial, con un conteo de propiedad, que es el número de veces que se ha accedido al recuento de variables.

  class MyClass(object):     def __init__(self):         self._count = 0     @property     def count(self):         tmp = self._count         self._count += 1         return tmp     @count.setter     def setcount(self):         raise AttributeError('read-only attribute')     @count.deleter     def delcount(self):         raise AttributeError('read-only attribute')   

Como ya estamos establecidos, el parámetro owner de la función significa que cuando accede al atributo en el nivel de clase, el __get__6 Función intercepta la llamada GetAtTRT. Como sucede, el código para property simplemente Devuelve la propiedad En sí mismo cuando se accede a nivel de clase, pero podría hacer cualquier cosa (como devolver un valor estático).

Ahora, imagine lo que sucedería si __set__ y __del__ funcionó de la misma manera. El owner0 y owner1111 Interceptaría todo owner2 y owner3 Llamadas a nivel de clase, además de la instancia nivel.

Como consecuencia, esto significa que el atributo "CUENTA" de owner4 es efectivamente unmodifiable . Si está acostumbrado a programar en lenguajes estáticos, compilados como Java, esto no parece muy interesante, ya que no puede modificar las clases en el código de aplicación. Pero en Python, puedes. Las clases se consideran objetos, y puede asignar dinámicamente alguno de sus atributos. Por ejemplo, digamos owner5 es parte de un módulo de terceros, y 99887776616 es casi totalmente perfecto para nuestra aplicación (asumamos que hay otro código allí además del código para owner7 ) Excepto que deseamos que el método de conteo funcione un poco de manera diferente. En su lugar, queremos que siempre regrese 10, por cada instancia. Podríamos hacer lo siguiente:

  owner8  

Si owner9 intercepó la llamada a property0 , entonces no habría manera de cambiar realmente MyClass. En su lugar, el código para property1 lo interceptaría y no podía hacer nada con él. La única solución sería editar el código fuente para MyClass. (Ni siquiera estoy seguro de que podría sobrescribirlo en una subclase, porque creo que la definición en una subclase aún invocaría el código __get__6622 . Pero no estoy seguro, y ya que ya estamos Tratar con un contrafactual aquí, realmente no tengo una forma de probarlo).

Ahora, puede estar diciendo: "¡Eso es exactamente lo que quiero! I intencionalmente ¿No quiso que mi usuario reasignar atributos de mi clase?" A eso, todo lo que puedo decir es que lo que quería es imposible usar descriptores ingenuos, y lo diría al razonamiento anterior. Permitir que los atributos de clase sean reasignados están mucho más en línea con los modismos actuales de Python.

Si lo realmente, realmente quiere hacer un atributo de clase de solo lectura, no creo que pueda decirle cómo. Pero si hay una solución, probablemente involucraría el uso de metaclases y crear un property3 de la Metaclass o modificar el código de Metaclass para SetAttr y Delattr . Pero esto es magia profunda, y mucho más allá del alcance de esta respuesta (y mis propias habilidades con Python).

 

I came across this question with similar confusion, and after I answered it for myself it seemed prudent to report my findings here for prosperity.

As ThiefMaster already pointed out, the "owner" parameter makes possible constructions like a classproperty. Sometimes, you want classes to have methods masked as non-method attributes, and using the owner parameter allows you to do that with normal descriptors.

But that is only half the question. As for the "read-only" issue, here's what I found:

I first found the answer here: http://martyalchin.com/2007/nov/23/python-descriptors-part-1-of-2/. I did not understand it at first, and it took me about five minutes to wrap my head around it. What finally convinced me was coming up with an example.

Consider the most common descriptor: property. Let's use a trivial example class, with a property count, which is the number of times the variable count has been accessed.

class MyClass(object):     def __init__(self):         self._count = 0     @property     def count(self):         tmp = self._count         self._count += 1         return tmp     @count.setter     def setcount(self):         raise AttributeError('read-only attribute')     @count.deleter     def delcount(self):         raise AttributeError('read-only attribute') 

As we've already established, the owner parameter of the __get__ function means that when you access the attribute at the class level, the __get__ function intercepts the getattr call. As it happens, the code for property simply returns the property itself when accessed at the class level, but it could do anything (like return some static value).

Now, imagine what would happen if __set__ and __del__ worked the same way. The __set__ and __del__ methods would intercept all setattr and delattr calls at the class level, in addition to the instance level.

As a consequence, this means that the "count" attribute of MyClass is effectively unmodifiable. If you're used to programming in static, compiled languages like Java this doesn't seem very interesting, since you can't modify classes in application code. But in Python, you can. Classes are considered objects, and you can dynamically assign any of their attributes. For example, let's say MyClass is part of a third-party module, and MyClass is almost entirely perfect for our application (let's assume there's other code in there besides the code for count) except that we wished the count method worked a little differently. Instead, we want it to always return 10, for every single instance. We could do the following:

>>> MyClass.count = 10 >>> myinstance = MyClass() >>> myinstance.count 10 

If __set__ intercepted the call to setattr(MyClass, 'count'), then there would be no way to actually change MyClass. Instead, the code for setcount would intercept it and couldn't do anything with it. The only solution would be to edit the source code for MyClass. (I'm not even sure you could overwrite it in a subclass, because I think defining it in a subclass would still invoke the setattr code. But I'm not sure, and since we're already dealing with a counterfactual here, I don't really have a way of testing it.)

Now, you may be saying, "That's exactly what I want! I intentionally did not want my user to reassign attributes of my class!" To that, all I can say is that what you wanted is impossible using naive descriptors, and I would direct you to the reasoning above. Allowing class attributes to be reassigned is much more in line with current Python idioms.

If you really, REALLY want to make a read-only class attribute, I don't think could tell you how. But if there is a solution, it would probably involve using metaclasses and either creating a property of the metaclass or modifying the metaclass's code for setattr and delattr. But this is Deep Magic, and well beyond the scope of this answer (and my own abilities with Python).

 
 
1
 
vote

En lo que respecta a las propiedades de la lectura (consulte la discusión anterior), el siguiente ejemplo muestra cómo se hace:

  property4  
 

As far as read only properties are concerned (see discussion above), the following example shows how its done:

############################################################ # #    descriptors # ############################################################  # define a class where methods are invoked through properties class Point(object):     def getX(self):     print "getting x"     return self._x      def setX(self, value):     print "setting x"     self._x = value      def delX(self):     print "deleting x"     del self._x      x = property(getX, setX, delX)  p = Point() p.x = 55    # calls setX a = p.x     # calls getX del p.x     # calls delX  # using property decorator (read only attributes) class Foo(object):     def __init__(self, x0, y0):     self.__dict__["myX"] = x0     self.__dict__["myY"] = y0      @property     def x(self):     return self.myX  f = Foo(4,6) print f.x try:     f.x = 77        # fails: f.x is read-only except Exception,e:     print e 
 
 
0
 
vote

El propietario es solo la clase de la instancia y se proporciona por conveniencia. Siempre puede calcularlo de instancia:

  property5  
 

The owner is just the class of the instance and is provided for convenience. You can always compute it from instance:

owner = instance.__class__ 
 
 
     
     
0
 
vote
  1. El método __set__ para cambiar los atributos en una instancia. Pero, ¿qué pasa si desea cambiar un atributo que sea compartido por todas las instancias y, por lo tanto, vive en la clase, por ejemplo, es un atributo de clase? Esto solo se puede hacer si tiene acceso a la clase, de ahí el argumento del propietario.

  2. Sí, puede sobrescribir la propiedad / descriptor si asigna a un atributo a través de la clase. Esto es por diseño, ya que Python es un lenguaje dinámico.

Espero que responda la pregunta, aunque se le preguntó hace mucho tiempo.

 
  1. The __set__ method is supposed to change attributes on an instance. But what if you would like to change an attribute that is shared by all instances and therefore lives in the class, e.g., is a class attribute? This can only be done if you have access to the class, hence the owner argument.

  2. Yes, you can overwrite the property / descriptor if you assign to an attribute through the class. This is by design, as Python is a dynamic language.

Hope that answers the question, although it was asked a long time ago.

 
 

Relacionados problema

0  ¿Por qué las clases con __get__ o __set__ saben quién los usa?  ( Why should classes with get or set know who uses them ) 
Acabo de leer sobre descriptores y se sintió muy involuntario de que el comportamiento de una clase Puede depender de quién lo usa. Los dos métodos __ge...

9  ¿Significados de signo de dólar en el método de Java descriptor?  ( Meanings of dollar sign in java method descriptor ) 
Por ejemplo, su parte de la pila de Jikes RVM. at [0x70cfba90, 0x708cfaa4] Lorg/apache/lucene/index/SegmentInfos; **access$000**(Ljava/lang/String;...

1  El descriptor de datos de Python no funcionó como variable de instancia? [duplicar]  ( Python data descriptor did not work as instance variable ) 
Esta pregunta ya tiene una respuesta aquí : ¿Por qué el descriptor no se llama cuando se ha definido...

1  Bajo qué escenario no se puede anular el descriptor de datos que no sean anulados por ejemplo los diccionarios  ( Under what scenario non data descriptor may not be overridden by instance dictio ) 
En la sección "Investigación de descriptores" de Descriptor HowTo Guía , dice: " Los descriptores de datos siempre anulan diccionarios de instancia. Los...

1  "Subclases" y yo en Python  ( Sub classes and self in python ) 
Note: Veo que necesito resolver más claramente qué es lo que quiero que quiero cada propiedad / descriptor / clase / método antes de preguntar cómo hacerlo!...

0  Web.xml y rutas relativas  ( Web xml and relative paths ) 
en web.xml, configuro mi archivo de bienvenida a un JSP dentro de Web.xml <welcome-file>WEB-INF/index.jsp</welcome-file> Dentro index.jsp I luego hacia...

0  Detector de características de denso OPENV  ( Opencv dense feature detector ) 
Estoy usando OpenCV para hacer una extracción de características densas. Por ejemplo, el código DenseFeatureDetector detector(12.f, 1, 0.1f, 10); Realm...

2  Descriptores de Python __Get__ y __set__  ( Python descriptors get and set ) 
Estoy seguro de que esto se marcará como un duplicado, pero realmente no entiendo lo que estoy mirando. He comprobado la documentación de Python sobre descrip...

0  ¿Cómo usar __Get__ para hacer serializable el objeto JSON?  ( How to use get to make object json serializable ) 
Tengo un decorador que devuelve una cadena en Wsdl=someurl UserName=admin UserPassword=ENC(encriptedpassword) 111111. ¿Cómo puedo hacerlo compatible con Wsd...

4  Descriptor de archivo de Linux: obtener el archivo STdout de redirección actual?  ( Linux file descriptor getting current redirection stdout file ) 
Estoy tratando de obtener la redirección de STdout actual, y tener algunos problemas. Tengo un script que siempre se ejecuta con Redirección STDOUT, es deci...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos