2012-03-28 13 views
10

Ver el simple ejemplo a continuación:__get__ y __call__ en Python

class Celsius(object): 
    def __init__(self, value=0.0): 
     self.value = float(value) 
    def __get__(self, instance, owner): 
     return self.value 
    def __set__(self, instance, value): 
     self.value = float(value) 
    def __call__(self): 
     print('__call__ called') 

class Temperature(object): 
    celsius = Celsius() 
    def __init__(self): 
     self.celsius1 = Celsius() 


T = Temperature() 
print('T.celsius:', T.celsius) 
print('T.celsius1:', T.celsius1) 

output 
T.celsius: 0.0 
T.celsius1: <__main__.Celsius object at 0x023544F0> 

me preguntan por qué tienen salida diferente. Sé que T.celsius llamará al __get__ y T.celsius1 llame al __call__.

+0

Nada que lamentar, eso es una buena pregunta. – brice

+0

Y entonces, usted mismo respondió su propia pregunta. – Denis

+1

Muy buena pregunta. Tuve que verificar la documentación. Comportamiento bastante confuso, IMO. – codeape

Respuesta

2

Desde el documentation:

Los siguientes métodos sólo se aplican cuando una instancia de la clase que contiene el método (a llamada clase descriptor) aparece en un propietario clase (el descriptor debe estar en el diccionario de la clase del propietario o en el diccionario de clase para uno de sus padres).

descriptores SO (es decir. Objetos que implementan __get__, __set__ o __delete__) deben ser miembros de una clase, una instancia NO.

Con los cambios followinging:

Temperature.celsius2 = Celsius() 

T = Temperature() 
print('T.celsius:', T.celsius) 
print('T.celsius1:', T.celsius1) 
print('T.celsius2:', T.celsius2) 

La salida es:

T.celsius: 0.0 
T.celsius1: <__main__.Celsius object at 0x7fab8c8d0fd0> 
T.celsius2:, 0.0 

Más enlaces:

8

Las diferencias radican en el hecho de la el primer atributo es un atributoclase mientras que la segunda es una instancia atributo .

Según the documentation, si un objeto que implementa al menos el primero de los métodos (Descriptor__get__, __set__ y __delete__) se mantiene en una atributo clase, su método __get__ se llamará cuando se accede. Este no es el caso con un atributo de instancia . Puede aprender más from the howto.

El método de un objeto __call__ sólo entra en juego cuando el objeto se invoca como una función:

>>> class Foo: 
... def __call__(self): 
...  return "Hello there!" 
... 
>>> f = Foo() 
>>> f() 
'Hello There!' 
+0

Escriba cuándo (y por qué) invocar el objeto como una función. – IProblemFactory

+0

@ProblemFactory [Uso avanzado del decorador] (http://wiki.python.org/moin/PythonDecorators), por ejemplo. Pasar un objeto a una función 'map',' filter' o 'reduce' para capacidades avanzadas. Despacho dinámico inteligente. Instrumentación de código. Monkey parches. La lista sigue y sigue y sigue... – brice

2

T.celcius como un atributo de la clase Temperature por lo que devuelve el resultado del método de T. __get__ celcius como se esperaba

T.celsius1 es un atributo de la instancia T por lo que devuelve la propia variable desde descriptores se invocan sólo para los nuevos objetos o clases de estilo.

El método __call__ se usaría si tuviera que hacer T.celsius().

0

Como han dicho otros, las instancias del descriptor están destinadas a ser utilizadas como atributos de clase.

class Temperature(object): 
    celsius = Celsius() 
    def __init__(self): 
     self.celsius1 = Celsius() 

Si quieres self.celsius1 tener un comportamiento personalizado, anular __getattr__ método:

class Temperature(object): 
    celsius = Celsius() 
    def __getattr__(self, name): 
     if name == 'celsius1': 
      return ... 
Cuestiones relacionadas