python 属性访问的顺序_属性访问

1.__dict__

什么是属性?

属性就是从一个对象到另一个对象的方法。

一个属性访问返回了哪个对象,对象在哪被设置为属性。这是本章需要解答的问题。

用户定义的属性通常(不全部都是)存在于这个对象的__dict__属性中。 例如:

class C(object):

classattr = 'attr on class'

cobj = C()

cobj.instattr = 'attr on instance'

>>>cobj.__dict__

{'instattr': 'attr on instance'}

>>>C.__dict__

{'classattr': 'attr on class', '__dict__': , '__module__': '__main__', '__weakref__': , '__doc__': None}

访问属性时,以下对象按顺序被搜索:

1. 对象本身(objectname.__dict__)

2. 对象的类型(objectname.__class__.__dict__)。

3. 对象的类的基类,和基类的基类,等等(每个objectname.__class__.__bases__的__dict__)

注意:对类来说,objectname.__bases__在object.__class__之前被搜索。

2.从函数到方法

class C(object):

classattr = 'attr on class'

def f(self):

return "function f"

cobj = C()

>>>cobj.classattr is C.__dict__['classattr']

True

>>>cobj.f is C.__dict__['f']

False

>>>cobj.f

>

>>>C.f

>>>C.__dict__['f']

>>>C.__dict__['f'].__get__(cobj, C)

>

绑定方法:绑定方法是一个可调用的对象,它调用一个函数传递一个实例作为第一个参数,没有传递这个函数需要的其他参数。

python创建一个绑定方法:在查找实例的属性时,如果Python在类的__dict__中找到一个带有__get__()方法的对象,而不是返回该对象,则会调用__get__()方法并返回结果。 请注意,使用实例和类分别作为第一个和第二个参数调用__get__()方法。

instance.attr 等价于 instance.__class__.__dict__['attr'].__get__(instance, obj)

3.创建描述符

任何对象有__get__()方法,以及可选的__set__()和__delete__()方法,并接受特殊的参数,这样被称之为遵循描述符协议。这样的对象就叫做描述符,可以被放入一个类的__dict__中,以便在检索,设置或删除时,执行特殊操作。

class Desc(object):

def __get__(self, instance, owner):

pass

def __set__(self, instance, value):

pass

def __delete__(self, instance):

pass

class C(object):

d = Desc()

cobj = C()

// 给实例的__dict__中添加了一个值。

cobj.__dict__['d'] = 'try to force a value'

// 还是触发__get__方法。

x = cobj.d

// 触发__get__(None, C)

x = C.d

// 描述符被替换了

C.d = 'set'

注意:

1. 优先使用描述符。

2. 当访问,修改,或是删除类的描述符属性(classname.descriptor_name)时,只有__get__()方法能触发,而删除和修改将会去除和替换掉描述符。

4.两种类型的描述符

data descriptor: 具有__get__()和__set__()方法的描述符。

non-data descriptor: 只具有__get__()方法的描述符。

例子:non-data descriptor

class GetonlyDesc(object):

def __get__(self, instance, owner):

pass

class C(object):

d = GetonlyDesc()

cobj = C()

// 将d放入cobj.__dict__中

cobj.d = 'set'

// 访问的是cobj.__dict__中的d

x = cobj.d

// 删除cobj.__dict__中的d

del cobj.d

// 和之前一样

x = C.d

C.d = 'set'

注意: 1. 没有__set__()不仅影响属性设置,同样影响取回。

本节总结:Data descriptors are useful for providing full control over an attribute. This is what one usually wants for attributes used to store some piece of data. For example an attribute that gets transformed and saved somewhere on setting, would usually be reverse-transformed and returned when read. When you have a data descriptor, it controls all access (both read and write) to the attribute on an instance. Of course, you could still directly go to the class and replace the descriptor, but you can't do that from an instance of the class.

Non-data descriptors, in contrast, only provide a value when an instance itself does not have a value. So setting the attribute on an instance hides the descriptor. This is particularly useful in the case of functions (which are non-data descriptors) as it allows one to hide a function defined in the class by attaching one to an instance.

5.属性搜索总结

当检索对象的属性时(objectname.attrname),python遵循以下步骤:

1. 如果attrname是一个特殊的属性(例如:python提供的),返回它。

2. 检查objectname.__class__.__dict__中是否有attrname。如果它存在且是一个data-descriptor,返回描述符结果。同时搜索objectname.__class__的所有父级。

3. 检查objectname.__dict__中是否有attrname,如果找到则返回。如果objectname是一个类,也去搜索它的基类。如果objectname是类,描述符存在它或它父级中,返回描述符。

4. 检查objectname.__class__.__dict__,如果它存在是一个non-data descriptor,返回描述符结果。如果它存在,不是一个描述符,返回它。同时搜索objectname.__class__的所有父级。

python首先找这个对象的类和这个类父级中的资料描述符,然后找对象__dict__中的属性,然后找这个对象的类和这个类父级中的非资料描述符。

上面的描述符结果指的是传入适当的参数调用描述符__get__()方法返回的结果。检查__dict__中是否有attrname意味着是否存在__dict__["attrname"]。

现在,python当设置一个用户定义的属性时遵循的步骤(objectname.attrname = something):

1. 检查objectname.__class__.__dict__中是否有attrname属性。如果他存在是一个data-descriptor,使用描述符来设置值。同时搜索objectname.__class__的父类。

2. 为objectname.__dict__名为"attrname"的键插入值。

python提供的描述符

例子:内建描述符

class HidesA(object):

def get_a(self):

return self.b - 1

def set_a(self, val):

self.b = val + 1

def del_a(self):

del self.b

a = property(get_a, set_a, del_a, "docstring")

def cls_method(cls):

return "You called class%s" % cls

clsMethod = classmethod(cls_method)

def stc_method():

return "Unbindable!"

stcMethod = staticmethod(stc_method)property: 通过调用函数这种的方式来访问,设置或删除实例的属性。当检索类的属性时,不会调用getter方法,会返回property对象本身。可以通过HidesA.a.__doc__来访问docstring。

类方法和常规的方法类似,除了将类作为第一个参数传给函数。类和实例都可以直接调用(instance.clsMethod() or class.clsMethod())。

静态方法和函数类似。

property注意要点:

1. getter和setter可以被定义在类外面。

2. Another useful observation would be to note that subclassing the class and redefining the getter (or setter) functions is not going to change the property.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值