python基础整理笔记(八)
一. python反射的方式来调用方法属性
反射主要指的就是hasattr、getattr、setattr、delattr这四个函数,作用分别是检查是否含有某成员、获取成员、设置成员、删除成员。
此外还有一个 __import__方法,用来与getattr可以实现一些根据字符串来动态的获取模块、方法、属性的方法,示例如下:
1 # 普通的import模块方法: 2 import AA as aa 3 4 # 使用__import__的等效方法: 5 aa = __import__('AA') 6 7 # 再通过getattr,可以获取到 aa模块里定义的 aaClass 8 aaClass = getattr(aa, 'aaClass') 9 # 这样可以正常的实例化 10 aaObj = aaClass ('abc') 11 12 # 再通过getattr可以把示例里面的方法也用出来,属性也取出来 13 func = getattr(aaObj , 'aaFuncton') 14 func() 15 print(getattr(aaClass, 'aaAttr'))
二. python类的一些注意点
1. 定义在子类里的属性和方法(注意不是子类重写的,而是特有的,父类没有的),在父类的方法里面我们也可以调用!但是如果是父类的实例,去调用了使用了这种子类属性的方法,是会报错的!这种实现的作用,是将父类当做类似其他语言中的纯抽象类或者接口的实现,父类里是不会调用这样的方法的,或者实例化父类的。使用这种方式,可以降低代码的重复,将更多的共同抽象到父类里面去。
示例如下:
1 class Father(object): 2 def __init__(self): 3 self.aa = 1 4 self.bb = 2 5 6 def show_bb(self): 7 print self.bb 8 9 def show_cc(self): 10 print self.cc 11 12 13 class Son(Father): 14 def __init__(self): 15 super(Son, self).__init__() 16 self.cc = 3 17 18 s1 = Son() 19 s1.show_bb() 20 s1.show_cc()
如图所示,这里调用 show_bb()和show_cc()都是合法的,尽管show_cc()是父类的方法,而且父类没定义cc这个属性。这是因为这里的self是子类自己的s1这个实例。
但是如果要实例化父类并调用show_cc就会出错如下:
2. python中类有个特殊的方法 __call__,它的作用是实现了这个方法,那么在调用实例的后面直接加一个(),就会执行这个__call__方法。
示例如下:
1 class Father(object): 2 def __init__(self): 3 self.aa = 1 4 self.bb = 2 5 6 7 def show_bb(self): 8 print self.bb 9 10 def show_cc(self): 11 print self.cc 12 13 14 class Son(Father): 15 def __init__(self): 16 super(Son, self).__init__() 17 self.cc = 3 18 19 def __call__(self, *args, **kwargs): 20 self.show_bb() 21 self.show_cc() 22 23 s1 = Son() 24 s1()
用这种方法,能够在一些情况下让代码显得更加简洁清晰。
3. python中的类,还有个特殊方法__iter__,实现了这个方法,就可以直接对这个类的实例进行迭代,示例如下:
1 class TestIter(object): 2 def __init__(self): 3 self.iter_lst = [1, 3, 4, 5] 4 5 def __iter__(self): 6 for i in self.iter_lst: 7 yield i 8 9 t1 = TestIter() 10 11 for i in t1: 12 print i
4. property, XXX.setter装饰器
在python的类中,还有两个特殊的装饰器,一个叫property,一个叫XXX.setter,
前者作用是能像调用属性一样的调用一个方法,后者作用是能像给属性设值一样调用一个方法...XXX是这个方法的名称。通过这两个装饰器,一个类里面就可以有两个同名的方法,分别负责存取一个像属性的值。
示例如下:
1 class TestPP(object): 2 def __init__(self): 3 self.aa = 1 4 self.bb = 2 5 6 @property 7 def aa_bb(self): 8 return self.load_aa_bb() 9 10 @aa_bb.setter 11 def aa_bb(self, new_value): 12 self.save_aa_bb(new_value) 13 14 @staticmethod 15 def save_aa_bb(aa_bb): 16 with open('aa_bb', 'wb') as fp: 17 fp.write(aa_bb) 18 19 def load_aa_bb(self): 20 if os.path.exists('aa_bb'): 21 with open('aa_bb', 'rb') as fp: 22 return fp.read() 23 else: 24 init_value = '%s_%s' % (self.aa, self.bb) 25 self.save_aa_bb(init_value) 26 return init_value 27 28 pp = TestPP() 29 print(pp.aa_bb) 30 pp.aa_bb = '3333' 31 print(pp.aa_bb)
这种方式往往用于对一个外部存储的属性(比如存在数据库,json文件中等),进行获取和赋值时候使用,可以使得代码变得简洁。