zoukankan      html  css  js  c++  java
  • Python面向对象之多态、封装

    一、多态

    超过一个子类继承父类,出现了多种的形态。

    例如,动物种类出现了多种形态,比如猫、狗、猪

    class Animal:pass
    class Cat(Animal):pass
    class Dog(Animal):pass
    class Pig(Animal):pass

    Python是处处有多态,因为新式类都是继承object

    多态的定义:一个类表现出的多种形态,通过继承来实现,一个父类有多个子类。再简化的说法就是“有多种形式”,就算不知道变量(参数)所引用的对象类型,也一样能进行操作,来者不拒。

    count(),repr() 这类就是多态的代表

    在java中的表示:在一个函数中需要给参数指定数据类型,如果这个地方可以接收两个以上类型的变量,那么这些类型应该有一个父类,这个父类是所有子类对象的类型

    在python中:函数的参数不需要指定数据类型,所以不需要通过继承的形式来统一一组数据类型,换句话说 所有的对象其实都是object类型,所有在python中处处是多态。

    经典类和新式类都有多态

    from abc import ABCMeta,abstractmethod
    
    class Animal(metaclass=ABCMeta):
        @abstractmethod
        def talk(self):pass
    
    class Cat(Animal):
        def talk(self):
            print('喵喵')
    class Dog(Animal):
        def talk(self):
            print('汪汪')
    
    c = Cat()
    c.talk()
    d = Dog()
    d.talk()
    
    '''
    喵喵
    汪汪
    '''

    代码中有 Cat 和 Dog 两个类,都继承了类 Animal,它们都有 talk() 方法,输入不同的动物名称,会得出相应的结果。

    鸭子类型:

    在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由 James Whitcomb Riley 提出的鸭子测试,“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

    定义:不是明确的通过继承实现的多态,而是通过一个模糊的概念来判断这个函数能不能接收这个类型的参数

    python中通过鸭子类型来体现多态:比如len(),print()

    二、封装

    广义的封装:

    定义一个类,把所有的属性和方法都放在类里面

    为了只有这个类的对象才能使用定义在类中的方法,其他都用不了

    狭义上上的封装:

    把一个变量藏在类里,在类的外部不能引用私有变量,只有类的内部能使用

    class A:
        __x = 0     # 私有的静态变量

    定义一个类,执行的时候把类的内容读完才开辟类的空间,所有类的内容加载的时候就完成了

    class A:
        __x = 0     # 私有的静态变量
        print('AAA')
    
    '''
    AAA
    '''

    定义类的内存机制:

    ① 类中的静态变量和方法名在程序加载的过程中就已经执行完毕了,不需要等待调用

    ② 在类加载完成之前,类的名字还没出现在内存空间中

    ③ 私有的静态属性可以在类的内部使用,用来隐藏某个变量的值

    当私有变量在存储时会做了变形:_类名__私有变量

    类名.变形的私有变量可以取值,但是从编程规范的角度上出发,不能在类的外部使用私有的变量

    class Course:
        __name = 'python'     # 变形:_Course__name
    
    print(Course.__dict__)      # 查看类里所有的属性和变量
    print(Course._Course__name) # python,不建议使用这方法取值
    
    '''
    {'__module__': '__main__', '_Course__name': 'python', '__dict__': <attribute '__dict__' of 'Course' objects>, '__weakref__': <attribute '__weakref__' of 'Course' objects>, '__doc__': None}
    python
    '''

    定义私有变量的原因:

    ① 不想让使用者看到这个值

    ② 不想让使用者修改这个值

    ③ 让使用者修改这个值的时候做一些限制:保证了数据的安全

    ④ 有些方法或者属性不希望被子类继承

    不想让使用者修改这个值

    class University:
        def __init__(self,name,site):
            self.__name = name      # 定义了私有属性
            self.__site = site      # 定义了私有属性
    
        def name(self):             # 定义方法返回值
            return self.__name
    
        def site(self):             # 定义方法返回值
            return self.__site
    
    uni = University('哈佛大学','马萨诸塞州剑桥市')
    print(uni.name())               # 调用类提供的方法取值
    print(uni.site())               # 调用类提供的方法取值
    print(uni.name)                 # 类对象的方法的内存地址
    print(uni)                      # 类对象的内存地址
    uni.name = '剑桥大学'           # 在类对象里添加了name的值
    print(uni.__dict__)
    
    '''
    哈佛大学
    马萨诸塞州剑桥市
    <bound method University.name of <__main__.University object at 0x00000209EBDE7E48>>
    <__main__.University object at 0x00000209EBDE7E48>
    {'_University__name': '哈佛大学', '_University__site': '马萨诸塞州剑桥市', 'name': '剑桥大学'}
    '''

    让使用者修改这个值的时候做一些限制

    class Supermarket:
        __discount_coupon = 1000
        def __init__(self,name,price):
            self.name = name
            self.__price = price                # 定义私有变量
    
        def price(self):                        # 获取变量值的方法
            if self.__price > 5999:
                return self.__price - Supermarket.__discount_coupon
            else:
                return self.__price
    
        def change_price(self,new_price):       # 改变变量值的方法
            if isinstance(new_price,int):
                self.__price = new_price
            else:
                print('价格修改失败')
    
    
    ap = Supermarket('IPhone',6000)
    print(ap.price())                           # 通过方法获得私有变量的值
    ap.change_price(3000)                       # 通过方法改变私有变量的值
    print(ap.price())
    
    '''
    5000
    3000
    '''

    类中的私有成员:

    ① 私有的静态属性

    ② 私有的对象属性

    ③ 私有的方法

    私有变量在类的外部不能被定义,因为在类的内部带__ 定义私有变量都会变形,在外部被定义不会变形

    class Language:
        __China = 'chinese'             # 发生变形  '_Language__China': 'chinese'
    
    print(Language.__dict__)
    Language.__Korea = 'Korean'         # 在类的外部定义不会发生变形   __Korea': 'Korean'
    print(Language.__dict__)
    
    '''
    {'__module__': '__main__', '_Language__China': 'chinese', '__dict__': <attribute '__dict__' of 'Language' objects>, '__weakref__': <attribute '__weakref__' of 'Language' objects>, '__doc__': None}
    {'__module__': '__main__', '_Language__China': 'chinese', '__dict__': <attribute '__dict__' of 'Language' objects>, '__weakref__': <attribute '__weakref__' of 'Language' objects>, '__doc__': None, '__Korea': 'Korean'}
    '''

    私有变量不能被继承

    # 封装前
    class A:
        def __init__(self,name):
            self.name = name
    
    class B(A):
        def get_name(self):
            print(self.name)
    
    b = B('haha')
    b.get_name()
    
    '''
    haha
    '''
    
    # 封装后
    class A:
        def __init__(self,name):
            self.__name = name
    
    class B(A):
        def get_name(self):
            print(self.__name)
    
    b = B('haha')
    b.get_name()
    
    
    AttributeError: 'B' object has no attribute '_B__name'

    私有成员的特点:

    ① 不能在类的外部被调用,只能在类的内部被调用(在类的内部变形了,_类名__变量名)

    ② 不能被子类继承

    三、property 内置函数

    装饰器的使用:所有的装饰器函数、方法、类的上一行直接@装饰器的名字

    装饰器的分类:

    ① 装饰函数

    ② 装饰方法

    ③ 装饰类

    property 是一个装饰器函数

    @property 是装饰方法的,将一个方法伪装成一个属性,相当于调用方法是不需要加括号

    class A:
        def __init__(self,name):
            self.__name = name
    
        @property
        def name(self):
            return self.__name
    
    a = A('小明')
    print(a.name)
    
    '''
    小明
    '''
  • 相关阅读:
    form表单里submit的提交,如何不让其阻止ajax的调用
    前端模拟后台json 调接口
    纯前端实现搜索功能、模糊查询
    js如何获取select下拉框的value以及文本内容 并赋值
    清除表单input输入框内数据
    js动态生成的dom mouseover事件无效
    jq获取当前日期xxxx-xx-xx格式
    获取自定义属性、 data-* 的值
    媒体查询不起作用
    shell_判断语句If
  • 原文地址:https://www.cnblogs.com/st-st/p/9555567.html
Copyright © 2011-2022 走看看