反射
一、反射的概念
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
二、反射的四种方法
只要能通过 xx.xx 调用到的东西都可以用反射,如:
# 类.属性 # 类.方法 # 对象.属性 # 对象.方法 # 内置模块.属性 # 自定义模块.属性 # 模块.类
①hasattr
此方法是用来检查一个对象有没有一个XX,格式为:hansattr(对象,‘XX‘),注意,第二个参数是一个字符串类型的。返回一个布尔值,如下:
1 class Person: 2 kind = '人类' 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 self.changdu = 28 7 def func(self): 8 print('func.....') 9 p = Person('fuyong',18) 10 11 print(hasattr(p,'name')) #True 12 print(hasattr(p,'func')) #True 13 print(hasattr(Person,'kind')) #True 14 print(hasattr(Person,'func')) #True
②getattr
此方法是用来获取一个对象的XX,XX是字符串类型,它可以是类的属性,可以对象是属性及方法,可以是模块的类,等等……
最好搭配hasattr方法使用,判断它有此方法或者对象的时候才获取,以免找不到报错,也可以指定找不到的默认值。格式为getattr(对象,XX,默认值),如下:
1 class Person: 2 kind = '人类' 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 self.changdu = 28 7 def func(self): 8 print('func.....') 9 p = Person('fuyong',18) 10 11 ret = getattr(p,'func',None) 12 if ret: 13 ret() #func..... 14 15 ret = getattr(p,'funcxxx','没有此方法') 16 print(ret) #没有此方法 17 18 if hasattr(p,'func'): 19 getattr(p,'func')() #func.....
③setattr
此方法用来设置一个对象的属性,格式为setattr(对象,属性名,属性值) ,如下:
1 class Person: 2 kind = '人类' 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 self.changdu = 28 7 def func(self): 8 print('func.....') 9 p = Person('fuyong',18) 10 11 print(p.age) #18 12 setattr(p,'age',19) 13 print(p.age) #19 14
④delattr
此方法是用来删除一个对象的属性,格式为delattr(对象,XXX) ,如下:
1 class Person: 2 kind = '人类' 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 self.changdu = 28 7 def func(self): 8 print('func.....') 9 p = Person('fuyong',18) 10 11 print(p.age) #18 12 delattr(p,'age') 13 print(p.age) #报错:AttributeError: 'Person' object has no attribute 'age'
三、类的内置方法
① __init__
此方法在类被实例化的时候被自动调用
② __str__和__repr__
__str__( )方法在三种情况下被自动调用
△ str(对象名)
△ print(对象名)
△ '%s'%对象名
如下:
1 class Person: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def __str__(self): 6 return '他是一个名叫%s的帅哥'%self.name 7 8 p = Person('fuyong',18) 9 print(str(p)) #他是一个名叫fuyong的帅哥 10 print(p) #他是一个名叫fuyong的帅哥 11 print('%s'%p) #他是一个名叫fuyong的帅哥
__repr__方法在以下三种情况下被调用:
△ repr(对象名)
△ '%r'%对象名
△ 当类没有__str__方法又被调用__str__方法的时候被调用
如下:
1 class Person: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def __repr__(self): 6 return '他是一个名叫%s的帅哥'%self.name 7 8 p = Person('fuyong',18) 9 print(repr(p)) 10 print('%r'%p) 11 print(str(p)) 12 print(p) 13 #打印结果如下 14 # 他是一个名叫fuyong的帅哥 15 # 他是一个名叫fuyong的帅哥 16 # 他是一个名叫fuyong的帅哥 17 # 他是一个名叫fuyong的帅哥
③ __del__
此方法会在对象被释放的时候被自动调用(一种情况是对象被删除,一种情况是程序执行完了被Python解释器释放),如下:
1 class Person: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def __del__(self): 6 print('程序执行完了') 7 8 p = Person('fuyong',18) 9 10 #程序执行完了
④ __call__
此方法会在对象后面加括号的时候被自动调用,如下:
1 class Person: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def __call__(self): 6 print('你在对象名后加了括号(类似一个函数)') 7 p = Person('fuyong',18) 8 p() 9 #你在对象名后加了括号(类似一个函数)
⑤ __len__
此方法在调用len(对象)的时候被执行,如下:
1 class Person: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 self.changdu = 28 6 def __len__(self): 7 return self.changdu 8 p = Person('fuyong',18) 9 print(len(p)) #28
⑥ __new__
此方法是在实例化一个对象的时候回自动触发(在__init__函数之前)。如下:
1 class Person: 2 def __init__(self,name): 3 self.name = name 4 print('调用__init__函数........') 5 6 def __new__(cls, *args, **kwargs): 7 print('调用__new__函数.........') 8 return object.__new__(Person) 9 10 p = Person('付勇') 11 print(p.name) 12 13 #调用__new__函数......... 14 # 调用__init__函数........ 15 # 付勇
利用__new__方法实现单例模式:
1 class Person: 2 _obj = None 3 def __init__(self,name): 4 self.name = name 5 6 def __new__(cls, *args, **kwargs): 7 if cls._obj: 8 return _obj 9 else: 10 _obj = object.__new__(Person) 11 12 p1 = Person('付勇') 13 p2 = Person('小明') 14 print(p1 is p2)
⑦ __hash__
此方法在has(对象)的时候被调用,如下:
1 class Person: 2 _obj = None 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 7 def __hash__(self): 8 return hash(self.name)+hash(self.age) 9 10 p1 = Person('付勇',18) 11 p2 = Person('付勇',19) 12 print(hash(p1) == hash(p2)) #False
⑧__eq__
此方法在比较两个对象的时候被调用,如:obj1 == obj2 或者 如下:
1 class Person: 2 _obj = None 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 7 def __eq__(self, other): 8 if self.__dict__ == other.__dict__: 9 return True 10 else: 11 return False 12 13 p1 = Person('付勇',18) 14 p2 = Person('付勇',18) 15 print(p1 == p2) #True
⑨ __getitem__\__setitem__\__delitem__
一旦一个类中定义了这三种内置方法,操作类的属性的时候就可以像操作字典一样,如:
obj [属性] ----> __getitem__ obj [属性] = 属性值 ----> __setitem__ del obj [属性] ----> __delitem__
实例如下:
1 class Person: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 6 def __getitem__(self, item): 7 return self.__dict__[item] 8 9 def __setitem__(self, key, value): 10 self.__dict__[key] = value 11 12 def __delitem__(self,key): 13 del self.__dict__[key] 14 15 p = Person('付勇',18) 16 17 print(p['name']) #付勇 18 19 p['age'] = 19 20 print(p['age']) #19 21 22 del p['age'] 23 24 print(p['age']) #因为age属性已被删除,所以会报错!KeyError: 'age'