2011-11-30 16 views
9

Acabo de notar que se puede hacer esto en Python:¿Los métodos classless en Python son útiles para cualquier cosa?

def f(self): 
    print self.name 

class A: 
    z=f 
    name="A" 

class B: 
    z=f 
    name = "B" 

...

print a.z() 

>>> A 

En otras palabras, f() se comporta como un método que no está definida en cualquier clase, pero se puede conectar a uno. Y, por supuesto, producirá un error de tiempo de ejecución si espera métodos o campos en el objeto al que está conectado, que no existen.

Mi pregunta: ¿esto es útil? ¿Sirve un propósito? ¿Hay situaciones en las que resuelve un problema? Tal vez es una forma de definir interfaces?

Respuesta

6

Sí, es útil y que sirve un propósito, pero también es bastante raro tener que hacer esto. Si crees que necesitas parchear las clases después de haberlas definido, siempre debes detenerte y considerar si realmente es la mejor.

Una situación es el parche de monos.He hecho esto en un gran sistema Plone donde algunos métodos requieren ajustes menores, pero simplemente no había una manera fácil de anular el comportamiento normalmente. En esa situación en la que tiene una biblioteca compleja, proporciona una manera fácil de inyectar un comportamiento nuevo o modificado sin tener que cambiar la biblioteca original.

La otra situación que me viene a la mente es cuando quieres una gran cantidad de métodos que se pueden generar automáticamente. p.ej. Pruebas basadas en datos.

def createTest(testcase, somedata, index): 
    def test(self): 
     "Do something with somedata and assert a result" 
    test_name = "test_%d" % index 
    setattr(testcase, test_name, test) 

for index, somedata in enumerate(somebigtable): 
    createTest(MyTestCase, somedata, index) 

cuando MyTestCase es un unittest.TestCase usted podría tener una prueba que va a través de todos los datos, pero se detiene en el primer fallo y de tener que tratar de averiguar qué línea de datos falló. Al crear dinámicamente los métodos, todas las pruebas se ejecutan por separado y el nombre de la prueba le dice cuál falló (el original del código anterior realmente construyó un nombre más significativo que incluye algunos de los datos, así como el índice).

No se puede hacer eso dentro del cuerpo de la clase porque no hay forma de hacer referencia a la clase o a su diccionario antes de que se complete la definición. Sin embargo, puede hacer algo similar con una metaclase, ya que le permite modificar el dictado de clase antes de crear la clase y, a veces, esa es una forma más limpia de hacer el mismo tipo de cosas.

La otra cosa a tener en cuenta es que hay situaciones en las que esto no funcionará. Algunos métodos especiales __xxx__ no pueden anularse después de que se haya creado la clase: la definición original se guarda internamente en algún lugar que no sea el __dict__ de la clase, por lo que se pueden ignorar los cambios que realice más adelante. Además, si se trabaja con metaclases, a veces las funciones adicionales no obtendrán el tratamiento que la metaclase les dé a los atributos como parte de la definición de la clase.

+0

¡Interesante! Esto también sugiere que otro valor podría estar moviendo la definición de métodos que no son centrales para la clase en otro lugar. Obviamente para situaciones especiales. –

2

Datos de interés:

  1. función en Python es un tipo:

    type(f) # prints <type: function> 
    
  2. Por lo tanto, la función es una instancia exigible, por lo que puede ser conectado en cualquier lugar.

  3. Se puede usar para hacer que las funciones sean portátiles y emular la funcionalidad Plug and Play.

  4. Esto puede ser muy útil durante el desarrollo - para probar diferentes lógicas (Al conectar en diferentes funciones)

  5. Esto proporciona abstracción sobre la lógica, ya que podemos reemplazar los métodos de clase con funciones importadas.

Aunque, dudo que cómo lo usará para emular la interfaz.

3

Dado que los objetos de función tienen el método __get __ (...), no es un descriptor de datos.

Cuando se define un método en la clase A, que es sólo un objeto de función en una .__ dict__:

In [78]: class A(object): 
    ....:  def f1(self): 
    ....:   pass 
    ....: 

In [79]: A.__dict__["f1"] 
Out[79]: <function f1 at 0x0D39A070> 

pero cuando llegas a esta función desde la instancia o de clase por atributos, se obtiene método o método no unido unidos .

In [80]: A.f1 
Out[80]: <unbound method A.f1> 

In [81]: A().f1 
Out[81]: <bound method A.f1 of <__main__.A object at 0x0D2F1CD0>> 

Así es como funciona el método. Por lo tanto, puede agregar el método más tarde:

In [82]: A.f2 = lambda self: id(self) 

In [83]: A().f2() 
Out[83]: 221189392 

así que su código es casi lo mismo que:

class A: 
    def z(self): 
     print self.name 
    name="A" 

Por favor, lea el detalle de http://docs.python.org/howto/descriptor.html

+0

Sí, pero ¿es útil este modismo para cualquier cosa? –

Cuestiones relacionadas