一、上节补充
1、静态属性
静态属性 : 类的属性,所有的对象共享这个变量
如果用对象名去修改类的静态属性:在对象的空间中又创建了一个属性,而不能修改类中属性的值
操作静态属性应该用类名来操作
例1:请你写一个类,能够统计一共实例化了多少个对象?
class Foo: count = 0 def __init__(self): Foo.count += 1 f1 = Foo() print(f1.count) # 1 f2 = Foo() f3 = Foo() f4 = Foo() f5 = Foo() print(f1.count) # 5 print(f5.count) # 5 print(Foo.count) # 5
结论:当类中的属性发生改变的时候,对象中没有同名的属性、方法的时候,对象使用属性名会跟着类中的变量走
例二:(类的静态属性为可变数据类型,对象也能引用并修改)
class Foo: count = [0] f1 = Foo() f1.count[0] += 1 # 静态属性的修改 1 print(f1.count[0]) # 对象引用类的静态属性 1 print(Foo.count[0]) # 类修改后 也是 1 f1.count = [2] # 对象新增 2 print(f1.count) # 2 print(Foo.count) # 类不变 1
结论:
1,类的静态属性是可变数据类型时,对象可以引用并修改
2,只要对象的某个属性被直接赋值,那么一定是对象的命名空间发生变化
3,只要是静态变量,就用类名操作
(面向对象的三大特性:继承、多态、封装,这里先说一下继承)
二、继承(提高代码的重用性,规范性)
(C语言没有面向对象,而java和C#只有单继承没有多继承(但是有接口),
python和C++有单继承也有多继承(python原本并没有接口,但是有些人为python开发了接口模块,所以在python中,
需要用接口的时候要安装特定的模块))
2-1单继承:
1,语法:
class A:
pass
class B(A):
pass
这就是单继承:
A就叫:父类/超类/基类
B就叫:子类/派生类
2,继承与重用:子类可以使用父类中的变量和方法
下面看个例子了解一下:
我们都知道猫有自己的名字和吃的粮食,还有猫会喝水吃东西,抓老鼠等,
狗也有自己的名字和吃的粮食,狗也会喝水吃东西,狗还能看家等。
因此构建出来的类如下:
class Cat(): def __init__(self,name,food): self.name = name self.food = food def eat(self): print(‘吃猫粮‘) def drink(self): print(‘喝水‘) def catch_mouse(self): print(‘抓老鼠‘) class Dog(): def __init__(self,name,food): self.name = name self.food = food def eat(self): print(‘吃狗粮‘) def drink(self): print(‘喝水‘) def look_after_house(self): print(‘看家‘) xiaomao = Cat(‘啊猫‘,‘猫粮‘) print(xiaomao.name) #啊猫 xiaomao.eat() #吃猫粮 xiaomao.catch_mouse() #抓老鼠 xiaogou = Dog(‘啊狗‘,‘狗粮‘) print(xiaogou.name) #啊狗 xiaogou.eat() #吃狗粮 xiaogou.look_after_house() #看家
这么一看是不是感觉代码有很多重复的地方,比如初始化名字和食物、吃东西和喝水的方法,
那么怎么样可以节省代码呢?这就要用到继承。
我们先定义一个公共的类Animal,用来存储猫和狗相同的方法和属性。猫类和狗类分别继承Animal类,
就可以继承Animal的属性和方法了。
class Animal: def __init__(self,name,food): self.name = name self.food = food def eat(self): print(‘吃%s‘%(self.food)) def drink(self): print(‘喝水‘) class Cat(Animal): def catch_mouse(self): print(‘抓老鼠‘) class Dog(Animal): def look_after_house(self): print(‘看家‘) xiaomao = Cat(‘啊猫‘,‘猫粮‘) print(xiaomao.name) #啊猫 xiaomao.eat() #吃猫粮 xiaomao.catch_mouse() #抓老鼠 xiaogou = Dog(‘啊狗‘,‘狗粮‘) print(xiaogou.name) #啊狗 xiaogou.eat() #吃狗粮 xiaogou.look_after_house() #看家
这样一来是不是就简化了很多,而且再来一个猪类,只要它也是有这些公共方法,它也能继承Animal类,
一下子就可以节省了很多代码。
其中:
父类/超类/基类 :Animal
子类/派生类 :Cat、Dog
3,继承与派生:
(1)继承:提高代码的重用性,规范代码
(2)派生:子类在父类的基础上又新创建了自己需要的方法和属性
(3)父类有的而子类没有:子类对象直接调用 就会直接执行父类的方法
(4)父类有的而子类也有:1、子类对象调用 直接执行子类中的方法
2、想在子类中使用父类的名字:父类名、super()去调用
例如:
class Animal: def __init__(self, name, food): self.name = name self.food = food def eat(self): print(‘吃%s‘ % (self.food)) def drink(self): print(‘喝水‘) class Cat(Animal): # Animal的派生类 def __init__(self, name, food, eye_color): self.eye_color = eye_color # 派生属性 super().__init__(name, food) # Animal.__init__(self,name,food) 跟上一句super()都是调用父类的方法 # 不同的是super()不需要传self,而直接用父类名.方法(),需要传self def catch_mouse(self): # 派生方法 print(‘抓老鼠‘) def eat(self): # 不仅执行了父类中的基础功能,还完成了特殊的功能 Animal.eat(self) # super().eat() self.weight = 10 class Dog(Animal): def look_after_house(self): print(‘看家‘) def eat(self): # Animal.eat(self) super().eat() self.drink() # 吃完东西调用父类喝水的方法 xiaomao = Cat(‘阿猫‘, ‘猫粮‘, ‘绿色‘) print(xiaomao.eye_color) # 绿色 print(xiaomao.food) #猫粮 xiaomao.catch_mouse() #抓老鼠 xiaomao.eat() #吃猫粮 print(xiaomao.weight) # 10 xiaogou = Dog(‘啊狗‘, ‘狗粮‘) xiaogou.eat() #吃狗粮 喝水
2-2多继承:
1,语法:
class A:
pass
class B:
pass
class C(A,B):
pass
C既继承了A,又继承了B
2,实例:
# 天鹅:飞 游泳 走路 # 老虎:走路 游泳 # 鹦鹉:飞 说话 走路 class Animal: def __init__(self,name): self.name = name class FlyAnimal(Animal): #会飞的动物类 def fly(self): print(‘%s在飞‘ % self.name) class WalkAnimal(Animal): #会走路的动物类 def walk(self): print(‘%s在走路‘%self.name) class SwimAnimal(Animal): #会游泳的动物类 def swim(self): print(‘%s在游泳‘%self.name) class Tiger(SwimAnimal,WalkAnimal): # 老虎 pass class Swan(SwimAnimal,WalkAnimal,FlyAnimal): # 天鹅 pass class Parrot(FlyAnimal,WalkAnimal): # 鹦鹉 def talk(self): print(‘%s说话了‘%self.name) swan = Swan(‘天鹅‘) swan.fly() # 天鹅在飞 swan.walk() # 天鹅在走路
三、抽象类:抽象类是一个规范,它基本不会实现什么具体的功能,只能被继承,不能被实例化
1、抽象类的作用:规范编程模式
多人开发、复杂的需求、后期的扩展
是一种用来帮助我们完成规范化的手段
2、如何定义抽象类
1,from abc import ABCMeta,abstractmethod
2,在这个类创建的时候指定 metaclass = ABCMeta
3,在你希望子类要实现的方法的上一行加上一个 @abstractmethod装饰器
3、使用抽象类
1,继承这个类
2,必须实现这个类中被@abstractmethod装饰器装饰的方法
4、实例
# 支付功能 from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 模板的功能 @abstractmethod # abstractmethod是一个装饰器,装饰器怎么用?放在函数或者类的上一行 def pay(self): pass # 这样就构建了一个抽象类Payment,并声明了子类必须要实现的方法是 pay(),若子类没有定义pay(),则实例化时会报错 class Alipay(Payment): # 继承了抽象类,就必须实现抽象类中被@abstractmethod装饰器装饰的方法 pay() def pay(self, money): print(‘使用支付宝支付了%s元‘ % money) class Wechatpay(Payment): def pay(self, money): print(‘使用微信支付了%s元‘ % money) class My_pay(Payment): # 这里没有定义pay()方法,那么在实例化的时候机会报错 def fuqian(self,money): print(‘你支付了%s元‘ % money) def pay(obj, money): obj.pay(money) # p = Payment() # 报错 抽象类不能被实例化 a = Alipay() # a.pay(100) pay(a,100) # 使用支付宝支付了100元 we = Wechatpay() # we.pay(200) pay(we,200) # 使用微信支付了200元 my = My_pay() # 报错:类中没有定义抽象类的pay方法 pay(my,300)
四、新式类
1、新式类和经典类:
继承了object的类就是新式类
在py3中默认都继承了object因此所有的类都是新式类
在py2中既有新式类又有经典类
python3.x:
在python3.x版本中所有的类都是新式类
所有的新式类都有一个默认的父类 : object
class Person1:pass
class Person2():pass
class Person3(object):pass
# __bases__方法是查看某个类继承的所有父类
print(Person1.__bases__) # (<class ‘object‘>,)
print(Person2.__bases__) # (<class ‘object‘>,)
print(Person3.__bases__) # (<class ‘object‘>,)
python 2.7:
经典类和新式类并存
class Student:pass # 经典类
class Student(object):pass # 新式类
class Person1:pass # 经典类
class Person2():pass #经典类
class Person3(object):pass #新式类
2、多继承的顺序(在新式类和经典类之间的区别)
新式类
所有的多继承关系寻找方法的顺序 :遵循广度优先算法
继承object
类名.mro() # (返回一个类的寻找顺序(继承顺序)的列表)
super : super不是单纯的找父类,而是遵循mro顺序的
经典类
python2.x
不主动继承object
经典类在找父类中方法的过程中遵循:深度优先算法
不提供mro方法和super
2-1、新式类中
class A: def func(self): print(‘A‘) class B(A): def func(self): super().func() print(‘B‘) class C(A): def func(self): super().func() print(‘C‘) class D(B,C): def func(self): super().func() print(‘D‘) print(D.mro()) # [<class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>] D().func() # A C B D
class A: pass class B(A): pass class C(A): pass class D(B): pass class E(C): pass class F(D,E): pass print(F.mro()) 结果: # [<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>,
<class ‘__main__.A‘>, <class ‘object‘>]