今日所学:
一、多态
1、定义:多态是指对象如何通过他们共同的属性和动作来操作及访问,而不需要考虑他们具体的类。
多态表明了动态绑定的状态,不同的对象调用同一种方法,python本身就是多态的。
2、多态和继承的关系:
多态是基于继承而来的。
多态的继承有两层含义:(1)改变 (2)扩展
多态是类的这两层意义的恶一个具体的实现机制,即调用不同的实例化的对象下的相同的方法,实现的过程不一样。
import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass def func(obj): obj.talk() 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‘) p1=People() #实例化 d1=Dog() z1=Pig() p1.talk() #子类调用基类的属性 d1.talk() z1.talk() p1.func() #也可以定义一个接口函数func(),然后在该函数调用talk方法,则在调用func时就相当于调用talk函数 d1.func() #这就是多态,基于继承而来,且不同实例化的对象在调用方法时实现方式有多种 z1.func() >>> say hello say wangwang say aoao say hello say wangwang say aoao
python本身就是多态的。
#str,list,tuple都是序列类型 s=str(‘hello‘) l=list([1,2,3]) t=tuple((4,5,6)) print(s.__len__()) print(l.__len__()) print(t.__len__()) #两种不同的调用方法,平时所用的len()函数就相当于调用了对象下的__len__函数 print(len(s)) print(len(l)) print(len(t)) >>> 5 3 3 5 3 3
二、封装
1、三种含义:
(1)类就是一个麻袋,本身就是一个封装
(2)用单下划线或双下划线把属性定义为私有(约定说外部不能调用,但仍是可以调用的)
(3)内部的实现逻辑,外部无法知晓,这是真正意义上的封装
#封装的用法:明确区分内外。把自己的方法定义为私有的。(在函数名前加__) 正常情况: class A: def fa(self): print("from A") def test(self): self.fa() class B(A): def fa(self): print("from B") b1=B() b1.test() #若父类和子类同名,则会先在子类中寻找 #如果只要调用父类的函数,则就可以使用封装,把自己的方法定义为私有的。 封装后 class A: def __fa(self): #在加__后,会自动定义成_类名__fa,在属性字典中即可看到 print("from A") def _mu(self): #单下划线也可以用来表示私有,但只是一种约定而已,外部仍可以调用得到 print("我是单下划线") def test(self): self.__fa() class B(A): def fa(self): print("from B") b1=B() b1.test() b1._mu() b1._A__fa() #子类不能访问__fa(),但可以访问_A__fa()。 print(A.__dict__) >>> from B from A 我是单下划线 from A {‘__module__‘: ‘__main__‘, ‘_A__fa‘: <function A.__fa at 0x000001E1E685B670>, ‘_mu‘: <function A._mu at 0x000001E1E685B700>, ‘test‘: <function A.test at 0x000001E1E685B790>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘A‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘A‘ objects>, ‘__doc__‘: None}
2、封装的真谛在于明确地区分内外,封装的属性可以直接在内部(类中)使用,而不能被外部(调用者)直接使用。
然而定义属性的目的终归是要用,外部要想用类隐藏的属性,需要为其开辟接口,即在类中设置接口函数(访问函数),让外部能够间接地用到我们隐藏起来的属性
#类的设计者 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #接口函数,对外提供的接口,隐藏了内部的实现细节 return self.__width * self.__length #内部可以调用内部的逻辑,但外部使用者则不能看到该实现逻辑 #使用者 r1=Room(‘卧室‘,‘egon‘,20,20,20) a=r1.tell_area() #使用者调用接口tell_area print(a) --> 400 #类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了 return self.__width * self.__length * self.__high #对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能 r1=Room(‘卧室‘,‘egon‘,20,20,20) b=r1.tell_area() print(b) -->8000
3、封装不要滥用,如真需要隐藏起来才封装,如果先隐藏了,后期要通过一个个接口函数去调出来方法,相当于把类打了一个个孔,最终写出来的类会乱七八糟的。
4、封装可以用来封装数据、方法,其中封装方法目的是为了隔离复杂度。
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱 #对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做 #隔离了复杂度,同时也提升了安全性 class ATM: def __card(self): print(‘插卡‘) def __auth(self): print(‘用户认证‘) def __input(self): print(‘输入取款金额‘) def __print_bill(self): print(‘打印账单‘) def __take_money(self): print(‘取款‘) def withdraw(self): #接口函数,内部调用设定的私有函数 self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw()
三、反射(自省)
1、反射指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。
2、4个可以实现自省的函数
#1、hasattr()判断object中有没有一个name字符串对应的方法或属性,返回值是一个布尔值 class A: def __init__(self,name): self.name=name def test(self): print("我的名字是%s" %self.name) class B(A): def __init__(self): pass b1=B() print(hasattr(b1,"test")) print(hasattr(b1,"test1111")) >>> True False
#2、getattr()是用来获取属性 class A: def __init__(self,name): self.name=name def test(self): print("我的名字是%s" %self.name) b1=A("alex") print(getattr(b1,"test")) #获取属性test() func=getattr(b1,"test") #可为其赋予函数,然后运行该函数 func() #getattr还有第三个参数,可用来传入若找不到属性可输出的内容,默认报错 print(getattr(b1,"asflka","找不到啊")) #第三个参数设置找不到是输出的内容 >>> <bound method A.test of <__main__.A object at 0x000002AB12C9AA60>> 我的名字是alex 找不到啊
#3、setattr()是用来设置属性 class A: def __init__(self,name): self.name=name def test(self): print("我的名字是%s" %self.name) b1=A("alex") setattr(b1,"happy","asjdhaf") #三个参数:类名、实例;属性名;属性内容。缺一不可 print(b1.__dict__) setattr(b1,‘show_name‘,lambda self:self.name+‘sb‘) #属性内容也可设置为函数 print(b1.show_name(b1)) #在添加属性后,也可以用同样的方法去调用 >>> {‘name‘: ‘alex‘, ‘happy‘: ‘asjdhaf‘} alexsb
#4、delattr()是用来删除属性 class A: def __init__(self,name): self.name=name def test(self): print("我的名字是%s" %self.name) b1=A("alex") setattr(b1,"happy","asjdhaf") #三个参数:类名、实例;属性名;属性内容。缺一不可 print(b1.__dict__) setattr(b1,‘show_name‘,lambda self:self.name+‘sb‘) #属性内容也可设置为函数 print(b1.show_name(b1)) #在添加属性后,也可以用同样的方法去调用 delattr(b1,"show_name") #删除属性,类名/实例;属性名 print(b1.__dict__) >>> {‘name‘: ‘alex‘, ‘happy‘: ‘asjdhaf‘} alexsb {‘name‘: ‘alex‘, ‘happy‘: ‘asjdhaf‘}
以上。
Python 小栈_19:Python 面向对象之多态、封装和反射
原文:https://www.cnblogs.com/211293dlam/p/12562101.html