[Python-Dev] Python 3, new-style classes and __class__

Michael Foord fuzzyman at voidspace.org.uk
Sun Nov 20 19:44:25 CET 2011


On 20 Nov 2011, at 16:35, Guido van Rossum wrote:

> Um, what?! __class__ *already* has a special meaning. Those examples
> violate that meaning. No wonder they get garbage results.
> 
> The correct way to override isinstance is explained here:
> http://www.python.org/dev/peps/pep-3119/#overloading-isinstance-and-issubclass
> .
> 


Proxy classes have been using __class__ as a descriptor for this purpose for years before ABCs were introduced. This worked fine up until Python 3 where the compiler magic broke it when super is used. That is now fixed anyway.

If I understand correctly, ABCs are great for allowing classes of objects to pass isinstance checks (etc) - what proxy, lazy and mock objects need is to be able to allow individual instances to pass different isinstance checks.

All the best,

Michael Foord

> --Guido
> 
> On Sat, Nov 19, 2011 at 6:13 PM, Michael Foord
> <fuzzyman at voidspace.org.uk> wrote:
>> 
>> 
>> On 19 November 2011 23:11, Vinay Sajip <vinay_sajip at yahoo.co.uk> wrote:
>>> 
>>> Michael Foord <fuzzyman <at> voidspace.org.uk> writes:
>>> 
>>>> That works fine in Python 3 (mock.Mock does it):
>>>> 
>>>>  >>> class Foo(object):
>>>> ...  @property
>>>> ...  def __class__(self):
>>>> ...   return int
>>>> ...
>>>>  >>> a = Foo()
>>>>  >>> isinstance(a, int)
>>>> True
>>>>  >>> a.__class__
>>>> <class 'int'>
>>>> 
>>>> There must be something else going on here.
>>>> 
>>> 
>>> Michael, thanks for the quick response. Okay, I'll dig in a bit further:
>>> the
>>> definition in SimpleLazyObject is
>>> 
>>> __class__ = property(new_method_proxy(operator.attrgetter("__class__")))
>>> 
>>> so perhaps the problem is something related to the specifics of the
>>> definition.
>>> Here's what I found in initial exploration:
>>> 
>>> --------------------------------------------------------------------------
>>> Python 2.7.2+ (default, Oct 4 2011, 20:06:09)
>>> [GCC 4.6.1] on linux2
>>> Type "help", "copyright", "credits" or "license" for more information.
>>>>>> from django.utils.functional import SimpleLazyObject
>>>>>> fake_bool = SimpleLazyObject(lambda: True)
>>>>>> fake_bool.__class__
>>> <type 'bool'>
>>>>>> fake_bool.__dict__
>>> {'_setupfunc': <function <lambda> at 0xca9ed8>, '_wrapped': True}
>>>>>> SimpleLazyObject.__dict__
>>> dict_proxy({
>>>    '__module__': 'django.utils.functional',
>>>    '__nonzero__': <function inner at 0xca9de8>,
>>>    '__deepcopy__': <function __deepcopy__ at 0xca9c08>,
>>>    '__str__': <function inner at 0xca9b18>,
>>>    '_setup': <function _setup at 0xca9aa0>,
>>>    '__class__': <property object at 0xca5730>,
>>>    '__hash__': <function inner at 0xca9d70>,
>>>    '__unicode__': <function inner at 0xca9b90>,
>>>    '__bool__': <function inner at 0xca9de8>,
>>>    '__eq__': <function inner at 0xca9cf8>,
>>>    '__doc__': '\n A lazy object initialised from any function.\n\n
>>>        Designed for compound objects of unknown type. For builtins or
>>>        objects of\n known type, use django.utils.functional.lazy.\n ',
>>>    '__init__': <function __init__ at 0xca9a28>
>>> })
>>> --------------------------------------------------------------------------
>>> Python 3.2.2 (default, Sep 5 2011, 21:17:14)
>>> [GCC 4.6.1] on linux2
>>> Type "help", "copyright", "credits" or "license" for more information.
>>>>>> from django.utils.functional import SimpleLazyObject
>>>>>> fake_bool = SimpleLazyObject(lambda : True)
>>>>>> fake_bool.__class__
>>> <class 'django.utils.functional.SimpleLazyObject'>
>>>>>> fake_bool.__dict__
>>> {
>>>    '_setupfunc': <function <lambda> at 0x1c36ea8>,
>>>    '_wrapped': <object object at 0x1d88b70>
>>> }
>>>>>> SimpleLazyObject.__dict__
>>> dict_proxy({
>>>    '__module__': 'django.utils.functional',
>>>    '__nonzero__': <function inner at 0x1f56490>,
>>>    '__deepcopy__': <function __deepcopy__ at 0x1f562f8>,
>>>    '__str__': <function inner at 0x1f561e8>,
>>>    '_setup': <function _setup at 0x1f56160>,
>>>    '__hash__': <function inner at 0x1f56408>,
>>>    '__unicode__': <function inner at 0x1f56270>,
>>>    '__bool__': <function inner at 0x1f56490>,
>>>    '__eq__': <function inner at 0x1f56380>,
>>>    '__doc__': '\n A lazy object initialised from any function.\n\n
>>>        Designed for compound objects of unknown type. For builtins or
>>>        objects of\n known type, use django.utils.functional.lazy.\n ',
>>>    '__init__': <function __init__ at 0x1f560d8>
>>> })
>>> --------------------------------------------------------------------------
>>> 
>>> In Python 3, there's no __class__ property as there is in Python 2,
>>> the fake_bool's type isn't bool, and the callable to set up the wrapped
>>> object never gets called (which is why _wrapped is not set to True, but to
>>> an anonymous object - this is set in SimpleLazyObject.__init__).
>>> 
>> 
>> The Python compiler can do strange things with assignment to __class__ in
>> the presence of super. This issue has now been fixed, but it may be what is
>> biting you:
>> 
>>     http://bugs.python.org/issue12370
>> 
>> If this *is* the problem, then see the workaround suggested in the issue.
>> (alias super to _super in the module scope and use the old style super
>> calling convention.)
>> 
>> Michael
>> 
>> 
>>> 
>>> Puzzling!
>>> 
>>> Regards,
>>> 
>>> Vinay Sajip
>>> 
>>> _______________________________________________
>>> Python-Dev mailing list
>>> Python-Dev at python.org
>>> http://mail.python.org/mailman/listinfo/python-dev
>>> Unsubscribe:
>>> http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.uk
>>> 
>> 
>> 
>> 
>> --
>> 
>> http://www.voidspace.org.uk/
>> 
>> May you do good and not evil
>> May you find forgiveness for yourself and forgive others
>> 
>> May you share freely, never taking more than you give.
>> -- the sqlite blessing http://www.sqlite.org/different.html
>> 
>> _______________________________________________
>> Python-Dev mailing list
>> Python-Dev at python.org
>> http://mail.python.org/mailman/listinfo/python-dev
>> Unsubscribe:
>> http://mail.python.org/mailman/options/python-dev/guido%40python.org
>> 
>> 
> 
> 
> 
> -- 
> --Guido van Rossum (python.org/~guido)
> 


--
http://www.voidspace.org.uk/


May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing 
http://www.sqlite.org/different.html







More information about the Python-Dev mailing list