关于python中的钩子方法和内置函数的举例

在学习python的类知识的时候,总是看到各种带__的属性、方法,其中上次也总结了这些带下划线的成员的知识点。这里面有一些我感到特别的好奇,所以也做一下总结。

__getattr__getattr

我首先感到好奇的类当中的反射。在一个定义的类当中,可以用getattr(object, name, [,defalut])来获取object对象中的name属性,同时也有的使用object.__getattr__(self, name)来获取objectname属性。

这两个长得那么像,总感觉他们是一个东西啊。于是我开始进一步去了解后,发现实际上他们两个,还真不是一个东西。getattrpython自带的全局函数,而__getattr__是一个需要用户在类中定义以后才可以用的方法。这里就需要搞清楚python自带的全局函数和这种需要用户在类中自定义的方法的区别是什么?

python自带的全局函数是python自带的,随时所有人都可以用,在哪里都可以用;而需要用户在类中定义的方法(也叫钩子方法)则是用户定义了就有,没定义就按python默认的走,有点类似用户定义了,解释器就会在适当的时机下去触发它。所以他们本质上是不一样的。

getattr__getattr__来举例:

python 复制代码
class A:
	pass
	
class B:
	def __getattr__(self, name):
		print(f'正在访问{self.name}')
		return self.name

a = A()
b = B()

print(a.x)    
# -> AttributeError: 'A' object has no attribute 'x'
# class A没有定义__getattr__钩子方法,所有解释器就会抛出异常

print(b.x)    
# -> 正在访问x
# -> x
# class B定义了__getattr__钩子方法,所有这里解释器就去触发了钩子方法,返回了x  

print(getattr(a, 'x', 'default a'))
# -> default a

print(getattr(a, 'x'))
# -> AttributeError: 'A' object has no attribute 'x'

print(getattr(b, 'x', 'default b'))
# -> 正在访问x
# -> x

# 这里就体现了getattr和__getattr__的联系,下面用一个图来体现他们俩的联系

getattr__getattr__的联系:

也不是所有的钩子函数都类似__getattr__getattr它俩这样的关系,比如len()__len__它们俩就与之不一样。len()也是python内置内置的全局函数,但它需要在类中定义了__len__才可以使用,平常我们使用len(1)len([1,2,3])可以用,是因为在int类、str类、list类中已经定义了__len__方法了。

python 复制代码
class A:
	pass

class B:
	def __len__(self):
		return 42
		
class C:
	def __len__(self):
		return "42"
		
a = A()
b = B()
c = C()

len(a)
# --> TypeError: object of type 'A' has no len()
# 虽然len是内置函数,但是它是去调用__len__这个钩子方法,如果用户定义了这个钩子方法,这个len才可以正常使用,没定义,就不能正常使用
# 这个和getattr这个内置函数就有一些区别
# getattr内置函数是,不管定义还是没定义,都可以使用,只是如果定义了__getattr__这个钩子方法,getattr会多调用一步

print(len(b))
# --> 42

print(len(c))
# --> TypeError: 'str' object cannot be interpreted as an integer
# 注意这里报错,是因为内置函数len要求__len__必须返回非负整数,而自己定义的__len__返回了一个字符串,所以报错

从上面两个例子来看,内置函数和钩子方法有点像是python的制造大师们,把内置函数开发好了,提供给开发者们用,但是也配置了一些使用方法,有的内置函数使用方法上要配合一些钩子函数来使用,而这个内置函数对钩子函数的使用方式又各有不同。

__getattr____getattribute__

除了有内置函数getattr__getattr__很像以外,还有另外一个方法__getattribute__也和它非常像,那它们俩又是什么关系呢?他们俩都是python中的魔术方法,但__getattr__是用户定义了才有,而__getattribute__是在python的基类object类中定义好的,不管用户定义还是不定义,它都存在,只是如果用户定义了,就会覆盖__getattribute__。所以如果说钩子方法是用户定义才有,没定义就没有的话,__getattribute__就不算是一个钩子方法了。

那么他们俩在功能上有什么联系?我也用一个图来进行总结。这个图中访问类中的属性,可以是通过object.xxx的形式来访问,也可以是通过getattr(object,'x',)的方式来访问。

注意 :如果getattr中提供了默认值,那么在调用__getattribte__以后如果没有返回值,那么就直接去getattr的默认值了,不会再去调用__getattr__了。

相关推荐
程序员小远2 小时前
软件测试之单元测试详解
自动化测试·软件测试·python·测试工具·职场和发展·单元测试·测试用例
心无旁骛~3 小时前
python多进程和多线程问题
开发语言·python
星云数灵3 小时前
使用Anaconda管理Python环境:安装与验证Pandas、NumPy、Matplotlib
开发语言·python·数据分析·pandas·教程·环境配置·anaconda
计算机毕设匠心工作室3 小时前
【python大数据毕设实战】青少年抑郁症风险数据分析可视化系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习
后端·python
计算机毕设小月哥3 小时前
【Hadoop+Spark+python毕设】智能制造生产效能分析与可视化系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
计算机毕设小月哥6 小时前
【Hadoop+Spark+python毕设】中风患者数据可视化分析系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
Keep_Trying_Go6 小时前
基于Zero-Shot的目标计数算法详解(Open-world Text-specified Object Counting)
人工智能·pytorch·python·算法·多模态·目标统计
计算机毕设匠心工作室6 小时前
【python大数据毕设实战】强迫症特征与影响因素数据分析系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习、实战教学
后端·python·mysql
Trouville017 小时前
Pycharm软件初始化设置,字体和shell路径如何设置到最舒服
ide·python·pycharm