2011-04-23 15 views
6

Actualmente estoy parcheando una propiedad de una clase de una biblioteca para hacerlo más versátil.¿Por qué property.fget es un atributo de solo lectura?

que estoy haciendo esto usando el siguiente código que funciona muy bien:

_orig_is_xhr = BaseRequest.is_xhr.fget 
_orig_is_xhr_doc = BaseRequest.is_xhr.__doc__ 
BaseRequest.is_xhr = property(lambda self: _orig_is_xhr(self) or 
    '_iframe-xhr' in request.form, doc=_orig_is_xhr_doc) 

Sin embargo, sería mucho mejor si yo podría simplemente sobrescribir la función getter así se conserva la cadena de documentación:

_orig_is_xhr = BaseRequest.is_xhr.fget 
BaseRequest.is_xhr.fget = lambda self: (_orig_is_xhr(self) or 
    '_iframe-xhr' in request.form) 

Esto no funciona porque property.fget es un atributo de solo lectura (TypeError: readonly attribute cuando intenta asignarlo). Tengo curiosidad si hay una razón especial para esto o si los desarrolladores de Python simplemente pensaron que no tiene sentido modificar una propiedad después de crearla sin reemplazarla por una nueva.

Respuesta

6

Probablemente tenga razón, es solo una convención hacer esos atributos de solo lectura, elegidos para hacer que la propiedad sea "todo o nada". Parece que sería un poco más "pitónico" permitir que estos se asignen después del hecho, pero no puede encontrar el fundamento en el Python 2.2 release notes (cuando se introdujeron las propiedades).

En Objects/descrobject.c atributos miembros de la propiedad se definen como de sólo lectura:

static PyMemberDef property_members[] = { 
     {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, 
     {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, 
     {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, 
     {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, 
     {0} 
    }; 

Aparte: si reemplaza READONLY con 0 y compilar, eso es todo lo que se necesita para permitir que fget, fset, .. ser asignados:

class Test(object): 
    def __init__(self): 
     self.flag = True 
    prop = property(lambda self: self.flag) 

obj = Test() 
print obj.prop 
Test.prop.fget = lambda self: not self.flag 
print obj.prop 

salida:

True 
False 
+0

Je, agradable - no voy a cortar la pitón fuente, sin embargo: p – ThiefMaster

+2

Por supuesto :-) Solo estaba señalando que no hay nada más exótico detrás de la lectura-solo-ness. – samplebias

+1

Las propiedades mutables crearían algunas oportunidades aterradoras para los efectos secundarios no intencionales. 'Thread.ident.fget = Thread.daemon.fget' ¿Alguien? – ncoghlan

0

probado con Anaconda 2.3.0 (Python 3.4.3) en una cáscara de IDLE

>>> p = property() 
>>> p.fget 
>>> p.__init__(lambda obj: None) 
>>> p.fget 
<function <lambda> at 0x0121FF18> 
>>> p.fget = lambda obj: None 
Tracebabk (most recent call last): 
    File "<pyshell#19>", line 1, in <module> 
    p.fget = lambda obj: None 
AttributeError: readonly attribute 
>>> 

no se ve tan sólo lectura a mí;)

Cuestiones relacionadas