面向对象编程(封装、多态)Python版(Demo详解)

Jane ·
更新时间:2024-11-10
· 895 次阅读

本篇介绍面向对象编程的( 封装、多态 )相关知识点,一起学习,共同进步

Python专栏请参考:人生苦短-我学python 文章目录一.封装二.多态三.类属性和实例属性四.静态方法和类方法 一.封装

面向对象三大特性:封装、继承、多态

封装的意义: ①将属性和方法放到一起做为一个整体,然后通过实例化对象来处理; ②隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了; ③对类的属性和方法增加 访问权限控制。 私有权限:在属性名和方法名 前面 加上两个下划线 __ ①类的私有属性 和 私有方法,都不能通过对象直接访问,但是可以在本类内部访问; ②类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问; ③私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。 class Master(object): def __init__(self): self.kongfu = "古法煎饼果子配方" def make_cake(self): print("[古法] 按照 制作了一份煎饼果子..." % self.kongfu) class School(object): def __init__(self): self.kongfu = "现代煎饼果子配方" def make_cake(self): print("[现代] 按照 制作了一份煎饼果子..." % self.kongfu) class Prentice(School, Master): def __init__(self): self.kongfu = "猫氏煎饼果子配方" # 私有属性,可以在类内部通过self调用,但不能通过对象访问 self.__money = 10000 # 私有方法,可以在类内部通过self调用,但不能通过对象访问 def __print_info(self): print(self.kongfu) print(self.__money) def make_cake(self): self.__init__() print("[猫氏] 按照 制作了一份煎饼果子..." % self.kongfu) def make_old_cake(self): Master.__init__(self) Master.make_cake(self) def make_new_cake(self): School.__init__(self) School.make_cake(self) class PrenticePrentice(Prentice): pass damao = Prentice() # 对象不能访问私有权限的属性和方法 # print(damao.__money) # damao.__print_info() pp = PrenticePrentice() # 子类不能继承父类私有权限的属性和方法 print(pp.__money) pp.__print_info() Traceback (most recent call last): File "D:/Phython/study/venv/Include/hello.py", line 47, in print(damao.__money) AttributeError: 'Prentice' object has no attribute '__money' 总结 Python中没有像C++中 public 和 private 这些关键字来区别公有属性和私有属性。 Python是以属性命名方式来区分,如果在属性和方法名前面加了2个下划线’__’,则表明该属性和方法是私有权限,否则为公有权限。 修改私有属性的值 如果需要修改一个对象的属性值,通常有2种方法 对象名.属性名 = 数据 ----> 直接修改 对象名.方法名() ----> 间接修改 私有属性不能直接访问,所以无法通过第一种方式修改,一般的通过第二种方式修改私有属性的值:定义一个可以调用的公有方法,在这个公有方法内访问修改。 class Master(object): def __init__(self): self.kongfu = "古法煎饼果子配方" def make_cake(self): print("[古法] 按照 制作了一份煎饼果子..." % self.kongfu) class School(object): def __init__(self): self.kongfu = "现代煎饼果子配方" def make_cake(self): print("[现代] 按照 制作了一份煎饼果子..." % self.kongfu) class Prentice(School, Master): def __init__(self): self.kongfu = "猫氏煎饼果子配方" # 私有属性,可以在类内部通过self调用,但不能通过对象访问 self.__money = 10000 # 现代软件开发中,通常会定义get_xxx()方法和set_xxx()方法来获取和修改私有属性值。 # 返回私有属性的值 def get_money(self): return self.__money # 接收参数,修改私有属性的值 def set_money(self, num): self.__money = num def make_cake(self): self.__init__() print("[猫氏] 按照 制作了一份煎饼果子..." % self.kongfu) def make_old_cake(self): Master.__init__(self) Master.make_cake(self) def make_new_cake(self): School.__init__(self) School.make_cake(self) class PrenticePrentice(Prentice): pass damao = Prentice() # 对象不能访问私有权限的属性和方法 # print(damao.__money) # damao.__print_info() # 可以通过访问公有方法set_money()来修改私有属性的值 damao.set_money(100) # 可以通过访问公有方法get_money()来获取私有属性的值 print(damao.get_money()) 100 二.多态

所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态 ,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

鸭子类型:虽然我想要一只"鸭子",但是你给了我一只鸟。 但是只要这只鸟走路像鸭子,叫起来像鸭子,游泳也像鸭子,我就认为这是鸭子。

