Python 魔法方法3

Python 魔法方法2icon-default.png?t=N3I4https://blog.csdn.net/qq_49873907/article/details/130320814?spm=1001.2014.3001.5501       

        本篇文章主要介绍与属性访问相关的函数和魔法方法,主要包括__getattr__()、__getattribute__()、__setattr__()、__delattr__()。

一、与属性访问相关的函数

        对于与属性访问相关的函数分别为hasattr()、getattr()、setattr()、delattr()。我们通过一个例子来进行简单说明:

class C:
	def __init__(self,name,age):
		self.name = name
		self.__age = age    #定义一个私有的属性age [属性名前加两个下划线__]

		
c = C("Python",22)
hasattr(c,"name")          #这里hasattr第二个参数要加上引号
# True
hasattr(c,"age")           #要注意访问私有变量要用"_类名__属性名"的形式进行强访问
# False
hasattr(c,"_C__age")
# True
getattr(c,"name")          #获取属性值
# 'Python' 

getattr(c,"_C__age")     
# 22
setattr(c,"_C__age",18)   #设置属性值
getattr(c,"_C__age")
# 18
delattr(c,"_C__age")      #删除属性值
hasattr(c,"_C__age")
# False

        通过上述代码不难看出,这些和属性访问相关的方法和点好运算符是等价的。 

二、与属性访问相关的魔法方法

2.1 __getattribute__()

        对于__getattrible__()魔法方法,与之对应的是getattr()函数,这里有点特殊,因为可能大家都会比较认同getattr()函数对应的魔法方法应该是__getattr__()才更加匹配,可事实不是这样,我们通过一个例子来简单说明:

class C:
	def __init__(self,name,age):
		self.name = name
		self.__age = age
	def __getattribute__(self,attrname):       
		print("访问了getattribute")
		return super().__getattribute__(attrname) 

'''
super()调用的是父类的object的__getattribute__()方法
Python中所有类默认继承object类,而调用object中的
__getattributr__(attrname)的结果就是return attrname
'''

	def __getattr__(self,attrname):
		if attrname == "Python":               # 当访问的属性名是Python时,打印结果
			print("I Love Python")
		else:
			raise AttributrError(attrname)     

		
c = C("hello",22)
getattr(c,"name")
# 访问了getattribute
# 'hello'
c.name                 #点号运算符和getattr()等价
# 访问了getattribute
# 'hello'
getattr(c,"Python")
# 访问了getattribute
# I Love Python
getattr(c,"123")
# 访问了getattribute
'''
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    getattr(c,"123")
  File "<pyshell#23>", line 12, in __getattr__
    raise AttributrError(attrname)
NameError: name 'AttributrError' is not defined

'''

        通过上述代码,我们可以看出,只有当用户试图访问不存在的属性时,才会去触发__getattr__()方法,不过还是会先访问__getattribute__()方法。

2.2 __setattr__() 

        setattr() 对应的魔法方法是__setattr__() ,对属性进行赋值操作,虽然不像__getattribute__()那样,不过其中还是有需要注意的点的。

class C:
	def __setattr__(self,name,value): 
		self.name = value                        #陷入无限递归

		
c = C()
setattr(c,"name","python") 

#死循环报错
'''                                             
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    setattr(c,"name","python")
  File "<pyshell#33>", line 3, in __setattr__
    self.name = value
  File "<pyshell#33>", line 3, in __setattr__
    self.name = value
  File "<pyshell#33>", line 3, in __setattr__
    self.name = value
  [Previous line repeated 990 more times]
RecursionError: maximum recursion depth exceeded

'''
class C:                        
	def __setattr__(self,name,value):
		return super().__setattr__(name,value)            #调用父类解决

	
c =C()
setattr(c,"name","Python")
getattr(c,"name")
# 'Python'

class C: 
	def __setattr__(self,name,value):
		self.__dict__[name] = value                      #使用__dict__利用集合实现

		
c = C()
setattr(c,"name","Python")
getattr(c,"name")
# 'Python'

        通过上述代码可以看出,进行赋值操作的时候陷入了无限循环,因为__setattr__()本身就是进行赋值,执行方法体中的代码再一次进行了赋值,这不就相当于实现递归,自己调用自己了吗。我们有两种解决方式,第一种是直接交给父类来处理,实现函数原本的功能,在一个是借助__dict__()函数,利用集合来实现赋值的操作。

2.3 __delattr__() 

        __delattr__()魔法方法对应着delattr()函数,用来删除属性值。它和__setattr__()同样要注意递归的问题,这里可以参考上面__setattr__()的说明。

# 法1
class C:
	def __setattr__(self,name,value):
		return super().__setattr__(name,value)
	def __delattr__(self,name):
		return super().__delattr__(name)

	
c = C()

setattr(c,"name","haha")
c.__dict__
# {'name': 'haha'}
delattr(c,"name")
c.__dict__
# {}

# 法2
class C:
	def __setattr__(self,name,value):
		self.__dict__[name] = value
	def __delattr__(self,name):
		del self.__dict__[name]

		
c = C()
setattr(c,"name","haha")
c.__dict__
# {'name': 'haha'}
delattr(c,"name")
c.__dict__
# {}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学者山羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值