5

I am learning Python, and I am trying to understand descriptors better. When I look at this Python online book: http://www.cafepy.com/article/python_attributes_and_methods/ch01s05.html, it says:

  1. If attrname is a special (i.e. Python-provided) attribute for objectname, return it.

I don't understand what Python-provided means. Can someone give me an exemple of such Python-provided attribute that would take precedence over the usual resolution order?

Note: I am only interested in new-style classes (as descriptors don't even apply to old-style as far as I know).

Flavien
  • 7,497
  • 10
  • 45
  • 52

2 Answers2

1

__class__, for instance:

>>> class Test(object):
    __dict__ = {'__class__' : "dict of Test"}
    def __init__(self):
        self.__dict__['__class__'] = "dict of test"


>>> test = Test()
>>> test.__class__
<class '__main__.Test'>
>>> test.__dict__
{'__class__': 'dict of test'}
>>> Test.__dict__
dict_proxy({'__dict__': {'__class__': 'dict of test'}, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, '__init__': <function __init__ at 0x02BD2770>})
>>> 

equivalent in old-style-classes:

>>> class Test:
        pass

>>> Test.__dict__["__class__"] = "spam"
>>> test = Test()
>>> test.__class__
<class __main__.Test at 0x02BD1110>
>>> test.__dict__ = {'__class__': "foo"}
>>> test.__class__
<class __main__.Test at 0x02BD1110>

while

>>> test.__dict__ = {'__lolcat__': "bar"}
>>> test.__lolcat__
'bar'

There are many more special attribute names, depending on the type of the object. For instance, functions:

>>> def test():pass

>>> dir(test)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
>>> test.func_closure
>>> test.__dict__['func_closure']='roflcopter'
>>> test.func_closure
>>> test.__dict__['foo']='bar'
>>> test.foo
'bar'

see http://docs.python.org/reference/datamodel.html for an overview

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
ch3ka
  • 11,792
  • 4
  • 31
  • 28
  • I didn't realise this before, but directly modifying a `__dict__` of a class doesn't seem to work with new-style classes - it results in `TypeError: 'dict_proxy' object does not support item assignment`. You can still see the above behaviour in python 3 by modifying the `__dict__` of the instance, i.e. `test.__dict__["__class__"] = "spam"`. Also, do you know what other attributes work like this? The only other one I have found is `__dict__` itself. – James May 10 '12 at 15:12
  • My question was about new-style classes, what you demonstrate only works on old-style. – Flavien May 10 '12 at 15:25
  • Well, actually, that is the normal resolution order. It takes the value from the data descriptor in object's dictionary, as expected. `test = Test() ` `print("__class__" in type(test).__dict__) # Looking for a descriptor in the classes __dict__: false` `print("__class__" in object.__dict__) # Same with parent class: true` `print(object.__dict__["__class__"].__get__) # It's a descriptor` `print(object.__dict__["__class__"].__set__)` You exemple doesn't show it is being treated differently. – Flavien May 10 '12 at 16:21
  • now i'm confused. checkout: `>>> class Test(object): __class__ = "dict of Test" def __init__(self): self.__dict__['__class__'] = "dict of test"`, then `>>> test.__class__ 'dict of test'`, so it seems __class__ is not special at all?! OTOH, `>>> Test.__class__ ` I'm kinda confused now – ch3ka May 10 '12 at 16:36
  • it seems like this contradicts the book, because if `__class__` isn't special, how would the code lookup `objectname.__class__.__dict__` in step two, when objname has a non-class `.__class__`? It seems to me `__class__` *has* to be special for this algo to work. – ch3ka May 10 '12 at 16:42
  • I think the book is inaccurate, the code actually looks up `type(objectname).__dict__`, and `type(objectname)` is different from `objectname.__class__` because it bypasses completely `objectname.__dict__`, and go directly to the class object (see http://docs.python.org/reference/datamodel.html#new-style-special-lookup). – Flavien May 10 '12 at 17:02
  • Setting `__dict__` in the class definition does not actually affect the `__dict__` of the class. – Ethan Furman Oct 05 '12 at 23:26
0

As you guessed, step 1 is flat-out wrong and doesn't exist.

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237