一、面向对象编程之反射
python是动态语言,而
反射机制被视为动态语言的关键。
(一)基本概念
反射机制:
反射是一种“能力”,指的是在程序的运行状态中,对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性。即在程序运行过程中,可以"动态"获取对象的信息,调用属性或方法。
那么反射有什么作用呢?
当我们想要查看对象拥有的属性时,使用的是__dict__方法,不过对象使用这个方法取不到类的属性,只能取到对象专属于自己的属性。而通过dir()方法,就可以获取到对象的所有属性,其中也包括类的属性和一系列内置属性。
class test:
x = 1
y = 2
def z(self):
return self.x + self.y
obj = test()
print(obj.__dict__)
# {}
print(dir(obj))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y', 'z']
这样的话,我们得到的就是一系列字符串格式的属性和方法,但并不能使用(在某些情况下,我们是要让用户使用到其中的某些方法的,即程序自动获取,自动调用或者用户触发调用),所以python给我们提供了反射。
(二)实现反射
反射是通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射四大函数(通过字符串来操作属性值)
class test:
x = 1
y = 2
def __init__(self, m, n):
self.m = m
self.n = n
def z(self):
return self.x + self.y
obj = test(3, 4)
-
hasattr():判断某个属性是否存在
print(hasattr(obj, 'x')) # True print(hasattr(obj, 'z')) # True print(hasattr(obj, 'n')) # True print(hasattr(obj, '混入其中')) # False -
getattr():获取某个属性的值
print(getattr(obj, 'x')) # 1 print(getattr(obj, 'z')) # <bound method test.z of <__main__.test object at 0x0000014B51775640>> print(getattr(obj, 'n')) # 4 print(getattr(obj, '混入其中')) # 报错,找不到就报错 # 我们可以添加第三个参数来设置找不到时的返回值 print(getattr(obj, '混入其中', None)) # None -
setattr():设置某个属性(有则更改,无则创建)
setattr(obj, 'x', 100) # obj.x = 100 print(obj.x) # 100 setattr(obj, 'name', '山炮') print(obj.name) # 山炮 -
delattr():删除某个属性
print(obj.m) # 3 delattr(obj, 'm') print(obj.m) # 报错,找不到
注意:在python中一切皆对象,所以反射四大方法也适用于一切对象。
当不确定对象有没有某些方法时,可以先进行判断,再进行操作,这样子会避免报错。
x = 10
# print(x.__dict__) # 报错:'int' object has no attribute '__dict__'
print(getattr(x, '__dict__', None)) # None
obj = 10
if hasattr(obj, '__dict__'):
print(getattr(obj, '__dict__'))
else:
pass
# 无事发生
还有些类型是不被允许再添加属性进去的:
x = 10
setattr(x, '混入其中', 'niub') # 'int' object has no attribute '混入其中'
反射应用小案例
class QQ:
def put(self):
print('正在发消息')
def get(self):
print('正在收消息')
def interactive(self):
method = input(">>>: ").strip() # method接收的是一个字符串类型
if hasattr(self, method):
getattr(self, method)()
else:
print('输入的指令不存在')
obj = QQ()
obj.interactive()
二、面向对象编程之内置方法
(一)基本概念
-
什么是内置方法?
定义在类内部,以
__开头并以__结尾的方法。特点: 会在某种情况下自动触发执行
-
为何要用内置方法?
为了来帮助使用者高度定制自己的类或对象。
(二)如何使用内置方法
以
__str__与__del__为例
__str__:在打印对象时会自动触发,然后将返回值(==必须是字符串类型==)当做本次打印的结果输出,print功能打印的就是它的返回值。
# 未使用__str__
class People:
def __init__(self, name, age):
self.name = name
self.age = age
obj = People('山炮', 18)
print(obj) # <__main__.People object at 0x0000020ADA933310>
# 使用__str__
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "<姓名:%s | 年龄:%s>" % (self.name, self.age)
obj = People('山炮', 18)
print(obj) # <姓名:山炮 | 年龄:18>
__del__会在对象被删除时自动触发,先执行该方法,再清理对象。
class test:
def __del__(self):
print('清理中...')
obj = test()
# 结果:清理中...
# 当程序只有上面这么多时,程序运行结束后,自动输出了“清理中...”是因为在python程序空间释放时(清理对象),该方法先于清理对象执行。
由于Python自带的垃圾回收机制会自动清理Python程序的资源,所以当一个对象只占用应用程序级资源时,完全没必要为对象定制__del__方法,但在产生一个对象的同时涉及到申请系统资源(比如系统打开的文件、网络连接等)的情况下,关于系统资源的回收,Python的垃圾回收机制便派不上用场了。此时就需要我们为对象定制该方法,用来在对象被删除时自动触发回收系统资源的操作。
举个例子:
class People:
def __init__(self, name, age):
self.name = name
self.age = age
self.x = open('a.txt', mode='w')
# self.x =》 占据的是操作系统资源
def __del__(self):
# 发起系统调用,告诉操作系统回收相关的系统资源
self.x.close()
obj = People('山炮', 18)