2012-09-13 20 views
17

En una de mis clases, tengo una serie de propiedades que hacen cosas muy similares para obtener y configurar. Así que recopiló los argumentos a property en una función de fábrica:Subclassing `property` de Python

def property_args(name): 
    def getter(self): 
     # do something 
     return getattr(self, '_' + name) 
    def setter(self, value) 
     # do something 
     setattr(self, '_' + name, value) 
    return getter, setter 

class MyClass(object): 
    def __init__(self): 
     self._x = None 
    x = property(*property_args('x')) # obviously there's more than one of these IRL 

Sin embargo, he descubierto desde entonces que property es, de hecho, una clase, y la subclasificación que sería perfecto para esto. No puedo encontrar nada en la documentación que explique lo que necesito sobrescribir (y las firmas de argumentos de __init__, etc.), y realmente no quiero tener que buscar el código fuente de C para ello. ¿Alguien sabe dónde puedo encontrar esta información?

+1

Como referencia, la implementación de C se puede encontrar aquí: http://hg.python.org/cpython/file/tip/Objects/descrobject.c – nneonneo

+0

@nneonneo: ¡Gracias! El gran bloque de comentarios en la línea 1228 es la respuesta. Si quieres escribir eso en una respuesta completa, entonces lo aceptaré. –

+0

poorsod puede responder su propia pregunta :) –

Respuesta

18

Aquí es un equivalente Python puro para el código en inmueble():

class Property(object): 
    "Emulate PyProperty_Type() in Objects/descrobject.c" 

    def __init__(self, fget=None, fset=None, fdel=None, doc=None): 
     self.fget = fget 
     self.fset = fset 
     self.fdel = fdel 
     if doc is None and fget is not None: 
      doc = fget.__doc__ 
     self.__doc__ = doc 

    def __get__(self, obj, objtype=None): 
     if obj is None: 
      return self 
     if self.fget is None: 
      raise AttributeError("unreadable attribute") 
     return self.fget(obj) 

    def __set__(self, obj, value): 
     if self.fset is None: 
      raise AttributeError("can't set attribute") 
     self.fset(obj, value) 

    def __delete__(self, obj): 
     if self.fdel is None: 
      raise AttributeError("can't delete attribute") 
     self.fdel(obj) 

    def getter(self, fget): 
     return type(self)(fget, self.fset, self.fdel, self.__doc__) 

    def setter(self, fset): 
     return type(self)(self.fget, fset, self.fdel, self.__doc__) 

    def deleter(self, fdel): 
     return type(self)(self.fget, self.fset, fdel, self.__doc__)