1

Descriptors HowTo

Can someone please help me understand this with an example?:

If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence.

The implementation works through a precedence chain that gives data descriptors priority over instance variables, instance variables priority over non-data descriptors, and assigns lowest priority to _ getattr_() if provided.

Specifically what I don't understand is this:

  1. How can an instance's dictionary have an entry with the same name as the descriptor. Can you please give me an example?

  2. Also can you give me an example where data descriptors are being given priority over instance variables and instance variables priority over non-data descriptors etc?

Also in the code below I was surprised to see self.x in testclass invoking __ set __: I believe this behaviour is because of this explanation in the link above:

For objects, the machinery is in object.__ getattribute __ () which transforms b.x into type(b). __ dict __ ['x']. __ get __ (b, type(b)). Right ??

    #! /usr/bin/env python
    class descclass(object):

            def __init__(self, value):
                    print "in desc init"
                    self.value = value
                    print "out of desc init"                

            def __get__(self, inst, insttype):
                    print "in desc get"
                    return self.value

            def __set__(self,inst, val):
                    print "in desc set"
                    self.value = val

    class testclass(object):

            x = descclass(100)
            print "desc created"

            def __init__(self, val):
                    print "in testclass init"
                    self.x = val  # this invokes __set__ on descriptor in x
                    print "out of testclass init"

    if __name__ == '__main__':

            t = testclass(45)
            print t.x
            print vars(t)
            print vars(testclass)
4

2 回答 2

4

这是一个例子。

# Not a data descriptor because it doesn't define __set__
class NonDataDescriptor(object):
    def __get__(self, obj, objtype):
        return 3

class Namespace(object):

    # Data descriptor - defines both __get__ and __set__
    @property
    def foo(self):
        return 3

    bar = NonDataDescriptor()

x = Namespace()
x.__dict__['foo'] = 4  # We bypass the foo descriptor's __set__ here,
x.bar = 4              # but there's no bar setter, so this one goes to the dict

# x now has foo and bar descriptors and __dict__ entries

print x.foo  # prints 3 - data descriptor wins over instance __dict__ entry
print x.bar  # prints 4 - instance __dict__ entry wins over non-data descriptor
于 2013-08-21T21:35:55.717 回答
1

描述符总是的一部分;实例有自己的属性,通常它们优先于类上的任何属性。

数据描述符只是同时具有 a__get____set__方法的描述符。所以 Python 这样做:

  1. 查看是否有数据描述符;带有两个钩子的描述符。
  2. 在实例上查找属性
  3. 在类上查找常规(非数据)描述符
  4. 回退到类的常规属性

第 3 点和第 4 点实际上是一回事;描述符是具有特定方法的类属性;因此,当该属性上没有描述符挂钩时,第 4 点实际上是第 3 点。

于 2013-08-21T21:48:47.160 回答