[Python-ideas] An even simpler customization of class creation

Nick Coghlan ncoghlan at gmail.com
Mon Mar 9 14:36:59 CET 2015


On 9 March 2015 at 22:40, Andrew Barnert <abarnert at yahoo.com> wrote:
> On Mar 8, 2015, at 5:22 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>
>
> On 9 Mar 2015 10:12, "Nick Coghlan" <ncoghlan at gmail.com> wrote:
>>
>>
>> On 9 Mar 2015 03:18, "Mark Young" <marky1991 at gmail.com> wrote:
>> >
>> > Thanks Nick! I swear I checked on the 3.x "Data Model" page, but I guess
>> > not.
>>
>> Every other reference on that page is to the class attribute rather than
>> the implicit method nonlocal, so it took a moment for me to relocate it
>> myself. I should have searched for "super" instead :)
>
> With the benefit of hindsight, if I had the chance to do this over, I'd
> suggest we call the implicit method nonlocal "__classdef__" instead,
> specifically to avoid the name collision with the runtime type information
> on object instances. My general impression is that the current name triggers
> too many incorrect assumptions for most readers, and the name collision
> makes it harder than it needs to be to build a more correct mental model.
>
> I can tell you that every single time I've mentioned the __class__ nonlocal
> in a StackOverflow answer, someone mistakenly "corrected" me to tell me
> either "you need to write self.__class__" or "that won't work because it's
> the runtime type of self, which could be a subclass".
>
> I think a better solution, if you were doing it from scratch, might be to
> get rid of the __class__ member and force people to use type(self) to get
> it, so TOOTDI.

They're not substitutes for each other, as __class__ lets you lie
about your type to the consumer, while type() doesn't, and this is by
design:

>>> import weakref
>>> class Example():
...     pass
...
>>> a = Example()
>>> b = weakref.proxy(a)
>>> b.__class__
<class '__main__.Example'>
>>> type(b)
<class 'weakproxy'>

For many use cases, you actually want obj.__class__ in order to handle
proxy objects correctly.

> (Of course that implies that code that needs to change
> __class__ would have to call some function to do so, but I'm not sure that's
> a bad thing. Dynamically changing your type is a rare thing to do in Python,
> and unusual or impossible in most other OO languages, except maybe during
> initialization in the Smalltalk family, so why shouldn't it be signaled by
> something scary?)

It's not (just) about being able to dynamically change your type, it's
about the fact that __class__ goes through the descriptor and class
attribute lookup machinery, while type() doesn't.

>
> On the other hand, is __class__ the only thing that's spelled with double
> underscored that isn't an attribute? Maybe that's the part that's confusing
> people...

It's not the only one - implicit module attributes like __name__ work
that way, as do the __debug__ and __import__ builtins.

As far as I can tell, it's specifically the fact that "__class__"
looks like a plausible typo for "self.__class__" that causes problems,
as this also creates the problem that if you search for "__class__"
not only on the data model page, but anywhere, you're far more likely
to get a hit on the attribute (which has been around for as long as
Python has had classes) than you will on the implicit method nonlocal
introduced in Python 3.

Hence why I suspect changing/aliasing the preferred name for
referencing the nonlocal to be __classdef__ may help improve things,
as it better hints at the lexical scoping, where you're referring to
the class where the method is being defined at compile time, rather
than the one where it was retrieved at run time.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list