面向对象初识
面向对象
# 思想:角色的抽象,创建类创建对象(实例化),操作这些实例 # 面向对象的关键字 class 类名: 静态属性='aaa' def __init__(self):pass 类名.静态属性 # 存储在类的命名空间里 对象 = 类名() # 实例化:创造了一个self对象,然后执行init方法,返回self对象给外部 # 类名.属性 # 类名.方法()
# 组合使用 --- 嵌套使用 # 组合:一个类的对象是另一个类的属性即为组合 class JI(object): def __init__(self,a,b): self.a = a self.b = b def JiaFa(self): return self.a + self.b def JianFa(self): return self.a - self.b class Ring(object): def __init__(self,a,b): self.jiafa = JI(a,b) self.jianfa = JI(a,b) def test1(self):return self.jiafa.JiaFa() def test2(self):return self.jianfa.JianFa() ring = Ring(20,10) print(ring.test1()) print(ring.test2())
面向对象三大特性
1)继承
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
class A:pass # 父类,基类,超类 class B:pass # 父类,基类,超类 class A1_son(A,B):pass # 子类,派生类 class A2_son(A,B):pass # 子类,派生类 # 一个类 可以被多个类继承 # 一个类 可以继承多个类 --- python独有,其他语言没有多继承 print(A1_son.__bases__) # 查看父类 print(A.__bases__) # -- 在python3里没有继承父类则默认继承 object --
class DongWu: def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age class Ren(DongWu): def A(self): return "这是个人" class Dog(DongWu): def A(self): return "这是个狗" r = Ren("小明",'男','18') print(r.name,r.sex,r.age) # 结果:小明 男 18 -- 由于子类没有init方法但是是个继承类,故寻找上级init方法
# 继承 class DongWu: def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age class Ren(DongWu): def A(self): return "这是个人" class Dog(DongWu): def A(self): return "这是个狗" r = Ren("小明",'男','18') print(r.name,r.sex,r.age) # 结果:小明 男 18 -- 由于子类没有init方法但是是个继承类,故寻找上级init方法
# 继承+派生 class DongWu: def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def A(self): print("执行了动物类") class Ren(DongWu): def __init__(self, name, sex, age, types): DongWu.__init__(self, name, sex, age) self.types = types # === 派生属性 def A(self): DongWu.A(self) # 如果想既实现子类又实现父类则需要直接调用父类方法 print("执行了人类") r = Ren("小明",'男','18','人') # print(r.name,r.sex,r.age,r.types) ''' 结果:小明 男 18 人 DongWu.__init__(self, name, sex, age) # 传值self进入此时DongWu的init里面就都有值了 self.types = types # 在原有的self里面新增派生属性 总结:父类中没有的方法在子类中出现即为派生,只有子类对象调用,子类中有的一定用子类的,如果子类没有则找父类,都没有则报错 如果子类中存在还想使用父类的方法则直接调用父类方法 ''' r.A()
# 单继承类内使用 class DongWu: def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age def eat(self): print('父类的eat') class Ren(DongWu): def __init__(self,name,sex,age,types): super().__init__(name,sex,age) # ==super()继承方式只在新式类中有,python3中所有类都是新式类 self.types = types def eat(self): print('子类的eat') r = Ren("小明",'男','18','人') print(r.name,r.sex,r.age,r.types) # 结果:小明 男 18 人 -- 由于子类没有init方法但是是个继承类,故寻找上级init方法 # super的第二种使用:在类外使用 r.eat() # === 子类的eat # 语法格式super(类名,对象名).方法() print(super(Ren,r).eat()) # === 父类的eat
【多继承】:在python3中所有类都是新式类遵循广度优先原则,正常情况从左往右继承,当父类还有父类时,深度继承到父类的焦点前一个父类止,开始往右继续继承,例如方式一中A为焦点类即深度继承到B点停止开始广度优先继承C,方式二中F为焦点类即深度继承到A点为止开始广度优先继承
方式一:

方式二:

【多继承】:在python2中新式类和经典类共存,新式类需手动继承object,没有继承object的为经典类,经典类走深度优先原则,即方式一
方式一:

注:python3和python2中类的区别
- python3只有新式类,默认继承object;
- python2中既有新式类又有经典类,新式类需要手动继承object否则为经典类;
- super()方法只在python3中才有;
- cls.mor() 只有新式类才有【cls.mor()查看继承顺序】;
面向对象的规范:接口类/抽象类
1)接口类
定义:要实现不同的功能就继承不同的类来实现,接口隔离原则
from abc import abstractmethod,ABCMeta """ metaclass=ABCMeta 代表成为一个规范类 @abstractmethod 代表继承这个类必须有这个函数方法否则报错 """ class ZouAnimal(metaclass=ABCMeta): @abstractmethod def zou(self):pass class YouAnimal(metaclass=ABCMeta): @abstractmethod def you(self):pass class FeiAnimal(metaclass=ABCMeta): @abstractmethod def fei(self):pass # tiger 走路,游泳 class Tiger(ZouAnimal,YouAnimal): def zou(self): pass def you(self): pass # oldying 走路,飞 class Oldying(ZouAnimal,FeiAnimal):pass # swan 走路,游泳,飞 class Swan(ZouAnimal,YouAnimal,FeiAnimal):pass t = Tiger() o = Oldying() # TypeError: Can't instantiate abstract class Oldying with abstract methods fei, zou
2)抽象类
定义:抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
# 抽象类:规范 # 一般情况下 单继承 能实现的功能都是一样的 # 多继承 由于功能比较复杂,所以不容易抽象出相同的实现功能内容在父类上 import abc class All_File(metaclass=abc.ABCMeta): all_file = 'file' @abc.abstractmethod # 定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' pass @abc.abstractmethod def write(self): '子类必须定义写功能' pass class Txt(All_File): # 子类继承抽象类,但是必须定义read和write方法 def read(self): print('文本数据读取方法') def write(self): print('文本数据写入方法') class Sata(All_File): # 子类继承抽象类,但是必须定义read和write方法 def read(self): print('硬盘数据读取方法') def write(self): print('硬盘数据写入方法') class Process(All_File): # 子类继承抽象类,但是必须定义read和write方法 def read(self): print('进程数据读取方法') def write(self): print('进程数据写入方法') wengben = Txt() yingpan = Sata() jincheng = Process() # 这样大家归一化,也就是linux系统中一切皆文件的思想 wengben.read() yingpan.read() jincheng.write() print(wengben.all_type) print(yingpan.all_type) print(jincheng.all_type)
2)封装
封装:属性和方法都隐藏起来,不让看见
- 所有的私有(属性/方法)都是在变量的左边加上双下划线
- 私有属性都不能在类外使用
class Person: __stu = '中山大学' def __init__(self,name,password): self.name = name self.__password = password # 定义代码级别的私有属性变量 """ 内部转换为_Person__password(_类名+__属性) {'name': 'Lee', '_Person__password': 'Lee001'} """ def __get_name(self): # 定义代码级别的私有方法 print(self.__dict__) return self.name def get_pwd(self): print(self.__dict__) return self.__password p = Person('Lee','Lee001') # 外部定义__私有属性无效 p.__hight = 10 # {'name': 'Lee', '_Person__password': 'Lee001', '__hight': 10} print(p.get_pwd())
父类的私有属性能被子类拿到吗? 答案:不能
class Foo: __key = '123456' # _Foo__key class Son(Foo): print(Foo.__key) # _Son__key s = Son() ''' 属性_Foo__key被变形_Son__key,所以无法调用父类私有属性 AttributeError: type object 'Foo' has no attribute '_Son__key' ''' print(s.__dict__)
会用到私有属性的场景
1、隐藏起一个属性,不想让外部调用
2、保护属性,不想属性随意被改变
3、保护属性不被子类继承
内置属性
1、@property:将方法伪装成属性使用
# 内置装饰器函数,只在面向对象中使用,将方法伪装成属性,但是函数中不能传任何参数 from math import pi # 圆类 class Circle: def __init__(self,r): self.r = r # 计算周长 @property # 将方法伪装成属性,函数中不能传任何参数 def perimeter(self): return 2*pi*self.r # 计算面积 @property # 将方法伪装成属性,函数中不能传任何参数 def area(self): return self.r**2*pi c1 = Circle(5) print(c1.area)
class Goods: sale = 0.8 # 折扣 def __init__(self,name,price): self.name = name self.__price = price # 原价设置私有属性 @property def price(self): # 返回卖价 return self.__price * Goods.sale good = Goods('苹果',5) print(good.price) """ 这样在修改时实例化带商品和原价,返回卖价,在静态属性修改折扣 """
class Person: def __init__(self,name): self.__name = name @property # 这个属性修改的方法 def name(self): return self.__name @name.setter # name为要修改的方法名 def name(self,new_name): self.__name = new_name @name.deleter # name为要删除的方法名 def name(self): del self.__name p = Person("小明") print(p.name) p.name = "大明" print(p.name) del p.name print(p.__dict__)
2、@classmethod:把一个方法变成一个类方法,这个方法可以直接被类调用,不需要任何对象
class Goods: __sale = 0.8 # 折扣 def __init__(self,name,price): self.name = name self.__price = price # 原价设置私有属性 @property def price(self): # 返回卖价 return self.__price * Goods.__sale @classmethod # 把一个方法变成一个类方法,这个方法可以直接被类使用,不需要依赖任何对象 def change_sale(cls,New_sale): # 修改折扣 cls.__sale = New_sale good = Goods('苹果',5) print(good.price) Goods.change_sale(0.5) print(good.price) # 当这个方法只涉及静态属性时,就应该使用@classmethod方法来装饰这个方法
3、@staticmethod:在面向对象中如果一个函数既和对象没有关系又和类没有关系可以使用这个方法将函数变成静态方法
class Login: def __init__(self,username,password): self.username = username self.password = password self.login() def login(self): print("登陆成功") @staticmethod def get_user_pwd(): user = input('请输入用户名:') pwd = input('请输入密码:') Login(user,pwd) Login.get_user_pwd()
问:对象能调用类方法和静态方法吗?
答:能
3)多态
多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)
import abc class File(metaclass=abc.ABCMeta): # 同一类事物:文件 @abc.abstractmethod def click(self): pass class Text(File): # 文件的形态之一:文本文件 def click(self): print('open file') class ExeFile(File): # 文件的形态之二:可执行文件 def click(self): print('execute file') # 同一事物,多种形态
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
class Payment: def pay(self,money):pass class Wechat(Payment): def pay(self,money): print('微信支付%s'% money) class Alipay(Payment): def pay(self,money): print('支付宝支付%s'% money) # 多态性依赖于:继承 # 多态性:定义统一的接口, def func(obj,money): # obj这个参数没有类型限制,可以传入不同类型的值 obj.pay(money) # 调用的逻辑都一样,执行的结果却不一样 wechat = Wechat() ali = Alipay() func(wechat,100) func(ali,200)

浙公网安备 33010602011771号