Python的多态,就是弱化类型,重点在于对象参数是否有指定的属性和方法,如果有就认定合适,而不关心对象的类型是否正确。

Python “鸭子类型”

class F1(object): def show(self): print('F1.show') class S1(F1): def show(self): print('S1.show') class S2(F1): def show(self): print('S2.show') # 由于在Java或C#中定义函数参数时,必须指定参数的类型 # 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法, # 所以在def Func的形参中obj的类型是 S1和S2的父类即F1 # # 而实际传入的参数是:S1对象和S2对象 def Func(obj): # python是弱类型,即无论传递过来的是什么,obj变量都能够指向它,这也就没有所谓的多态了(弱化了这个概念) obj.show() s1_obj = S1() Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show s2_obj = S2() Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show S1.show S2.show

通俗点理解:定义obj这个变量是说的类型是:F1的类型,但是在真正调用Func函数时给其传递的不一定是F1类的实例对象,有可能是其子类的实例对象,

这种情况就是所谓的多态

多态:不同的子类对象,调用相同的父类方法,产生不同的结果 ①继承 ②重写 案例如下 # 多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度) class Animal: def run(self): raise AttributeError('子类必须实现这个方法') class People(Animal): def run(self): print('人正在走') class Pig(Animal): def run(self): print('pig is walking') class Dog(Animal): def run(self): print('dog is running') peo = People() pig = Pig() d = Dog() peo.run() pig.run() d.run() 人正在走 pig is walking dog is running 多态性的好处 1.增加了程序的灵活性 以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal) 2.增加了程序额可扩展性 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用 三.类属性和实例属性 先来谈一下类属性和实例属性 在前面的例子中我们接触到的就是实例属性(对象属性),顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。 对于公有的类属性,在类外可以通过类对象和实例对象访问 类属性 class People(object): name = 'Tom' # 公有的类属性 __age = 12 # 私有的类属性 p = People() print(p.name) # 正确 print(People.name) # 正确 print(p.__age) # 错误,不能在类外通过实例对象访问私有的类属性 print(People.__age) # 错误,不能在类外通过类对象访问私有的类属性 实例属性(对象属性) class People(object): address = '山东' # 类属性 def __init__(self): self.name = 'xiaowang' # 实例属性 self.age = 20 # 实例属性 p = People() p.age = 12 # 实例属性 print(p.address) # 正确 print(p.name) # 正确 print(p.age) # 正确 print(People.address) # 正确 print(People.name) # 错误 print(People.age) # 错误 山东 xiaowang 12 山东 Traceback (most recent call last): File "D:/Phython/study/venv/Include/hello.py", line 14, in print(People.name) # 错误 AttributeError: type object 'People' has no attribute 'name' 通过实例(对象)去修改类属性 class People(object): country = 'china' #类属性 print(People.country) p = People() print(p.country) p.country = 'japan' print(p.country) # 实例属性会屏蔽掉同名的类属性 print(People.country) del p.country # 删除实例属性 print(p.country) china china japan china china 总结 ①如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。 ②如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。 四.静态方法和类方法 类方法 是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法 对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以’cls’作为第一个参数的名字,就最好用’cls’了),能够通过实例对象和类对象去访问。 class People(object): country = 'china' #类方法,用classmethod来进行修饰 @classmethod def get_country(cls): return cls.country p = People() print(p.get_country()) #可以用过实例对象引用 print(People.get_country()) #可以通过类对象引用 china china 类方法还有一个用途就是可以对类属性进行修改: class People(object): country = 'china' #类方法,用classmethod来进行修饰 @classmethod def get_country(cls): return cls.country @classmethod def set_country(cls,country): cls.country = country p = People() print(p.get_country()) #可以用过实例对象访问 print(People.get_country()) #可以通过类访问 p.set_country("japan") print(p.get_country()) print(People.get_country()) 运行结果 china china japan japan 结果显示在用类方法对类属性修改之后,通过类对象和实例对象访问都发生了改变 静态方法 需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数,可以通过对象和类来访问。 class People(object): country = 'china' @staticmethod #静态方法 def get_country(): return People.country p = People() # 通过对象访问静态方法 print(p.get_country()) # 通过类访问静态方法 print(People.get_country()) china china 总结 ①从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法; ②实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。 ③静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类实例对象来引用。 The best investment is in yourself
在这里插入图片描述 2020.04.05 记录辰兮的第48篇博客
作者:辰兮要努力



封装 对象 面向对象 面向对象编程 demo 多态 Python

需要 登录 后方可回复, 如果你还没有账号请 注册新账号