多态和封装

python 天生支持多态

导引

在其他语言中

class Alipay:
    def pay(self,money):
        print('使用支付宝支付了%s元' % money)

class Appplepay:
    def pay(self,money):
        print('使用Appplepay支付了%s元' % money)

def pay(Applepay,pay_obj,int money):#其他语言里面,这里需要传一个数据类型,但是代码里面既有Alipay又有Appplepay,只能传一个。
    pay_obj.pay(money)

那么怎么做?

class Payment:pass
class Alipay(Payment):
    def pay(self,money):
        print('使用支付宝支付了%s元' % money)

class Appplepay(Payment):
    def pay(self,money):
        print('使用Appplepay支付了%s元' % money)

def pay(Payment,pay_obj,int money):#直接以Payment代替
    pay_obj.pay(money)

其中class Payment:pass,这就是多态

但是python天生支持多态,所以就不用写这些

class Alipay():
    def pay(self,money):
        print('使用支付宝支付了%s元' % money)

class Appplepay():
    def pay(self,money):
        print('使用Appplepay支付了%s元' % money)

def pay(pay_obj,money):#直接以Payment代替
    pay_obj.pay(money)

动态的定义

多态指的是一类事物有多种形态

比如动物有多种形态:人,狗,猪等

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')

比如上面就是Animal类的多种形态

文件有多种形态:文本文件,可执行文件

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')

多态性

比如上面支付的代码:可以使用payment一种方法同时实现Applepay和Alipay,这个就是多态性

class List:
    def __len__(self):pass
class Tuple:
    def __len__(self):pass

#上面两个类很相似,实现了相同的方法,所以将这种情形叫做鸭子类型

def len(l_t):#因为python是一个强动态类型的语言,如果是其他强类型语言,那么这里就必须指定是list还是tuple,不能直接写参数;为为了方便就必须在代码前面协商一个fu类型来统指代这里
    return l_t.__len__()

l=list()
len(l)

其他语言怎么操作

class Foo:pass
class List(Foo):
    def __len__(self):pass
class Tuple(Foo):
    def __len__(self):pass

#上面两个类很相似,实现了相同的方法,所以将这种情形叫做鸭子类型

def len(Foo,l_t):#这里就使用Foo类来代理
    return l_t.__len__()

l=list()
len(l)

python是一个动态强类型的语言:
不崇尚根据继承所得来的相似
只是自己实现自己的代码即可
如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
list,tuple这种相似,是自己写代码的时候约束的,而不是通过父类约束的,也就是说,list和tuple两种数据类型的操作模式非常类似,但是彼此独立,比如删掉list中的str功能,并不影响tuple,这种关系又被称为松耦合。
优点:松耦合,每个相似的类之间都没有影响
缺点:太随意,如果

接口类和抽象类在python中的应用并不是非常必要

封装

广义上面向对象的封装:代码的保护,面向对象的思想本身就是一种
只让自己的对象能调用自己类中的方法

狭义上的封装——面向对象的三大特征之一
属性和方法都隐藏起来,不让你看见

class Person:
    def __init__(self,name,password):
        self.name=name
        self.password=password
alex=Person('alex','alex341')
print(alex.password)

假设我们不想让别人打印出密码,但是代码内部仍需要使用则

class Person:
    def __init__(self,name,password):
        self.name=name
        self.__password=password#在password前面加上__,这就能够将password私有,无法打印
alex=Person('alex','alex341')
print(alex.password)

调用字典,打印结果是这样

class Person:
    def __init__(self,name,password):
        self.name=name
        self.__password=password#在password前面加上__,这就能够将password私有,无法打印

alex=Person('alex','alex341')
print(alex.__dict__)

D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/3.二分查找算法.py
alex341
{'name': 'alex', '_Person__password': 'alex341'}

Process finished with exit code 0

那么也就是可以

