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

2011-11-20 Thread Vinay Sajip
Michael Foord  voidspace.org.uk> writes:

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

Yes, that workaround worked. Good catch - thanks!

Regards,

Vinay Sajip

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2011-11-20 Thread Guido van Rossum
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
.

--Guido

On Sat, Nov 19, 2011 at 6:13 PM, Michael Foord
 wrote:
>
>
> On 19 November 2011 23:11, Vinay Sajip  wrote:
>>
>> Michael Foord  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__
>> > 
>> >
>> > 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__
>> 
>> >>> fake_bool.__dict__
>> {'_setupfunc':  at 0xca9ed8>, '_wrapped': True}
>> >>> SimpleLazyObject.__dict__
>> dict_proxy({
>>    '__module__': 'django.utils.functional',
>>    '__nonzero__': ,
>>    '__deepcopy__': ,
>>    '__str__': ,
>>    '_setup': ,
>>    '__class__': ,
>>    '__hash__': ,
>>    '__unicode__': ,
>>    '__bool__': ,
>>    '__eq__': ,
>>    '__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__': 
>> })
>> --
>> 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__
>> 
>> >>> fake_bool.__dict__
>> {
>>    '_setupfunc':  at 0x1c36ea8>,
>>    '_wrapped': 
>> }
>> >>> SimpleLazyObject.__dict__
>> dict_proxy({
>>    '__module__': 'django.utils.functional',
>>    '__nonzero__': ,
>>    '__deepcopy__': ,
>>    '__str__': ,
>>    '_setup': ,
>>    '__hash__': ,
>>    '__unicode__': ,
>>    '__bool__': ,
>>    '__eq__': ,
>>    '__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__': 
>> })
>> --
>>
>> 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@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@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)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2011-11-20 Thread Michael Foord

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
>  wrote:
>> 
>> 
>> On 19 November 2011 23:11, Vinay Sajip  wrote:
>>> 
>>> Michael Foord  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__
 
 
 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__
>>> 
>> fake_bool.__dict__
>>> {'_setupfunc':  at 0xca9ed8>, '_wrapped': True}
>> SimpleLazyObject.__dict__
>>> dict_proxy({
>>>'__module__': 'django.utils.functional',
>>>'__nonzero__': ,
>>>'__deepcopy__': ,
>>>'__str__': ,
>>>'_setup': ,
>>>'__class__': ,
>>>'__hash__': ,
>>>'__unicode__': ,
>>>'__bool__': ,
>>>'__eq__': ,
>>>'__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__': 
>>> })
>>> --
>>> 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__
>>> 
>> fake_bool.__dict__
>>> {
>>>'_setupfunc':  at 0x1c36ea8>,
>>>'_wrapped': 
>>> }
>> SimpleLazyObject.__dict__
>>> dict_proxy({
>>>'__module__': 'django.utils.functional',
>>>'__nonzero__': ,
>>>'__deepcopy__': ,
>>>'__str__': ,
>>>'_setup': ,
>>>'__hash__': ,
>>>'__unicode__': ,
>>>'__bool__': ,
>>>'__eq__': ,
>>>'__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__': 
>>> })
>>> --
>>> 
>>> 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@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 

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

2011-11-20 Thread Guido van Rossum
On Sun, Nov 20, 2011 at 10:44 AM, Michael Foord
 wrote:
>
> 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.

Hm, okay. Though it's disheartening that it took three releases of 3.x
to figure this out. And there was a PEP even!

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

Ah, oops. Yes, __instancecheck__ is for the class to override
isinstance(inst, cls); for the *instance* to override apparently
you'll need to mess with __class__.

I guess my request at this point would be to replace '@__class__' with
some other *legal* __identifier__ that doesn't clash with existing use
-- I don't like the arbitrary use of @ here.

--Guido

> All the best,
>
> Michael Foord
>
>> --Guido
>>
>> On Sat, Nov 19, 2011 at 6:13 PM, Michael Foord
>>  wrote:
>>>
>>>
>>> On 19 November 2011 23:11, Vinay Sajip  wrote:

 Michael Foord  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__
> 
>
> 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__
 
>>> fake_bool.__dict__
 {'_setupfunc':  at 0xca9ed8>, '_wrapped': True}
>>> SimpleLazyObject.__dict__
 dict_proxy({
    '__module__': 'django.utils.functional',
    '__nonzero__': ,
    '__deepcopy__': ,
    '__str__': ,
    '_setup': ,
    '__class__': ,
    '__hash__': ,
    '__unicode__': ,
    '__bool__': ,
    '__eq__': ,
    '__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__': 
 })
 --
 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__
 
>>> fake_bool.__dict__
 {
    '_setupfunc':  at 0x1c36ea8>,
    '_wrapped': 
 }
>>> SimpleLazyObject.__dict__
 dict_proxy({
    '__module__': 'django.utils.functional',
    '__nonzero__': ,
    '__deepcopy__': ,
    '__str__': ,
    '_setup': ,
    '__hash__': ,
    '__unicode__': ,
    '__bool__': ,
    '__eq__': ,
    '__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__': 
 })
 --

 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 issu