Bugs item #1382740, was opened at 2005-12-16 15:18 Message generated for change (Comment added) made by rhettinger You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1382740&group_id=5470
Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: Python Interpreter Core Group: Python 2.4 Status: Open >Resolution: None Priority: 5 Submitted By: Kevin Quick (kquick) >Assigned to: Guido van Rossum (gvanrossum) Summary: len() on class broken Initial Comment: With the following python input: class A: @classmethod def __len__(cls): return 12 print '1',A.__len__() print '2',A().__len__() print '3',len(A()) print '4',len(A) The output always breaks for '4' with 'TypeError: len of unsized object' Same result for @staticmethod or normal instance method declaration. ---------------------------------------------------------------------- >Comment By: Raymond Hettinger (rhettinger) Date: 2005-12-16 23:40 Message: Logged In: YES user_id=80475 Guido, this issue arises throughout the language in various guises (for instance, it applies to __neg__ as well as __len__). It comes-up whenever built-in functions or operators bypass attribute lookup in favor of direct slot access. Much of the code in abstract.c is in the form: def PyObject_SomeFunc(o): if slots.somefunc is not None: return slots.somefunc(o) raise TypeError If we cared about this (and I'm not sure we do), the solution is to make the abstract.c functions smarter: def PyObject_SomeFunc(o): if slots.somefunc is not None: return slots.somefunc(o) try: f = gettattr(o, 'somefunc') except AttributeError: raise TypeError else: return f() The advantage of the change is restoring the symmetry between len(o) and o.__len__() where the method definition is available via attribute lookup but not via a slot. The thought is to keep the speedy access as default, but if that fails, then do a normal attribute lookup before barfing back an error message. This is precedent for this solution elsewhere in the codebase (though I don't remember where at the moment). OTOH, I'm not sure we care. pervades the code in abstract.c which is in the form: def PyObject_Size ---------------------------------------------------------------------- Comment By: Kevin Quick (kquick) Date: 2005-12-16 17:52 Message: Logged In: YES user_id=6133 That would indeed solve '4', but has a non-orthogonality of attribute propagation that I don't understand and which seems inconsistent. In my original: '1' demonstrates that __len__ is indeed in the dictionary for the class. '2' shows the expected attribute propagation effects: if at attribute is not found in the instance dictionary, the class dictionary is checked. '3' shows that len is implemented (generally) by looking for a __len__ method on the object in question. '4' confuses me, because it means that '3' isn't quite correct... With your metaclass solution (using "__metaclass__ = meta" :) it does indeed make '4' work, and '1', but '2' and '3' now do not work, showing that instance-->class propagation does not follow instance-->class-->metaclass. Or something ... Approaching this a different way: My understanding of @classmethod (or perhaps more properly @staticmethod) is that it allows "constant" methods that are independent of the particular object instance. So if I had: class C: @staticmethod def f(): return 1 then both C.f() and C().f() are valid and return 1. Why the len() translation to __len__ works *differently* is strange. I'm still defining a method, just one that I want Python to use for any len(A) or len(A()) refs, translating those to A.__len__() or A().__len__() and using those just as for C and f, respectively. ---------------------------------------------------------------------- Comment By: Reinhold Birkenfeld (birkenfeld) Date: 2005-12-16 16:43 Message: Logged In: YES user_id=1188172 You want to use a metaclass: class meta(type): def __len__(cls): return 12 class B: __metaclass__ = B print len(B) ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1382740&group_id=5470 _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com