class Person:
    def __init__(self,name,password):
        self.name=name
        self.__password=password#在password前面加上__,这就能够将password私有,无法打印

alex=Person('alex','alex341')
print(alex.__dict__)
print(alex._Person__password)#通过_Person__password方法调用

进一步

class Person:
    def __init__(self,name,password):
        self.name=name
        self.__password=password#在password前面加上__,这就能够将password私有,无法打印
    def get_pwd(self):
        return self.__password
alex=Person('alex','alex341')
print(alex.__dict__)
print(alex._Person__password)
print(alex.get_pwd())

#新的问题,为何明明是__password,为何生成的是_Person__password?
#因为这是在python类的内部才会这样,自动实现转换

那么如何证明只在类内部才有这个功能?

class Person:
    def __init__(self,name,password):
        self.name=name
        self.__password=password#在password前面加上__,这就能够将password私有,无法打印
    def get_pwd(self):
        print(self.__dict__)#得到的是__high而非_Person__high
        return self.__password
alex=Person('alex','alex341')

alex.__high=1
print(alex.get_pwd())

私有静态属性、私有对象、私有方法

class Person:
    __key=123#私有静态属性
    def __init__(self,name,password):
        self.name=name
        self.__password=password#私有对象
    def __get_pwd(self):#私有方法
        print(self.__dict__)#得到的是__high而非_Person__high
        return self.__password
alex=Person('alex','alex341')

alex.__high=1
print(alex.get_pwd())

当定义了私有以后,只能在类的内部调用,而不能在外部调用,那是因为发生了改变:

比如表面上是将password变为了__password,但是实际上却是变化了_Person__password,发生了变形,所以外面调不到

 封装的应用

class Room:
    def __init__(self,name,length,width):
        self.name = name
        self.__length=length#这里做了隐藏
        self.__width = width

    def area(self):
        return self.__length*self.__width

Jin=Room('金老板',2,4)
print(Jin.area())

延申

class Room:
    def __init__(self,name,length,width):
        self.__name = name
        self.__length=length#这里做了隐藏
        self.__width = width
#下面的get和set方法在c++里面很常用,python中用途较少,在实际编程过程中可以根据自己的实际情况选择合适的编程方法
    def get_name(self):
        return self.__name#因为上面已经对name进行了封装,所以必须要写这个函数,这样才能实现在外部调用name
    def set_name(self,Newname):
        if type(Newname) is str and Newname.isdigit()==False:
            self.__name=Newname
        else:
            print('名字不合法')

    def area(self):
        return self.__length*self.__width

Jin=Room('金老板',2,4)
print(Jin.area())
Jin.set_name('2')
print(Jin.get_name())

新的问题:父类的私有属性能被子类调用吗?

class Foo:
    __key='123'#这里封装以后,实际结果变为_Foo__key
class Son(Foo):
    print(Foo.__key)#而这里实际上是_Son__key,所以调不到,代码报错
#如果子类能够调用父类,那么代码执行结果就是123,但是结果显示代码报错

D:\anoconda\python.exe F:/python/python学习/人工智能/第一阶段day2/3.二分查找算法.py
Traceback (most recent call last):
  File "F:/python/python学习/人工智能/第一阶段day2/3.二分查找算法.py", line 4, in <module>
    class Son(Foo):
  File "F:/python/python学习/人工智能/第一阶段day2/3.二分查找算法.py", line 5, in Son
    print(Foo.__key)
AttributeError: type object 'Foo' has no attribute '_Son__key'

Process finished with exit code 1

也就是再次验证,私有化以后只能在自己的类中调用,不能在类的外面,更不能在其他类中调用

会用到私有这个概念的场景:
隐藏起一个属性,不想让类的外部调用;
我想保护这个属性,不想让属性随意改变
我想保护这个属性,不被子类继承

 

posted @ 2019-03-11 23:10  舒畅123  阅读(99)  评论(0编辑  收藏  举报