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

Vinay Sajip vinay_sajip at yahoo.co.uk
Sun Nov 20 00:11:38 CET 2011


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__).

Puzzling!

Regards,

Vinay Sajip



More information about the Python-Dev mailing list