继承
什么是继承
所谓继承指提供了同一类对象共性的处理方法,子类继承父类共性的东西。 这样有利于代码的复用性,即子类拥有父类的方法。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。
继承可以想象成什么是什么的关系
python中类的继承分为:单继承和多继承
class Parent1: # 父类1 pass class Parent2: #父类2 pass class Son1(Parent1): #单继承,基类是ParentClass1,派生类是Son1 pass class Son2(Parent1,Parent2): #多继承,父类是Parent1和Parent2,派生类是Son2 pass
查看继承
>>> Son1.__bases__ #__base__只查看从左到右继承的第一个父类,__bases__则是查看所有继承的父类 (<class '__main__.Parent1'>,) >>> Son2.__bases__ (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
如果没有指定基类,python的类会默认继承object类,object是所有python类的基类
>>> Parent1.__bases__
(<class 'object'>,)
# class Animal:
# def __init__(self,name,eat,drink,push,shit):
# self.name=name
# self.eat= eat
# self.drink= drink
# self.push= push
# self.shit= shit
# class Dog(Animal):
# def cry(self):
# print('%s汪汪汪'%self.name) #在子类中可以使用父类继承的name
# class Cat(Animal):
# def cry(self):
# print('%s喵喵喵'%self.name)
#
# teddy=Dog('泰迪','吃','喝','拉','撒')
# cat1=Cat('加菲','吃','喝','拉','撒')
# print(cat1.name) #调用属性无需添加()
# teddy.cry() #调用方法需要添加(),因为方法本质是函数
加菲
泰迪汪汪汪
在python3中,子类执行父类的方法也可以直接用super方法.
# class Animal: # def __init__(self,name,eat,drink,push,shit): # self.name=name # self.eat= eat # self.drink= drink # self.push= push # self.shit= shit # def run(self): # print('%s running'%self.name) # class Dog(Animal): # def cry(self): # super(Dog,self).run() #super(Dog,self).run() =Animal().run(self)=super().run() 执行父类的方法 # print('%s汪汪汪'%self.name) # class Cat(Animal): # def cry(self):
super().__init() #执行父类的属性 # print('%s喵喵喵'%self.name) # # teddy=Dog('泰迪','吃','喝','拉','撒') # cat1=Cat('附近反','吃','喝','拉','撒') # print(teddy.name) # teddy.cry()
多继承顺序
python3以上(新式类): 广度优先
python2(经典类) :深度优先
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>
#新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类
多态
什么是多态:相同方法调用,执行不同动作
向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。 也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao')
def func(object)
object.talk() #我们可以定义一个统一的接口来使用 三个类都有talk的方法
封装
什么是封装:
所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。。封装是面向对象的特征之一,是对象和类概念的主要特性。 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
私有变量及方法
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A: __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__X=10 #变形为self._A__X ,私有变量 def __foo(self): #变形为_A__foo,私有方法 print('from A') def bar(self): self.__foo() #只有在类内部才可以通过__foo的形式访问到.
对象名_A__foo() #在类外部需要_A__foo()才能在外部访问 (_类__名字)
属性函数(property)
将类方法转换为只读属性
重新实现一个属性的setter和getter方法以及删除方法
假设现在我需要对一个房子的房主姓名进行修改:
class Room(object): name = '土豪' room = Room() print room.name room.name = "房主"
以上方法虽然也可以实现对房主名字的改动,但是这样如果我想把房主改成比如数字2 同样也是可以的,这当然不是我想要看到的,所以就要对其进行限制。
我就在类中引入了两个方法get_name和set_name 分别进行输出和修改
# class Room: # def __init__(self,name,length,width): # self.__name=name # self.__length=length # self.__width=width # def get_name(self): # return self._name # def set_name(self,newname): # if type(newname)is str and newname.isdigit()==False: # self._name=newname # else: # print('不合法') # return self.__length*self.__width # a=Room('土豪',5,2) # a.set_name('二') # print(a.get_name())
但是这样做如果我想实现其他功能还要重新设置定义新的函数名,且调用时也还需要记函数名相应实现什么功能,比较麻烦。这里就可以用property属性函数,来实现。之后导入不同功能的装饰器,且函数名无需改变。
# class Room: # def __init__(self,name,length,width): # self.__name=name # self.__length=length # self.__width=width # @property #@property 用于获取值 使用setter和deleter装饰器,必须是在有@property的前提下才可以 # def name(self): # return self._name # @name.setter #@名字.setter 用于修改 # def name(self,newname): # if type(newname)is str and newname.isdigit()==False: # self._name=newname # else: # print('不合法') # return self.__length*self.__width
# @name.deleter #@名字.deleter 用于删除
# del self.__name # a=Room('土豪',5,2) # a.name='二'
del a.name # print(a.name) # print(Room.name)
method方法
classmethod(类方法) :把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
class Goods: # __discount = 0.8 # def __init__(self,name,price): # self.name = name # self.__price = price # # def price(self): # return self.__price * Goods.__discount # @classmethod #类方法 # def change_discount(cls,new_discount): # 修改折扣 # cls.__discount = new_discount # apple = Goods('苹果',5) # print(apple.price()) # Goods.change_discount(0.5) # Goods.change_discount(Goods) # print(apple.price())
4.0
2.5
staticmethod(静态方法):一个函数 既和对象没有关系 也和类没有关系,用@staticmethod装饰后,可以变成类的静态方法。静态方法没有默认的参数 就象函数一样
# class Login: # def __init__(self,name,password): # self.name = name # self.pwd = password # def login(self):pass # # # @staticmethod # def get_usr_pwd(): # 静态方法 # usr = input('用户名 :') # pwd = input('密码 :') # Login(usr,pwd) # # Login.get_usr_pwd()