反射、内置方法
# 反射
通过 字符串 来操作类或者对象的属性
涉及四个内置函数: hasattr getattr setattr delattr
>>> hasattr
<built-in function hasattr>
1
2
2
# 操作属性
注意, 使用 getattr时候, 必须捕获的到的是 AttributeError 异常, 才能返回getattr设置的第三个参数值!!
就像是 自定义迭代器要raise StopIteration一样, 只有这样for循环才会捕捉到并终止迭代!!
xxx = 1
class Pepole:
country = 'china'
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} is eating!")
p = Pepole('dc')
# -- 本质上是看 p能否对country这个属性进行引用 不局限于判断 "country" in p.__dict__
# 也就是在判断能否通过.访问到某个属性 即p.country是否报错
# 回顾下属性查找规则(命名空间): 自身-类-父类-...-顶级父类object
print(hasattr(p, "country")) # True
print(hasattr(p, "xxx")) # False
# <bound method Pepole.eat of <__main__.Pepole object at 0x7f8adde7e910>>
print(getattr(p, "eat"))
print(p.eat) # <bound method Pepole.eat of <__main__.Pepole object at 0x7f8adde7e910>>
# print(getattr(p, "xxx")) # AttributeError:'Pepole' object has no attribute 'xxx'
print(getattr(p, "xxx", "没有该属性")) # 没有该属性 -- 通常情况下没找到会设置返回值为None
setattr(p, "age", 18) # -- 等同于 p.age = 18
print(p.age) # 18
print(p.__dict__) # {'name': 'dc', 'age': 18}
delattr(p, "name") # -- 等同于 del p.name
print(p.__dict__) # {'age': 18}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 反射简单应用
这个例子很好的诠释了 反射比点语法好的地方!! 因为反射的第二个参数是字符串!!
class Ftp:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def get(self):
print("GET function")
def put(self):
print("PUT function")
def run(self):
while True:
# -- 输入字符串反射到对象具体的方法上面
choice = input(">>>: ").strip()
if hasattr(self, choice):
method = getattr(self, choice)
method()
else:
print("您输入的命令不存在!")
"""
method = getattr(self, choice, None)
if method:
method()
else:
print("不存在")
"""
conn = Ftp("1.1.1.1", 3306)
conn.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 内置方法
自定义内置方法来定制类的功能
以__开头和__结尾的方法在满足某种条件下会自动触发.
# __str__
d = {'x': 1} # -- 即d = dict({'x':1}) 调用dict这个类来完成实例化的过程
print(d) # {'x': 1} -- d是一个对象,本质是一个命名空间,里面存的是一堆数据
"""
像内置数据类型一样,在打印对象时,打印有用的信息出来.而不是打印内存地址.
__str__ 为打印对象定制打印的格式
"""
class People:
def __init__(self, name, age):
self.name = name
self.age = age
# -- 在对象self被打印时,自动触发
# 在顶级父类object中有__str__方法,返回的是self的内存地址
# 我们应该重写该方法,在该方法内采集与对象self有关的信息,然后拼成字符串返回
def __str__(self):
return "name:%s,age:%s" % (self.name, self.age)
obj = People('dc', 18)
# -- 没有__str__方法的时候,打印 <__main__.Foo object at 0x7fef48e8d1f0>
# 有__str__方法后, name:dc,age:18
print(obj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# __del__
__del__
析构方法. 会在对象被删除之前自动触发
应用场景:
该对象不仅仅占用python应用程序的内存空间,还占用其他(eg:操作系统)的资源.
需要在回收该对象时候,使用析构方法将占用的其他资源顺带一起回收了..
__del__会在对象被删除时自动触发.
由于Python自带的垃圾回收机制会自动清理Python程序的资源
所以当一个对象只占用应用程序级资源时,完全没必要为对象定制__del__方法.
但在产生一个对象的同时涉及到申请系统资源(比如系统打开的文件、网络连接等)的情况下
【关于系统资源的回收,Python的垃圾回收机制便派不上用场了?? "这句话好像不严谨"】
需要我们为对象定制该方法,用来在对象被删除时自动触发回收系统资源的操作!!
"""
f = open('a.txt') 可以看作一个类实例化得到了f对象
f对象占用两方面的资源:
1> f是python的一个变量名,占用python应用程序的空间
2> f还对应操作系统打开的a.txt文件
申请资源后,需要回收资源:
1> 针对变量的回收,python有gc机制,能回收变量对应的值
2> 操作系统方面的资源 在f变量被回收之前,通过f.close()进行回收
"""
f = open('a.txt')
class People:
def __init__(self, name, age):
self.name = name
self.age = age
self.f = open('a.txt', 'rt', encoding='utf-8')
def __del__(self):
self.f.close()
def __str__(self):
return "name:%s,age:%s" % (self.name, self.age)
# -- obj是python应用程序的资源,没必要考虑回收
# 但是obj里面有属性f,该属性不仅占用python资源,还指向操作系统打开的文件
obj = People('dc', 18)
# -- 方式1> 程序结束,自动回收 命名空间生命周期结束,引用计数为0,回收
# -- 方式2> 程序当中,主动删除对象,使用del解除对象与值的绑定关系,该对象则会被gc机制自动回收
del obj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38