[Zope3-dev] Re: Interface support in Python? (was Re: [Zope3-dev] Proposal: Improving on __implements__)

Jim Fulton jim@zope.com
Thu, 23 Jan 2003 07:25:55 -0500


Steve Alexander wrote:
> 
>>   You can't use the class dictionary's '__implements__' entry to hold 
>> the value, because that entry needs to be saved for the descriptor to 
>> say what the class provides to *its* instances.  So you have to come 
>> up with another name for the entry to hold the value.  Only, you can't 
>> use the same name for both instances and classes, because there might 
>> be another meta-level that needs to store an assertion for *its* 
>> instances...
> 
> 
> getattr seems to be a bit over-overloaded in this example.
> 
> If I have an instance, its class, its metaclass, and its meta-metaclass, 
> is the following true?

I'm sorry, I really don't want to think about meta-meta classes.

>   getattr(instance, 'foo')
>    gets me the foo of the instance

yes

>    or if there is none, the foo of the class

yes

>    or if there is none, the foo of the metaclass,

no

>    or if there is none, the foo of the meta-metaclass,

don't care. :) (But I'd guess no)

>    or if there is none, a KeyError


No, AttributeError

>   getattr(cls, 'foo')
>    gets me the foo of the class

yes

>    or if there is none, the foo of the metaclass,

yes

>    or if there is none, the foo of the meta-metaclass,

don't care. :) (But I'd guess no)


>    or if there is none, a KeyError

No, AttributeError

>   getattr(metacls, 'foo')
>    gets me the foo of the metaclass,

yes

>    or if there is none, the foo of the meta-metaclass,

don't care. :) (But I'd guess yes)

>    or if there is none, a KeyError

No, AttributeError

You made me perform the followeing experiment.

I wrote the script:

-------------------------------------------

class dualattr(object):

     def __init__(self, ival, cval):
         self.ival = ival
         self.cval = cval

     def __get__(self, inst, class_):
         if inst is None:
             return self.cval
         else:
             return self.ival


class m(type):
     mm = 'mm'
     mc = 'mc'
     mi = 'mi'

     x = dualattr("cx", "mx")
     y = dualattr("cy", "my")

class c:
     __metaclass__ = m

     cc = 'cc'
     ci = 'ci'

     mc = 'cmc'
     mi = 'cmi'

     y = dualattr("iy", "cy")
     z = dualattr("iz", "cz")

i = c()

i.ii = 'ii'
i.ci = 'ici'
i.mi = 'imi'

print 'i.mm', getattr(i, 'mm' ,'AttributeError')
print 'i.mc', getattr(i, 'mc' ,'AttributeError')
print 'i.mi', getattr(i, 'mi' ,'AttributeError')
print 'i.cc', getattr(i, 'cc' ,'AttributeError')
print 'i.ci', getattr(i, 'ci' ,'AttributeError')
print 'i.ii', getattr(i, 'ii' ,'AttributeError')
print 'i.x', getattr(i, 'x' ,'AttributeError')
print 'i.y', getattr(i, 'y' ,'AttributeError')
print 'i.z', getattr(i, 'z' ,'AttributeError')
print

print 'c.mm', getattr(c, 'mm' ,'AttributeError')
print 'c.mc', getattr(c, 'mc' ,'AttributeError')
print 'c.mi', getattr(c, 'mi' ,'AttributeError')
print 'c.cc', getattr(c, 'cc' ,'AttributeError')
print 'c.ci', getattr(c, 'ci' ,'AttributeError')
print 'c.x', getattr(c, 'x' ,'AttributeError')
print 'c.y', getattr(c, 'y' ,'AttributeError')
print 'c.z', getattr(c, 'z' ,'AttributeError')
print

print 'm.mm', getattr(m, 'mm' ,'AttributeError')
print 'm.mc', getattr(m, 'mc' ,'AttributeError')
print 'm.mi', getattr(m, 'mi' ,'AttributeError')
print 'm.x', getattr(m, 'x' ,'AttributeError')
print 'm.y', getattr(m, 'y' ,'AttributeError')
print

i.mm

-------------------------------------------
i.mm AttributeError
i.mc cmc
i.mi imi
i.cc cc
i.ci ici
i.ii ii
i.x AttributeError
i.y iy
i.z iz

c.mm mm
c.mc cmc
c.mi cmi
c.cc cc
c.ci ci
c.x cx
c.y cy
c.z cz

m.mm mm
m.mc mc
m.mi mi
m.x mx
m.y my

Traceback (most recent call last):
   File "t.py", line 69, in ?
     i.mm
AttributeError: 'c' object has no attribute 'mm'

-------------------------------------------

which seems pretty reasonable.

Note that the dualattr descriptor illustrates how the __implements__ descriptor
would work. With your proposal, given a custom meta class, there would be two
ways of saying what the interface if a class is. You use "implements" in the
meta class, or you can say "classImplements" in the class.

> Maybe a change in the way getattr and metaclasses work could accompany a 
> proposal to get interfaces into Python?

I don't think this is necessary.

Jim

-- 
Jim Fulton           mailto:jim@zope.com       Python Powered!
CTO                  (888) 344-4332            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org