博客地址:http://lizhenliang.blog.51cto.com and https://yq.aliyun.com/u/lizhenliang
QQ群:323779636(Shell/Python运维开发群)
6.7 类的继承 子类继承父类,子类将继承父类的所有方法和属性,提高代码重用。 1)简单继承 #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__(self, name=None): self.name = name def func(self, age): return "Name: %s, Age: %s" %(self.name, age) class Child(Parent): pass mc = Child('xiaoming') print mc.func('22') print mc.name # python test.py Name: xiaoming, Age: 22 xiaoming 2)子类实例初始化 如果子类重写了构造函数,那么父类的构造函数将不会执行: #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__(self): self.name_a = "xiaoming" def funcA(self): return "function A: %s" % self.name_a class Child(Parent): def __init__(self): self.name_b = "zhangsan" def funcB(self): return "function B: %s" % self.name_b mc = Child() print mc.name_b print mc.funcB() print mc.funcA() # python test.py zhangsan function B: zhangsan Traceback (most recent call last): File "test2.py", line 17, in <module> print mc.funcA() File "test2.py", line 7, in funcA return "function A: %s" % self.name_a AttributeError: Child instance has no attribute 'name_a' 抛出错误,提示调用funcA()函数时,没有找到name_a属性,也就说明了父类的构造函数并没有执行。 如果想解决这个问题,可通过下面两种方法: 方法1:调用父类构造函数 #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__(self): self.name_a = "xiaoming" def funcA(self): return "function A: %s" % self.name_a class Child(Parent): def __init__(self): Parent.__init__(self) self.name_b = "zhangsan" def funcB(self): return "function B: %s" % self.name_b mc = Child() print mc.name_b print mc.funcB() print mc.funcA() # python test.py zhangsan function B: zhangsan function A: xiaoming 方法2:使用supper()函数继承 #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(object): def __init__(self): self.name_a = "xiaoming" def funcA(self): return "function A: %s" % self.name_a class Child(Parent): def __init__(self): super(Child, self).__init__() self.name_b = "zhangsan" def funcB(self): return "function B: %s" % self.name_b mc = Child() print mc.name_b print mc.funcB() print mc.funcA() # python test.py zhangsan function B: zhangsan function A: xiaoming 6.8 多重继承 每个类可以拥有多个父类,如果调用的属性或方法在子类中没有,就会从父类中查找。多重继承中,是依次按顺序执行。 类简单的继承: #!/usr/bin/python # -*- coding: utf-8 -*- class A: def __init__(self): self.var1 = "var1" self.var2 = "var2" def a(self): print "a..." class B: def b(self): print "b..." class C(A,B): pass c = C() c.a() c.b() print c.var1 print c.var2 # python test.py a... b... var1 var2 类C继承了A和B的属性和方法,就可以像使用父类一样使用它。 子类扩展方法,直接在子类中定义即可: #!/usr/bin/python # -*- coding: utf-8 -*- class A: def __init__(self): self.var1 = "var1" self.var2 = "var2" def a(self): print "a..." class B: def b(self): print "b..." class C(A,B): def test(self): print "test..." c = C() c.a() c.b() c.test() print c.var1 print c.var2 # python test.py a... b... test... var1 var2 在这说明下经典类和新式类。 经典类:默认没有父类,也就是没继承类。 新式类:有继承的类,如果没有,可以继承object。 在Python3中已经默认继承object类。 经典类在多重继承时,采用从左到右深度优先原则匹配,而新式类是采用C3算法(不同于广度优先)进行匹配。两者主要区别在于遍历父类算法不同,具体些请在网上查资料。 6.9 方法重载 直接定义和父类同名的方法,子类就修改了父类的动作。 #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__(self, name='xiaoming'): self.name = name def func(self, age): return "Name: %s, Age: %s" %(self.name, age) class Child(Parent): def func(self, age=22): return "Name: %s, Age: %s" %(self.name, age) mc = Child() print mc.func() # python test.py Name: xiaoming, Age: 22 6.10 修改父类方法 在方法重载中调用父类的方法,实现添加功能。 #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__(self, name='xiaoming'): self.name = name def func(self, age): return "Name: %s, Age: %s" %(self.name, age) class Child(Parent): def func(self, age): print "------" print Parent.func(self, age) # 调用父类方法 print "------" mc = Child() mc.func('22') # python test.py ------ Name: xiaoming, Age: 22 ------ 还有一种方式通过super函数调用父类方法: #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(): def __init__(self, name='xiaoming'): self.name = name def func(self, age): return "Name: %s, Age: %s" %(self.name, age) class Child(Parent): def func(self, age): print "------" print super(Child, self).func(age) print "------" mc = Child() mc.func('22') # python test.py ------ Traceback (most recent call last): File "test2.py", line 15, in <module> mc.func('22') File "test2.py", line 11, in func print super(Child, self).func(age) TypeError: must be type, not classobj 抛出错误,因为super继承只能用于新式类,用于经典类就会报错。 那我们就让父类继承object就可以使用super函数了: #!/usr/bin/python # -*- coding: utf-8 -*- class Parent(object): def __init__(self, name='xiaoming'): self.name = name def func(self, age): return "Name: %s, Age: %s" %(self.name, age) class Child(Parent): def func(self, age): print "------" print super(Child, self).func(age) # 调用父类方法。在Python3中super参数可不用写。 print "------" mc = Child() mc.func('22') # python test.py ------ Name: xiaoming, Age: 22 ------ 6.11 属性访问的特殊方法 有四个可对类对象增删改查的内建函数,分别是getattr()、hasattr()、setattr()、delattr()。 6.11.1 getattr() 返回一个对象属性或方法。 >>> class A: ... def __init__(self): ... self.name = 'xiaoming' ... def method(self): ... print "method..." ... >>> c = A() >>> getattr(c, 'name', 'Not find name!') 'xiaoming' >>> getattr(c, 'namea', 'Not find name!') >>> getattr(c, 'method', 'Not find method!') <bound method A.method of <__main__.A instance at 0x93fa70>> >>> getattr(c, 'methoda', 'Not find method!') 'Not find method!' 6.11.2 hasattr() 判断一个对象是否具有属性或方法。返回一个布尔值。 >>> hasattr(c, 'name') True >>> hasattr(c, 'namea') False >>> hasattr(c, 'method') True >>> hasattr(c, 'methoda') False 6.11.3 setattr() 给对象属性重新赋值或添加。如果属性不存在则添加,否则重新赋值。 >>> hasattr(c, 'age') False >>> setattr(c, 'age', 22) >>> c.age 22 >>> hasattr(c, 'age') True 6.11.4 delattr() 删除对象属性。 >>> delattr(c, 'age') >>> hasattr(c, 'age') False 6.12 类装饰器 与函数装饰器类似,不同的是类要当做函数一样调用: #!/usr/bin/python # -*- coding: utf-8 -*- class Deco: def __init__(self, func): self._func = func self._func_name = func.__name__ def __call__(self): return self._func(), self._func_name @Deco def f1(): return "Hello world!" print f1() # python test.py ('Hello world!', 'f1') 6.13 类内置装饰器 下面介绍类函数装饰器,在实际开发中,感觉不是很常用。 6.10.1 @property @property属性装饰器的基本功能是把类中的方法当做属性来访问。 在没使用属性装饰器时,类方法是这样被调用的: >>> class A: ... def __init__(self, a, b): ... self.a = a ... self.b = b ... def func(self): ... print self.a + self.b ... >>> c = A(2,2) >>> c.func() 4 >>> c.func <bound method A.func of <__main__.A instance at 0x7f6d962b1878>> 使用属性装饰器就可以像属性那样访问了: >>> class A: ... def __init__(self, a, b): ... self.a = a ... self.b = b ... @property ... def func(self): ... print self.a + self.b ... >>> c = A(2,2) >>> c.func 4 >>> c.func() 4 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'NoneType' object is not callable 6.10.2 @staticmethod @staticmethod是静态方法装饰器,可以通过类对象访问,也可以通过实例化后类对象实例访问。 实例方法的第一个参数是self,表示是该类的一个实例,称为类对象实例。 而使用静态方法装饰器,第一个参数就不用传入实例本身(self),那么这个方法当做类对象,由Python自身处理。 看看普通方法的用法: >>> class A: ... def staticMethod(self): ... print "not static method..." ... >>> c = A() >>> c.staticMethod() not static method... 使用静态方法则是这么用: >>> class A: ... @staticmethod ... def staticMethod(): ... print "static method..." ... >>> A.staticMethod() # 可以通过类调用静态方法 static method... >>> c = A() >>> c.staticMethod() # 还可以使用普通方法调用 static method... 静态方法和普通的非类方法作用一样,只不过命名空间是在类里面,必须通过类来调用。一般与类相关的操作使用静态方法。 6.10.3 @classmethod @classmethod是类方法装饰器, 与静态方法装饰器类似,也可以通过类对象访问。主要区别在于类方法的第一个参数要传入类对象(cls)。 >>> class A: ... @classmethod ... def classMethod(cls): ... print "class method..." ... print cls.__name__ ... >>> A.classMethod() class method... A 6.14 __call__方法 可以让类中的方法像函数一样调用。 >>> class A: ... def __call__(self, x): ... print "call..." ... print x ... >>> c = A() >>> c(123) call... 123 >>> class A: ... def __call__(self, *args, **kwargs): ... print args ... print kwargs ... >>> c = A() >>> c(1,2,3,a=1,b=2,c=3) (1, 2, 3) {'a': 1, 'c': 3, 'b': 2}