[pyar] Duda: @property con __(set|get)attr__

Germán L. Osella Massa gosella en gmail.com
Jue Feb 14 18:47:19 ART 2013


El día 13 de febrero de 2013 22:35, Claudio Freire
<klaussfreire en gmail.com> escribió:
> 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.

Yo  me refería a que en Python, cuando usas hasattr(), termina invoca
al getter de la property como efecto secundario no deseado (algo que
desconocía antes de probarlo y hubiera creído que no sucedía...).

Lo de que__setattr__() termina invocando al getter de la property no
tiene excusa (era fácil de implementar así ;-).

> 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.

Al final, quedó piola usando la metaclase. Con esto, básicamente
__setattr__() implementa una semántica similar a __getattr__(): se
invoca solamente cuando el atributo no existía previamente en el
objeto. Está buena tu solución!



More information about the pyar mailing list