[pyar] Duda: @property con __(set|get)attr__
Claudio Freire
klaussfreire en gmail.com
Mie Feb 13 22:35:34 ART 2013
2013/2/13 Germán L. Osella Massa <gosella en gmail.com>:
> El 13 de febrero de 2013 17:46, Claudio Freire <klaussfreire en gmail.com>
> escribió:
>
>>
>> No, eso invoca al getter cuando se invoca al setter, lo que puede ser
>> bastante anti-intuitivo (y dependiendo de lo que haga el setter,
>> indeseado)
>
>
> Coincido con vos plenamente pero anti-intuitivo y todo, Python es así:
No, no es cosa de python, es cosa del código que chequea si tiene el atributo.
obj.atributo = 3
Sólo invoca
obj.__setattr__('atributo', 3)
No debería invocar
obj.__getattr__('atributo')
Pero el código primero sí lo hace.
El código segundo es interesante... no ideal, pero interesante. Creo
que una metaclase no sería tan mala, y de hecho sería mucho más
robusto (ej: se podría subclasear fácilmente):
>>> def with_attrs(name, bases, attrs):
... attrset = set(attrs)
... for base in bases:
... attrset.update(set(dir(base)))
... attrs['_attrs'] = frozenset(attrset)
... return type(name, bases, attrs)
...
>>> class pdict(dict):
... __metaclass__ = with_attrs
... @property
... def foo(self):
... print("foo.getter")
...
... @foo.setter
... def foo(self, value):
... print("foo.setter", value)
...
... def __getattr__(self, name):
... return self.get(name, None)
...
... def __setattr__(self, name, value):
... print("In pdict.__setattr__(self, %r, %r):" % (name, value))
... if name in self._attrs:
... print("\tsuper().__setattr__(%r, %r)" % (name, value))
... super().__setattr__(name, value)
... else:
... print("\tself[%r] = %r" % (name, value))
... self[name] = value
Pero me sigue oliendo mal tener que implementar la lógica esa en
setattr, y tener que agregar el atributo ese. Justamente una metaclase
podría "anotar" el setattr automágicamente:
>>> def with_attrs(name, bases, attrs):
... attrset = set(attrs)
... for base in bases:
... attrset.update(set(dir(base)))
... attrset = frozenset(attrset)
... if attrset and '__setattr__' in attrs and
callable(attrs['__setattr__']):
... _original_setattr = attrs['__setattr__']
... def __setattr__(self, name, value):
... if name in attrset:
... return super(cls, self).__setattr__(name, value)
... else:
... return _original_setattr(self, name, value)
... attrs['__setattr__'] = __setattr__
... cls = type(name, bases, attrs)
... return cls
...
>>> class pdict(dict):
... __metaclass__ = with_attrs
... @property
... def foo(self):
... print("foo.getter")
...
... @foo.setter
... def foo(self, value):
... print("foo.setter", value)
...
... def __getattr__(self, name):
... return self.get(name, None)
...
... def __setattr__(self, name, value):
... print("In pdict.__setattr__(self, %r, %r):" % (name, value))
...
>>> d = pdict()
>>> d.foo
foo.getter
>>> d.foo = 3
('foo.setter', 3)
>>> d.bar
>>> d.bar = 4
In pdict.__setattr__(self, 'bar', 4):
Listo. Automagia.
More information about the pyar
mailing list