Type emulation issues with new style classes

Chris feb04.20.netman at spamgourmet.com
Sat Feb 28 14:56:54 EST 2004


I tried your suggestion, but it breaks down when in the case where I want a
emulation method to be undefined.  See example below.

Okay, it looks lke I'm going to have to come to the realization that there
is no way to hook into Python's test for the existance of emulation methods,
so I'm going to have to explicitly define every single possible emulation
method, from __add__ to __xor__.  But still, how do I have __add__ return a
special value or throw a special exception so that the interpreter will then
move on to try __radd__?

### Works with old style classes ###
class Y:
    value = 42
    def __getattr__(self, name):
        if name == '__coerce__':
            raise AttributeError
        if name == '__add__':
            raise AttributeError
        if name == '__int__':
            return lambda: self.value
        if name == '__radd__':
            return lambda other: self.value + other.value

>>> y1, y2 = Y(), Y()
>>> print int(y1)
42
>>> print y1 + y2
84


### With new style classes, __radd__ is never called ###
class DynOperDescr(object):
    def __init__(self, name):
        self.name = name
    def __get__(self, instance, typ):
        if instance is None:
            return self
        return instance.__getattr__(self.name)

def AddDynOper(declcls, name):
    if not hasattr(declcls, name):
        setattr(declcls, name, DynOperDescr(name))

class Z(object):
    value = 42
    def __getattr__(self, name):
        if name == '__radd__':
            return lambda other: Z.value + Z.value
        if name == '__int__':
            return lambda: self.value
        raise AttributeError(name)

AddDynOper(Z, "__int__")
AddDynOper(Z, "__add__")
AddDynOper(Z, "__radd__")

>>> z1, z2 = Z(), Z()
>>> print int(z1)
42
>>> print z1 + z2
AttributeError: __add__


"Greg Chapman" wrote:
> On Sat, 28 Feb 2004 11:33:54 GMT, "Chris"
<feb04.20.netman at spamgourmet.com>
> wrote:
>
> >class Z(object):
> >    value = 42
> >    def __hasattr__(self, name):
> >        if name == '__int__':
> >            return True
> >    def __getattr__(self, name):
> >        if name == '__int__':
> >            return lambda: self.value
>
> The following allows your test case to work, but it may have various
subtle
> problems.  AddDynOper emulates __getattr__ semantics: the descriptor is
not
> installed if the type already has an attribute of the given name:
>
> class DynOperDescr(object):
>     def __init__(self, name):
>         self.name = name
>     def __get__(self, instance, typ):
>         if instance is None:
>             return self
>         return instance.__getattr__(self.name)
>
> def AddDynOper(declcls, name):
>     if not hasattr(declcls, name):
>         setattr(declcls, name, DynOperDescr(name))
>
> class Z(object):
>     value = 42
>     def __getattr__(self, name):
>         if name == "__int__":
>             return lambda : self.value
>         raise AttributeError(name)
> AddDynOper(Z, "__int__")
>
> ---
> Greg Chapman
>





More information about the Python-list mailing list