zoukankan      html  css  js  c++  java
  • 面向对象之多态

    一、接口思想

    1、接口:建立关联的桥梁,方便管理代码

    python中没有接口语法

    def jiao(): pass
    def chi(): pass
    def pao(): pass
    
    # 清晰知道操作的功能,但不明确操作的具体对象
    print(len('123'))
    # 清晰最大操作的对象,但不明确具体的操作方法
    print('123'.__len__())

    2、接口类:

    用来定义功能的类,为继承它的子类提供功能的,该类的功能方法一般不需要有实现体,实现体有继承它的子类自己去实现

    class PetInterface:
        def close_master(self): pass
    
    class WatchInterface:
        def watch_door(self): pass
    
    class Dog(PetInterface, WatchInterface):
        def jiao(self): pass
    
        def chi(self): pass
    
        def pao(self): pass
    
        # 一定要重写接口的方法
        pass
    
    class Cat(PetInterface, WatchInterface): pass

    二、抽象类思想

    抽象父类:拥有抽象方法(子类共有的方法,但是父类不能有具体的实现体)的父类      

    抽象方法:方法名是具体的,但是实现体是抽象的(在子类中重写来具象化)

    # python中借助abc来实现抽象父类
    import abc  # abstract base class
    class Quan(metaclass=abc.ABCMeta):
        def __init__(self, name):
            self.name = name
        def run(self):
            print(self.name + 'running')
    
        # 抽象父类中的抽象方法,在继承它的子类中必须有自己的实现体
        #       -- 抽象父类中的抽象方法实现体就没有意义,实现与不实现都是pass填充
        @abc.abstractmethod
        def chi(self):
            # print(self.name + '肉')
            pass
        @abc.abstractmethod
        def jiao(self):
            # print('汪汪汪')
            pass
    
        @classmethod
        @abc.abstractmethod
        def fn(cls): pass
    
    class Dog(Quan):
        @classmethod
        def fn(cls): pass
    
        def kanmen(self):
            print(self.name + '看门')
        def chi(self):
            super().chi()
            print(self.name + '吃狗粮')
        def jiao(self):
            print('汪汪汪')
    
    class Wolf(Quan):
        @classmethod
        def fn(cls): pass
    
        def bulie(self):
            print(self.name + '捕猎')
        def chi(self):
            print(self.name + '吃肉')
        def jiao(self):
            print('嗷嗷嗷')
    
    dog = Dog('来福')
    wolf = Wolf('常委')
    
    dog.jiao()     # 汪汪汪
    wolf.jiao()    # 嗷嗷嗷
    dog.run()      # 来福running
    wolf.run()     # 常委running
    dog.chi()      # 来福吃狗粮
    wolf.chi()     # 常委吃肉

    三、多态

    1、定义:对象的多种状态 - 父类对象的多种(子类对象)状态

    2、多态的体现:

    功能或是需求,需要父类的对象,可以传入父类对象或任意子类对象均可以      

    注:一般都是规定需要父类对象,传入子类对象

    import abc
    class People(metaclass=abc.ABCMeta):
        def __init__(self, name):
            self.name = name
    
        @abc.abstractmethod
        def speak(self): pass
    
    class Chinese(People):
        def speak(self):
            print('说中国话')
    
    class England(People):
        def speak(self):
            print('说英国话')
    
    
    if __name__ == '__main__':
        # 多态的体现:功能或是需求,需要父类的对象,可以传入父类对象或任意子类对象均可以
        #       注:一般都是规定需要父类对象,传入子类对象
        def ask_someone(obj):
            print('让%s上台演讲' % obj.name)  # 父类提供,自己直接继承
            obj.speak()  # 父类提供,只不过子类重写了
    
        ch = Chinese('王大锤')
        en = England('Tom')
    
        ask_someone(ch)     # 让王大锤上台演讲
                            # 说中国话
    
        ask_someone(en)     # 让Tom上台演讲
                            # 说英国话

    四、鸭子类型

    1、定义:

    ①先规定:有什么属性及什么方法的类的类型叫鸭子类型

    ②这些类实例化出的对象,都称之为鸭子,都可以作为需求对象的一种具体体现

    class Test:
        def __init__(self, name):
            self.name = name
        def speak(self):
            print('说鸟语')
    
    if __name__ == '__main__':
        def ask_someone(obj):
            print('让%s上台演讲' % obj.name)      # 需要一个对象,这个对象需要什么特点,有name,有speak,
            obj.speak()                         # 那就制定一个规则,只要有一个对象,它有name属性,speak方法,都叫鸭子
                                                # 规定的规则能随意改变,需要一个什么样的对象,有这样特征的都叫鸭子
        test = Test('鸭子')
                                                # 规定一个对象有什么属性和方法,能提供该属性和方法的对象都叫鸭子
        ask_someone(test)    # 让鸭子上台演讲
                             # 说鸟语

    2、例子

    # 例:
    # 需求:需要一个对象,该对象有name属性及speak方法,就可以作为一种状态的体现被传入
    def ask_someone(obj):
        print('让%s上台演讲' % obj.name)
        obj.speak()
    
    # 1.先规定:有什么属性及什么方法的类的类型叫鸭子类型
    # 2.这些类实例化出的对象,都称之为鸭子,都可以作为需求对象的一种具体体现
    class A:
        # 能有自己特有的属性和方法,可以和B完全不一样,但是必须有鸭子类型规定的属性和方法,不然就不是鸭子类型
        def __init__(self, name):
            self.name = name
    
        def speak(self):
            print('说AAAA')
    
    class B:
        # 能有自己特有的属性和方法,可以和A完全不一样,但是必须有鸭子类型规定的属性和方法,不然就不是鸭子类型
        def __init__(self, name):
            self.name = name
    
        def speak(self):
            print('说BBBB')
    
    ask_someone(B('B'))           # 让B上台演讲
                                  # 说BBBB

    五、格式化和析构方法

     1、应用:

    class A:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        # ①格式化方法:在外界打印该类对象是被调用
        # 格式化外界直接打印该类对象的字符串表示结果
        def __str__(self):
    
            return '<name:%s | age:%s>' % (self.name, self.age)
    
        # ②析构方法:在对象被消耗的那一刹那被调用,在被消耗前可以做一些事情
        def __del__(self):
            # del会在self代表的对象被消耗的时候被调用
            # 我们可以在析构函数中释放该对象持有的其他资源,
            # 或者将一些持有资源持久化(保存到文件或数据库中)
            del self.name  # 也可以将name存起来
    
    a = A('老王', 88)
    print(a, type(a))     # <name:老王 | age:88>   <class '__main__.A'>
    
    import time
    time.sleep(3)
    
    print('文件马上执行完毕,a就会被销毁')

    2、了解:

    class B:
        # 了解:对象.语法的内部实现
        def __setattr__(self, key, value):
            # print(key, value)
            b.__dict__[key] = value
            # b.__dict__[key] = value.lower()
            # b.__dict__['xyz'] = 'XYZ'
    
        # 了了解:将对象添加属性的方式可以同字典形式
        def __setitem__(self, key, value):
            self.__dict__[key] = value
    
    
    b = B()
    b.name = 'BBB'   # == b.__dict__['name'] = 'BBB'
    print(b.name)    # BBB
    
    b['age'] = 18
    print(b.age)     # 18  # 访问还是通过.语法访问

    六、反射(*****)

    1、定义:通过字符串与类和对象的属性(方法)建立关联

    2、应用:

    class People:
        country = "China"
        
        def __init__(self, name):
            self.name = name
    
        def tell(self):
            print('%s is aaa' % self.name)
    
    obj = People('egon')
    
    # 1、hasattr(判断'country'是否在People的名称空间里)
    print(hasattr(People, 'country'))      # True  # 'country'是否在People的名称空间里
    print('country' in People.__dict__)    # True  # 不同的两种方法
    
    print(hasattr(obj, 'name'))            # True
    print(hasattr(obj, 'country'))         # True
    print(hasattr(obj, 'tell'))            # True
    
    # 2、getattr(查找)
    x = getattr(People, 'country')         # China
    print(x)
    x = getattr(People, 'country1',None)
    print(x)                               # None
    
    
    f = getattr(obj, 'tell', None)
    print(f == obj.tell)                 # True
    f()                                  # egon is aaa
    obj.tell()                           # egon is aaa
    
    
    # 3、setattr(增值)
    People.x = 111
    setattr(People, 'x', 111)
    print(People.x)                # 111
    
    obj.age = 18
    setattr(obj, "age", 18)
    print(obj.__dict__)            # {'name': 'egon', 'age': 18}
    
    
    # 4、delattr(删值)
    delattr(People, "country")     # ==del People.country
    print(People.__dict__)         # 从People的名称空间中删除了'country'
    
    delattr(obj, "name")           # ==del obj.name
    print(obj.__dict__)            # {}   # 删除obj里的’name’后,obj中的名称空间为空

    补充:

    ①__getattr__:在对象获取它没有的属性和方法的时候自动触发 

    ②__setattr__:在对象点属性设置属性值的时候自动触发

    class Demo(object):
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self, item):
            print('这个对象想获取一个它没有的属性>>>:',item)
            return 123
    
        def __setattr__(self, key, value):
            print(key, value)
    
    obj = Demo('jason')
    obj.password = '123'
    print(obj.name)
    print(obj.yyy)
    
    # 结果为
    # name jason
    # password 123
    # 这个对象想获取一个它没有的属性>>>: name
    # 123
    # 这个对象想获取一个它没有的属性>>>: yyy
    # 123

    3、小练习:

    class Foo:
        def run(self):
            while True:
                cmd = input('cmd>>: ').strip()if hasattr(self, cmd):
                    func = getattr(self, cmd)
                    func()
        def download(self):
            print('download....')
    
        def upload(self):
            print('upload...')
    
    obj=Foo()
    obj.run()
    # 结果为
    cmd>>: download
    download....
    cmd>>: upload
    upload...

    4、总结

    # 总结:
    # 类的属性用类来操作
    # 对象的属性用对象来操作
    # 方法建议使用类来操作,得到的方法调用时
    #       -- 对象的方法要传入具体的对象
    #       -- 类的方法不需要传入参数
    
    class C:
        def fn(self):
            print('fn')
    
        @classmethod
        def func(cls):
            print('func')
    
    fn = getattr(C, 'fn')
    c = C()
    fn(c)     # fn
    
    func = getattr(C, 'func')
    func()    # func

     

  • 相关阅读:
    shell基础--变量的数值计算
    shell基础--字符串和变量的操作
    shell基础--shell特殊变量
    Asp.net MVC 控制器扩展方法实现jsonp
    ASP.NET web api 跨域请求
    asp.net Web API简单的特性路由配置
    ASP.Net Web API 输出缓存 转载 -- Output caching in ASP.NET Web API
    基础拾遗 C# Json 与对象相互转换
    内存溢出和内存泄漏
    软件测试面试题(一)
  • 原文地址:https://www.cnblogs.com/zhangguosheng1121/p/10752188.html
Copyright © 2011-2022 走看看