反射的定义
python中的反射是去命名空间中寻找字符串形式的名字所指向的内存地址,对该内存地址进行获取、添加、删除、判断等操作。反射是一种基于字符串的事件驱动!它的功能非常强大,熟练掌握后可以在很多场景用来简化代码。
getattr
参数:
参数有二个:第一参数用来指定命名空间;第二参数是字符串格式的名字,若名字不存在会报错。
作用:
返回指定命名空间内字符串格式的名字所指向的内存地址(该地址存储的若是字符串则可将其当字符串用,若是代码块则可调用它)。
案例:
class Animal:
kind = '动物'
def __init__(self, name):
self.name = name
def eat(self):
print(f'{self.name}正在进食!')
white_cat = Animal('白猫')
print(getattr(white_cat, 'name'))
print(getattr(Animal, 'kind'))
getattr(white_cat, 'eat')()
print(getattr(Animal, 'name'))
out:
白猫
动物
白猫正在进食!
AttributeError: type object 'Animal' has no attribute 'name'
讲解:
上述案例中定义了Animal类并创建了它的实例white_cat。
print(getattr(white_cat, ‘name’))语句等价于print(white_cat.name);
getattr(white_cat, ‘eat’)()语句等价于white_cat.eat()。
print(getattr(Animal, ‘name’))获取Animal命名空间中的’name’时报错了,因为Animal命名空间中没有’name’这个名字。
hasattr
参数:
参数有二个:第一参数用来指定命名空间;第二参数是字符串格式的名字。
作用:
判断指定命名空间中有没有那个名字,有则返回True,没有则返回False。
案例:
class Animal:
kind = '动物'
def __init__(self, name):
self.name = name
def eat(self):
print(f'{self.name}正在进食!')
white_cat = Animal('白猫')
print(hasattr(white_cat, 'eat'))
print(hasattr(Animal, 'name'))
out:
True
False
讲解:
上述案例中定义了Animal类并创建了它的实例white_cat。
print(hasattr(white_cat, ‘eat’))语句是判断实例white_cat的命名空间中是否有eat这个名字,判断结果是True,表示有这个名字。
print(hasattr(Animal, ‘name’))语句是判断类Animal的命名空间中是否有name这个名字,判断结果是False,表示没有这个名字。
callable
参数:
参数有一个:参数是内存地址(可以是名字指向的或getattr返回的)。
作用:
判断内存地址中存放的是不是代码块,是则返回True,不是则返回False。
案例:
class Animal:
kind = '动物'
def __init__(self, name):
self.name = name
def eat(self):
print(f'{self.name}正在进食!')
white_cat = Animal('白猫')
print(callable(getattr(white_cat, 'eat')))
print(callable(getattr(Animal, 'kind')))
out:
True
False
讲解:
上述案例中定义了Animal类并创建了它的实例white_cat。
print(callable(getattr(white_cat, ‘eat’)))语句是打印判断实例white_cat的命名空间中eat指向的是不是代码块。判断结果是True,表示是代码块。
print(callable(getattr(Animal, ‘kind’)))语句是打印判断类Animal的命名空间中kind指向的是不是代码块。判断结果是False,表示不是代码块。
setattr
参数:
参数有三个:第一参数是命名空间;第二参数是名字;第三参数是代码块所在的内存地址(可以是名字或getattr返回的)。
作用:
该函数的作用是给指定命名空间(第一参数)添加指定名字(第二参数)的代码块(第三参数),返回值是None。
案例:
class Animal:
kind = '动物'
def __init__(self, name):
self.name = name
def eat(self):
print(f'{self.name}正在进食!')
white_cat = Animal('白猫')
def work(self):
print(f'{self.name}正在干活!')
setattr(Animal, 'work', work)
white_cat.work()
out:
白猫正在干活!
讲解:
使用该函数时要注意以下几点:
setattr(Animal, ‘work’, work)是给Animal类绑定work方法,这样Animal的所有实例均可调用work方法。
setattr(white_cat, ‘work’, work)是给实例white_cat绑定work方法,调用时要把实例本身作为第一参数,例如:white_cat.work(white_cat)。
另外给实例绑定方法后该方法只存在于实例的命名空间,Animal类的其他实例不能调用!
delattr
参数:
参数有二个:第一参数用来指定命名空间;第二参数是字符串格式的名字,若该名字不存在会报错。
作用:
该函数的作用是查找指定命名空间内字符串格式的名字,若找到则将其删除并释放资源,若找不到则报错。返回值是None。
案例:
class Animal:
kind = '动物'
def __init__(self, name):
self.name = name
def eat(self):
print(f'{self.name}正在进食!')
white_cat = Animal('白猫')
delattr(white_cat, 'name')
delattr(Animal, 'eat')
print(white_cat.name)
print(Animal.eat)
out:
AttributeError: 'Animal' object has no attribute 'name'
讲解:
请注意delattr函数只在指定的命名空间中找名字,不会按类的继承顺序去本类、父类、祖父类等命名空间找名字。这和调用实例的属性或方法时不一样。
调用时实例的属性或方法时若实例自身的命名空间中没有这个名字则会按类的继承顺序去本类、父类、祖父类等命名空间找名字。