[Zope-dev] Beyond Acquisition

jalon@dev.in.nuxeo.com jalon@dev.in.nuxeo.com
Fri, 19 Apr 2002 17:32:21 +0000 (UTC)


In article <6ae0cu8p0j6a7grmcdneeujvtlbpju26e1@4ax.com>,
Toby Dickenson  <tdickenson@geminidataloggers.com> wrote:
>On Fri, 19 Apr 2002 15:28:52 +0000 (UTC), jalon@dev.in.nuxeo.com ()
>wrote:
>
>>It seems there is no way to get the real 'b' attribute from a, i.e. the
>>B instance set at the line "a.b = B()"
>
>Thats exactly right. your __of__ method means that *any* time you try
>to take a B object out of an A, you get a C object instead of a B. 
>
>try a.__dict__['b']

That's not a good solution since the b attribute can be defined in the
classes of a...

With some tries, I think I got the solution:

_nodefault = []

def getrealattr(obj, name, default = _nodefault):
    try:
        return obj.__dict__[name]
    except KeyError: pass
    objclass = obj.__class__
    try:
        attr = getattr(objclass, name)
        if hasattr(attr, '__of__'):
            # a trick from extension class:
            # whenever you get a class attribute,
            # you will get a Python Method
            # im_func get the function if it is a
            # method and the real object if not
            return attr.im_func
        return attr
    except AttributeError:
        if default is _nodefault: raise
        return default

if __name__ == '__main__':
    # Tests
    from Acquisition import Implicit
    class C(Implicit):
        def __init__(self, name):
            self.name = name

    class B(C):
        def __of__(self, parent):
            return C(self.name + ' (in object %s)' % parent.name).__of__(parent)

    class A(C):
        b = B('b in the class')

    a = C('a')
    b = B('b')
    a.b = b
    print 'a.b = %s' % a.b.name
    print 'real a.b = %s' % getrealattr(a, 'b').name

    a = A('a')
    print 'a.b = %s' % a.b.name
    print 'real a.b = %s' % getrealattr(a, 'b').name

    print getrealattr(a, 'c', None)

-- 
Julien Jalon
http://www.nuxeo.com/