python魔法属性魔法方法_技术图文:Python魔法方法之属性访问详解

原标题:技术图文:Python魔法方法之属性访问详解

背景

今天在B站学习“零基础入门学习 Python”中的第45节“魔法方法:属性访问”,这也是我们组织的 的学习任务,其中有这样的一个题目。

练习要求:

写一个矩形类,默认有宽和高两个属性。

如果为一个叫square的属性赋值赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。

技术分析

我们先来看看有关于属性的四个魔法方法:

getattr(self, name): 定义当用户试图获取一个不存在的属性时的行为。

getattribute__(self, name)`:定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用`__getattr)。

setattr(self, name, value):定义当一个属性被设置时的行为。

delattr(self, name):定义当一个属性被删除时的行为。

classTest:

def__getattr__(self, name):

print( '__getattr__')

def__getattribute__(self, name):

print( '__getattribute__')

def__setattr__(self, name, value):

print( '__setattr__')

def__delattr__(self, name):

print( '__delattr__')

t = Test

t.x

# __getattribute__

如上述代码所示,x并不是Test实例对象t的一个属性,首先去调用 __getattribute__ 方法,得知该属性并不属于该实例对象。但是,按照常理,t.x应该打印 __getattribute__ 和__getattr__,但实际情况并非如此,为什么呢?

实例对象属性寻找的顺序如下:

① 首先访问 __getattribute__ 魔法方法(隐含默认调用,无论何种情况,均会调用此方法)。

② 接着,去t.__dict__中查找是否具备该属性。

③ 若在 t.__dict__ 中找不到对应的属性, 则去t.__class__.__dict__中寻找。

④ 若在实例的类中也找不到该属性,则去父类中寻找,即 t.__class__.__bases__.__dict__中寻找

⑤ 若以上均无法找到,则会调用 __getattr__ 方法,执行内部的命令(若未重载 __getattr__ 方法,则直接报错:AttributeError)

以上几个流程,即完成了属性的寻找。

但是,以上的说法,并不能解释为什么执行 t.x 时,不打印 __getattr__ 啊?

问题就出在了步骤的第④步,因为,一旦重载了 __getattribute__ 方法,如果找不到属性,则必须要手动加入第④步,否则无法进入到 第⑤步 (__getattr__)的。

验证一下以上说法是否正确:

方法一:采用 object(所有类的基类)

classTest:

def__getattr__(self, name):

print( '__getattr__')

def__getattribute__(self, name):

print( '__getattribute__')

object.__getattribute__(self, name)

def__setattr__(self, name, value):

print( '__setattr__')

def__delattr__(self, name):

print( '__delattr__')

t = Test

t.x

# __getattribute__

# __getattr__

方法二:采用 super 方法

classTest:

def__getattr__(self, name):

print( '__getattr__')

def__getattribute__(self, name):

print( '__getattribute__')

super.__getattribute__(name)

def__setattr__(self, name, value):

print( '__setattr__')

def__delattr__(self, name):

print( '__delattr__')

t = Test

t.x

# __getattribute__

# __getattr__

以上介绍完毕,那么 __setattr__ 和 __delattr__ 方法相对简单多了:

classTest:

def__getattr__(self, name):

print( '__getattr__')

def__getattribute__(self, name):

print( '__getattribute__')

object.__getattribute__(self, name)

def__setattr__(self, name, value):

print( '__setattr__')

def__delattr__(self, name):

print( '__delattr__')

t = Test

t.x = 1

# __setattr__

delt.x

# __delattr__

对了,再补充一点哈!

classTest:

def__init__(self):

self.count = 0

def__setattr__(self, name, value):

print( '__setattr__')

self.count += 1

t = Test

# AttributeError: 'Test' object has no attribute 'count'

看报错信息很容易明白,这是因为:

① __init__时,给内部属性 self.count进行了赋值;

② 赋值默认调用 __setattr__ 方法

③ 当调用 __setattr__方法时,首先打印 __setattr__字符串,而后执行 self.cout += 1操作

④ 当执行 self.cout + 1 操作时,将会去寻找 count 这个属性,然而,由于此时 __init__尚未完成,并不存在 count这个属性,因此导致 AttributeError 错误。

那么该如何更改呢?可以这样的:

classTest:

def__init__(self):

self.count = 0

def__setattr__(self, name, value):

print( '__setattr__')

super.__setattr__(name, value + 1)

t = Test

print(t.count)

# __setattr__

# 1

以上代码虽然解决了报错的问题,深入体会一下,你会发现,采用此方法只是给 基类object增加了一个属性 count,而并不是实例的属性,因此,以上这种写法避免使用。

另外,再次将代码改进一下,如下:

classTest:

def__setattr__(self, name, value):

self.name = value

t = Test

t.x = 'lsgo'

# Recursi: maximum recursion depth exceeded

当我们给 t.x 赋值时,调用了 __setattr__方法,进入该方法。该方法中,又来了一次赋值(self.name = value),又会去调用 __setattr__ 方法,持续这个死循环。

所以,我们只好改变上述的问题了:

classTest:

def__setattr__(self, name, value):

print( '__setattr__ been called')

super.__setattr__(name, value)

t = Test

t.x = 'lsgo'

# __setattr__ been called

print(t.x)

# lsgo

代码实现

上面详细介绍了关于属性的四个魔法方法,下面我们来看实现要求的具体代码:

classRectangle:

def__init__(self, width=0, height=0):

self.width = width

self.height = height

def__setattr__(self, key, value):

ifkey == 'square':

self.width = value

self.height = value

else:

super.__setattr__(key, value)

defgetArea(self):

returnfloat(self.width) * float(self.height)

r = Rectangle( 4, 5)

print(r.getArea) # 20.0

r.square = 10

print(r.__dict__) # {'width': 10, 'height': 10}

print(r.getArea) # 100.0

总结

魔法方法是 Python 面向对象编程中最核心的内容,需要花费一定的精力才能将其掌握,参加 Python基础刻意练习的小伙伴们加油!See You!

参考文献:

https://www.bilibili.com/video/av4050443/?p=46

https://www.runoob.com/python3/python3-tutorial.html

https://www.cnblogs.com/Jimmy1988/p/6804095.html

相关图文:

经过8年多的发展,LSGO软件技术团队在「地理信息系统」、「数据统计分析」、「计算机视觉」等领域积累了丰富的研发经验,也建立了人才培养的完备体系,目前深耕的领域为「机器学习与量化金融」,欢迎对计算机技术感兴趣的同学加入,与我们共同成长进步。

后台回复「搜搜搜」,随机获取电子资源!返回搜狐,查看更多

责任编辑:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值