Python 方法调用流程详解

python 新式类引进了内建属性__getattribute__,访问属性都要先通过内建属性__getattribute__,接下来谈谈类和实例分别访问属性的过程

class DevNull:
    def __init__(self,initval = None,name='var'):
        self.val = initval
        self.name = name

    def __get__(self, instance, owner):
        #self指的是RevealAccess实例,instance代表被代理的类的实例,owner代表被代理的类
        print("获取..",self.name)
        return self.val

    def __set__(self, instance, value):
        print("设置值:",self.name)
        self.val = value

class MyClass(object):
    x = DevNull(1000,"var 'x'")
    def foo(self):
        print("hello world")
m=MyClass()
m.x
输出:
获取.. var 'x'
1000

x属性是数据描述符,DevNull同时拥有 set 和 __get__方法,实例访问x, getattribute__会调用数据描述符的__get 方法

m.x=1
m.x
输出:
设置值: var 'x'
获取.. var 'x'
1

上面m.x=1触发了数据描述符的__set__ 方法,修改了DevNull中self.val的值。所以__get__返回的值也发生了变化。

print(m.__dict__)
输出 {}
print(MyClass.x)
MyClass.x=1
print(MyClass.x)

输出:
获取.. var 'x'
1000
1

上面通过类访问x,第一次通过数据描述符DevNull 的__get__,而第二次访问x,没有经过__get__ 并且类对x的赋值并没有触发数据描述符的__set__方法;这说明类对x赋值,把之前类中数据描述符属性x给覆盖了,所以再次通过类访问x,没有经过__get__.

接下来分析非数据描述符的情况

class DevNull:
    def __init__(self,initval = None,name='var'):
        self.val = initval
        self.name = name

    def __get__(self, instance, owner):
        #self指的是RevealAccess实例,instance代表被代理的类的实例,owner代表被代理的类
        print("获取..",self.name)
        return self.val

   # def __set__(self, instance, value):
    #     print("设置值:",self.name)
    #     self.val = value

class MyClass(object):
    x = DevNull(1000,"var 'x'")
    def foo(self):
        print("hello world")
m=MyClass()
m.x
输出:
获取.. var 'x'
1000

可以看出和数据描述符的情况一直

m.x=1
print(m.x)
输出:
1

对于非数据描述符x,实例修改x的值后,访问x, 没有经过__get__,非数据描述符x被实例属性x覆盖了。

print(m.__dict__)
输出:
{'x': 1}

接下来看下类访问非数据描述符x

print(MyClass.x)
MyClass.x=1
print(MyClass.x)

输出:
获取.. var 'x'
1000
1

与最上面非数据描述符的情况一致;

通过以上的分析由此得出以下结论:
通过类访问属性时有无数据描述符区别

通过实例访问属性时,遵循
数据描述符级别>实例属性>非数据描述符

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值