Python 方法调用流程详解

本文深入探讨Python中描述符的概念,特别是数据描述符与非数据描述符的区别,以及它们如何影响类和实例属性的访问与赋值过程。通过具体代码示例,详细解释了描述符的__get__和__set__方法在不同场景下的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值