一.继承
1.Python中能够实现单继承与多继承。
单继承:就是子类只有一个直接父类。
多继承:子类有两个及两个以上的直接父类。
2.子类继承父类,子类可以继承父类的相关特征。子类继承了父类的方法,如果在多继承情况下,父类出现同名函数,那么子类继承该函数时,根据继承的顺序进行调用。
3.super()函数,它指代了当前类的父类。我们可以在子类中调用super函数,用来初始化父类。但是使用super()调用父类的构造函数时,只能对多继承中的第一个父类生效。
4.抽象与继承的区别与关系
抽象:指对同一类别事物的相似部分进行抽取。抽象我们认为是对具体化对象的相关行为和属性的泛化过程。
继承:Python中我们通常认为类就是一个抽象的内容。类本身并不能直接执行,需要通过继承,进行对象的实例化,进而获得具体的对象本身,才能执行相关的功能。
也就是说继承其实是抽象的具体化过程。
5.多继承中,当一个子类继承多个父类时,我们需要如下声明:
class SubClass(A,B):
其中,A、B是SubClass的父类。那么,如果我们分为两种个情况:
第一,子类中没有显式的定义__init__(),那么在实例化子类时调用其父类的构造函数。如果有多个类,都定义了__init()函数,那么它会调用第一个具有__init__()函数的父类。
第二,子类中显式的定义理论__init_(),那么实例化子类时不再调用父类的构造函数。此时,如果我们要调用父类的构造函数,有两种方法。
(1)在子类的构造函数中,显式的调用对应父类的构造函数,例如:
A.__init__()
(2)采用super()函数,super().__init__()或者super(子类,self).__init__()
但是如果遇到其多个父类,他们的构造函数同名时,我们根据他们在MRO算法中的顺序,分别调用他们,例如:
可以使用super()函数指定多个父类中的同名方法。
class A(object):
def aa(self, x):
self._x = x
print('A',x)
class B(object):
def aa(self, y):
self._y = y
print('B',y)
class C(object):
def aa(self, z):
self._z = z
print('C',z)
class D(A,B,C):
def aa(self,x,y,z):
super(D,self).aa(x)#调用父类A中的方法
super(A,self).aa(y)#调用父类B中的方法
super(B,self).aa(z)#调用父类C中的方法
obj_d = D()
print(obj_d.aa('x','y','z'))#调用子类中的aa方法
注意,在这里不要看到super就认为是父类,但是在多继承时,实际上super指的是MRO算法排序中的下一个类。6.封装
在Python中,我们针对其内部细节进行封装。通常我们将属性定义为私有类型,意味着在类外无法直接访问。可以通过相关的方法对其进行调用。
私有的成员变量和方法,都需要在类内进行定义。所有在类外实现的定义都是公有的,代码如下:
class A:
__N = 'hello' # 此处是一个私有的类变量
def __init__(self):
self.__name = 'tom'
def __method(self):
print('我是私有函数')
def show(self):
self.__method()
print(self.__name)
a = A()
A.__age = 10 # 此处的__age是一个公有的类变量
print(A.__age)
8)property方法
在Python中,我们可以使用property来修饰指定的函数,被修饰后的函数,在类外可以通过对象调用(类似调用变量)
原理:当类被载入时,首先会载入类的名称和被property修饰的名字到类的命名空间中;然后在类对象进行实例化时,Python解析器会查找是否存在property修饰的名字,如果存在,就不在实例化对象是为其分配内存空间。
class Person:
def __init__(self, name, height, weight):
self.__name = name
self.__height = height
self.__weight = weight
@property
def bmi(self):
return self.__weight / self.__height**2
p = Person()
print(p.bmi) # 此处调用的bmi是Person类中的函数。
9)classmethod方法
在Python中,我们通常使用classmethod用来修饰一个方法,这个方法就被称为类方法,类方法通常用来操作类变量。类方法和类变量一样,都需要通过类名来调用。
class Goods:
__discount = 0.8
def __init__(self, name, price):
self.__name = name
self.__price = price
@classmethod
def change_discount(cls, new_discount): #此处传递的默认参数不是对象参数self,而是类参数cls
cls.__discount = new_discount
@classmethod
def get_discount(cls):
return cls.__discount
goods = Goods('apple', 6)
print(Goods.get_discount())
Goods.change_discount(0.9)
print(Goods.get_discount())
10.staticmethod方法
在Python中,我们使用staticmethod来修饰函数,该函数被称为静态方法,首先,静态方法不需要使用对象参数或类参数作为默认参数。其次,静态方法通常只能调用类变量,而不可以使用成员变量。最后,在类外进行调用时,可以使用类名来调用。
实例方法、类方法与静态方法的区别
实例方法:第一个参数必须是实例对象(self),通过它来传递实例的属性和方法,只能由实例对象来调用。
类方法:使用装饰器@classmethod,第一个参数必须是类对象(cls),通过它来传递类的属性和方法。可以通过实例对象或类对象来调用,通常使用类对象调用。
静态方法:使用装饰器@staticmethod,没有默认参数(self和cls),但是方法体中不能使用类或实例对象的任何属性和方法。可以通过实例对象或类对象进行调用。
1、类方法和静态方法都可以通过对象实例或者类名来调用。
2、类方法主要针对的是类,可以通过继承和重新定义
3、静态方法不能被继承,无法被重写,可以被认为是全局函数。静态方法在使用时完全不会用到对象实例本身。静态方法逻辑上属于类,但是不会涉及到类中的属性和方法的操作。11)方法重写
概念:当子类继承父类时,子类会继承父类所有的公有方法。如果在子类中重写定义一个与父类中同名的方法,我们成为方法的重写(覆盖)。方法重写只需要名字相同即可,与方法的参数个数、顺序无关
二.多态与鸭子类型
多态:多态一般都是通过继承来实现的,也就是根据不同的对象形态来进行区分。我们在Python中,使用多态时,意味着在编码时变量并不知道所引用的对象具体内容,只有在程序运行时相关对象被实例化后,才能够确定。
鸭子类型:在Python中,因为其自身特性并没有对多态进行明确的规定,可以创建一个功能相似,但与原对象无关的、全新对象,来实现程序的松耦合。
我们通常在开发中,采用接口的方式来实现。我们认为在一组功能相似,但没有继承关系的对象中,采用接口方式。
class Payment:
def payment(self, money):
pass
class Weixinpay(Payment):
def payment(self, money):
print('微信支付了{0}元'.format(money))
class Alipay(Payment):
def payment(self, money):
print('支付宝支付了{0}元'.format(money))
class My(Payment):
def payment(self, money):
print('支付了{0}元'.format(money))
此例,我们可以看到:
第一,通过继承,实现了多态,即三种支付方式不同的形态
第二,我们观察到,微信支付、支付宝、个人支付,三者之间没有任何继承关系,但是都具有相同的支付功能,我们可以认为这种形式就是鸭子类型
第三,因为三种支付方式,分别继承了接口类Payment,都重新了相关的支付方法payment()