zoukankan      html  css  js  c++  java
  • 封装、多态、类的约束、类的私有成员

    # 面向对象的三大特性
    # 封装:将一些重要的数据和信息放到一个空间,比如函数
    # 面向对象:
    
    class A:
        country = "China"  # 静态属性也是一种封装
        area = "深圳"
    
        def __init__(self, name, age):  # 这也是封装
            self.name = name
            self.age = age
    
    a1 = A("小明", 22)
    a2 = A("小花", 18)
    print(a1.__dict__)  # 对象属性的封装
    print(a1.name)  # 通过万能的 . 来调用
    # 多态
    # 一种事物有多种形态,比如水
    # Python默认支持多态
    # 鸭子类型
    # 看着像鸭子,就是鸭子
    # Python中约定俗成制定一些保持一致性的行为规范
    
    class A:
        def func1(self):
            print("in A func1")
    
        def func2(self):
            print("in A func2")
    
    class B:
        def func1(self):
            print("in B func1")
    
        def func2(self):
            print("in B func2")
    
    # 将A类B类里面相似的一些功能命名成相同的名字,隐约制定一些标准
    obj1 = A()
    obj1.func1()
    obj2 = B()
    obj2.func1()
    
    # 源码:
    # str index
    class Str_:
        def index(self):
            print("根据元素找索引")
    
    class List_:
        def index(self):
            print("根据元素找索引")
    
    class Tuple_:
        def index(self):
            print("根据元素找索引")
    
    # 这三个类中都有 index,都是指索引,这样更加规范化
    # 这三个类即互为鸭子
    # 类的约束
    # 目的是对类进行一些正确引导,约束,统一规范,满足正确的开发方式
    
    class Alipay:
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay:
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    a = Alipay()
    a.pay(100)  # 此次消费100元
    
    q = QQpay()
    q.pay(200)  # 此次消费200元
    # 统一支付功能
    
    class Alipay:
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay:
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    def pay(obj, money):  # 设计一个接口
        obj.pay(money)
    
    a = Alipay()
    a1 = Alipay()
    q = QQpay()
    pay(a, 100)
    pay(q, 100)
    pay(a1, 300)
    # 假设要添加一个微信支付
    
    class Alipay:
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay:
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class Wechat:
        def fuqian(self, money):  # 不规范
            print("此次消费%s元" % money)
    
    def pay(obj, money):  # 这是一个隐藏的标准
        obj.pay(money)
    
    c = Wechat()
    c.fuqian(300)
    # 制定一个约束或标准
    # 如果有父类,父类的方法只有一个pass
    # 其实就是制定了一个规范,表明子类一定要有pay()方法
    
    class A:
    
        def pay(self, money):
            pass
    
    class Alipay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class Wechatpay(A):
    
        def pay(self, money):  # 不规范
            print("此次消费%s元" % money)
    
    def pay(obj, money):  # 这是一个隐藏的标准
        obj.pay(money)
    
    c = Wechatpay()
    c.pay(300)
    # 在之前基础上
    class A:
    
        def pay(self, money):
            pass
    
    class Alipay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class Wechatpay(A):
    
        def pay(self, money):  # 不规范
            print("此次消费%s元" % money)
    
    class Unitypay(A):
    
        def zhifu(self, money):
            print("此次消费%s" % money)
    
    def pay(obj, money):  # 这是一个隐藏的标准
        obj.pay(money)
    
    u1 = Unitypay()
    pay(u1, 100)
    
    # 虽然没有这个方法,但是也没有报错,因为父类中有 pay()
    # 侧面说明 A类不是强制性约束,为了起到决定性的作用,可以强制加一个约束
    # 只要不按规则走就直接报错
    # 两种解决方法:
    # 1. 在父类写一个相同的方法,此方法主动抛出一个错误, 提示应该在子类写这个方法
    
    class A:
    
        def pay(self, money):  # 如果子类没有定义这个方法,使用了父类的就报错
            raise Exception("未定义pay方法")
    
    class Alipay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class Wechatpay(A):
    
        def pay(self, money):  # 不规范
            print("此次消费%s元" % money)
    
    class Unitypay(A):
    
        def zhifu(self, money):
            print("此次消费%s" % money)
    
    def pay(obj, money):  # 这是一个隐藏的标准
        obj.pay(money)
    
    
    u1 = Unitypay()
    pay(u1, 100)
    #  File "G:/.../123asda.py", line 203, in pay
    #     raise Exception("未定义pay方法")
    # Exception: 未定义pay方法
    # 解决方法二:
    # 在父类引用元类的抽象方法
    # 在实例化对象的时候就会报错
    from abc import ABCMeta, abstractmethod
    
    class A(metaclass=ABCMeta):
        """
        抽象类,接口类,制定一个规范,强制执行
        """
    
        @abstractmethod
        def pay(self, money):
            pass
    
    class Alipay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class QQpay(A):
    
        def pay(self, money):
            print("此次消费%s元" % money)
    
    class Wechatpay(A):
    
        def pay(self, money):  # 不规范
            print("此次消费%s元" % money)
    
    class Unitypay(A):
    
        def zhifu(self, money):
            print("此次消费%s" % money)
    
    def pay(obj, money):  # 这是一个隐藏的标准
        obj.pay(money)
    
    u1 = Unitypay()
    pay(u1, 100)
    # Traceback (most recent call last):
    #   File "G:/.../123asda.py", line 274, in <module>
    #     u1 = Unitypay()
    # TypeError: Can't instantiate abstract class Unitypay with abstract methods pay
    总结
    约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:

    1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c,所以使⽤频率还是很少的

    2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError
    这样比较专业, ⽽且错误比较明确.(推荐)
    # 类的私有成员
    
    # Python的结构分析
    # 类的结构
    # 分为属性和方法
    
    # 按照公有,私有对类进行划分
    # 私有分为三部分;
    
    class Boss:
        name = "alex"  # 公有静态属性 公有静态字段
        __secretary = ["女1", "男2", "眼膜"]  # 私有普通字段
    
        def __init__(self, username, password):
            self.username = username  # 公有对象属性 公有普通字段
            self.__password = password  # 私有对象属性
    
        def func(self):
            # print(self.__secretary)
            self.__func()
    
        def __func(self):  # 私有方法
            print("经常做一些不可描述的事")
    
    class Boss_son(Boss):
    
        def func(self):
            print(self.__secretary)
    
    # 私有成员:私有静态属性,私有对象属性,私有方法
    
    # 私有静态属性
    # 访问它有三个方法:
    #   1.类外部 Boss.name b1.name
    print(Boss.name)  # alex
    print(Boss.__secretary)  # 不能访问,报错
    
    #   2.类内部 func()访问
    b1 = Boss("alex", 123)  #
    b1.func()  # ['女1', '男2', '眼膜']
    
    #   3.子类
    b2 = Boss_son("other", 123)
    b2.func()
    # 报错

    b3 = Boss("abc", 123)
    b3.__func() # 报错
    b3.func() # 经常做一些不可描述的事
    print(b3.__password) # 报错
    b4 = Boss_son("asd", 123)
    print(b4.__password) # 报错
    # 因此私有方法只能在类内部访问,外部和派生类都不能
    # 然而
    class Boss:
        name = "alex"
        __secretary = ["女1", "男2", "眼膜"]
    
        def __init__(self, username, password):
            self.username = username
            self.__password = password
    
        def func(self):
            self.__func()
    
        def __func(self):
            print("经常做一些不可描述的事")
    
    b1 = Boss("asd", 1234)
    
    print(Boss.__dict__)
    # {'__module__': '__main__', 'name': 'alex',
    # '_Boss__secretary': ['女1', '男2', '眼膜'],
    # '__init__': <function Boss.__init__ at 0x000001BA3EA7AC80>,
    # 'func': <function Boss.func at 0x000001BA3EA7AD90>,
    # '_Boss__func': <function Boss.__func at 0x000001BA3EA7AD08>,
    # '__dict__': <attribute '__dict__' of 'Boss' objects>,
    # '__weakref__': <attribute '__weakref__' of 'Boss' objects>, '__doc__': None}
    
    # print(Boss._Boss__secretary)
    # 私有成员虽然可以在类外部或者派生类可以访问,但是不要这样做
    # 类的方法
    class A:
        name = "barry"
    
        def __init__(self, a, b):  # 双下方法
            self.a = a
            self.b = b
    
        def func(self):  # 实例方法——可通过实例化对象调用的方法,普通方法
            pass
    
        @staticmethod  # 静态方法,跟类和实例化对象没关系
        def func1():
            print(666)
    
        @classmethod  # 类方法
        def func2(cls):
            print(777)
    
        @property     # 将一个方法伪装成属性
        def bim(self):
            print(888)
    # 类方法
    # 类方法是通过类名直接调用的方法,类方法至少要有一个参数,第一个默认是cls
    
    class A:
        name = "barry"
    
        def func(self):  # 实例方法——可通过实例化对象调用的方法,普通方法
            pass
    
        @classmethod  # 类方法
        def func2(cls):
            print(cls)
            print(777)
    
    a = A()  # <class '__main__.A'>
    # print(a)
    # a.func()
    print(A)  # <class '__main__.A'>
    A.func2()  # 777
    
    # 对象可以调用类方法,但是 cls 接收的不是对象的空间,而是类的空间
    a.func2()
    # <class '__main__.A'>
    # 777
    # 类方法在哪使用?
    # 对类中的属性方法直接操作,与对象无关,这时需要使用类方法
    # 原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法
    # 且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。
    # 另外,如果需要继承,也可以定义为类方法。
    # 如下场景:
    # 假设我有一个学生类和一个班级类,想要实现的功能为:
    #     执行班级人数增加的操作、获得班级的总人数;
    #     学生类继承自班级类,每实例化一个学生,班级人数都能增加;
    #     最后,我想定义一些学生,获得班级中的总人数。
    #
    # 思考:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,
    # 但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。
    # 同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。
    
    class ClassTest(object):
        __num = 0
    
        @classmethod
        def addNum(cls):
            cls.__num += 1
    
        @classmethod
        def getNum(cls):
            return cls.__num
    
        # 这里我用到魔术函数__new__,主要是为了在创建实例的时候调用人数累加的函数。
        def __new__(self):
            ClassTest.addNum()
            return super(ClassTest, self).__new__(self)
    
    class Student(ClassTest):
        def __init__(self):
            self.name = ''
    
    a = Student()
    b = Student()
    print(ClassTest.getNum())
    # 静态方法
    # 相似功能,保持一致性,而类本来就是一种功能的划分
    # 静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,
    # 逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,
    # 不会涉及到类中的属性和方法的操作。可以理解为,
    # 静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。
    
    class A:
    
        name = "barry"
    
        @staticmethod
        def func():
            print(666)
    
    a1 = A
    A.func()  # 666
    a1.func()  # 666
    import time
    
    class TimeTest(object):
        def __init__(self, hour, minute, second):
            self.hour = hour
            self.minute = minute
            self.second = second
    
        @staticmethod
        def showTime():
            return time.strftime("%H:%M:%S", time.localtime())
    
    
    print(TimeTest.showTime())  # 12:23:37
    t = TimeTest(2, 10, 10)
    nowTime = t.showTime()
    print(nowTime)  # 12:23:37
    # 类的特殊方法——property
    # property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
    
    # 测体质
    class Bmi:
    
        def __init__(self, kg, m):
            self.kg = kg
            self.m = m
    
        def bmi_test(self):
            return self.kg / (self.m**2)
    
    b1 = Bmi(62, 1.7)
    print(b1.bmi_test())
    
    # 这个逻辑是没问题,但是本来 bmi 是名词,这里却当作动词,有点不太合理
    
    class Bmi:
    
        def __init__(self, kg, m):
            self.kg = kg
            self.m = m
    
        @property
        def bmi_test(self):
            return self.kg / (self.m ** 2)
    
    
    b1 = Bmi(62, 1.7)
    # print(b1.bmi_test())
    print(b1.bmi_test)
    # property——将一个方法伪装成属性,逻辑没变,就只是看起来更合理
    class A:
    
        def __init__(self, username, password):
            self.__username = username
            self.__password = password
    
        # @property
        def name(self):
            return self.__username
    
    a1 = A("alex", 123)
    # print(a1.username)  # 报错
    print(a1.name())  # alex
    # 这样写不合理,name是名词,这里当作动词用
    # 上面加了 @property,就可以这样调用
    
    class A:
    
        def __init__(self, username, password):
            self.__username = username
            self.__password = password
    
        @property
        def name(self):
            return self.__username
    
    a1 = A("alex", 123)
    print(a1.name)
    class A:
    
        def __init__(self, username, password):
            self.__username = username
            self.__password = password
    
        @property
        def name(self):
            return self.__username
    
        # 下面的使用的前提是使用了 @property
        @name.setter
        def name(self, a):
            print(a)
    
    a1 = A("alex", 123)
    print(a1.name)
    a1.name = 666  # 这个赋值运算触发了@name.setter的 name()方法,如果没有赋值,比如上面的 a1.name 那就只是触发了 @property 的 name()
    # 三个组合
    
    class A:
    
        def __init__(self, username, password):
            self.__username = username
            self.__password = password
    
        @property
        def name(self):
            return self.__username
    
        @name.setter
        def name(self, a):
            print(a)
    
        @name.deleter
        def name(self):
            print(888)
    
    a1 = A("alex", 123)
    print(a1.name)
    a1.name = 666  # 触发了@name.setter的name()方法
    del a1.name  # 触发了@name.deleter的name()方法
    class A:
    
        def __init__(self, username, password):
            self.__username = username
            self.__password = password
    
        @property
        def name(self):
            return self.__username
    
        @name.setter
        def name(self, a):
            if type(a) is str:
                self.__username = a
            else:
                print("账号必须是字符串类型")
    
        @name.deleter
        def name(self):
            print(888)
    
    a1 = A("alex", 123)
    a1.name = 666
    # 触发了@name.setter的name()方法,然后进行判断得出结果
    # 账号必须是字符串类型
    
    a1.name = "abc"
    # 注意这里 a1.name 触发了 @name.setter的name()
    # 因此得出的结果是:把之前的 a1.name = "alex" 变为 "abc"
    
    print(a1.name)
    # 上一步因为 self.__username = a, name 已经是 "abc"
    # 这里 a1.name 是触发了@property 的 name()
    
    # 注意上面几个函数的函数名一定要一样!!!
    class Supermarket:
    
        def __init__(self, name, price, discount):
            self.name = name
            self.__price = price
            self.__discount = discount
    
        @property
        def price(self):
            return self.__price * self.__discount
    
        @price.setter
        def price(self, new_price):
            self.__price = new_price
    
    apple = Supermarket("苹果", 8.0, 0.95)
    print(apple.price)
    
    apple.price = 7.5  # 触发 @price.setter 的 name()
    print(apple.price)  # 触发 @property 的name()
    # 为什么要用property
    
    # 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
    
    # 由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
    
    class Foo:
        @property
        def AAA(self):
            print('get的时候运行我啊')
    
        @AAA.setter
        def AAA(self,value):
            print('set的时候运行我啊')
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')
    
    #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    
    
    # 或者:
    class Foo:
        def get_AAA(self):
            print('get的时候运行我啊')
    
        def set_AAA(self,value):
            print('set的时候运行我啊')
    
        def delete_AAA(self):
            print('delete的时候运行我啊')
        AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
    
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
  • 相关阅读:
    <ul>下<li>的list-style属性
    js字符数组转化为数字数组
    ES6学习之— 字符串扩展(二)
    ES6学习之— 字符串扩展
    ES6学习之—— 变量的解构赋值
    ES6学习之——let和const命令
    微信小程序中cover-view踩坑总结
    uni-app 元素在交叉轴(竖直方向)的对齐方式
    uni-app元素对齐方式
    uni-app 页面导入css样式
  • 原文地址:https://www.cnblogs.com/shawnhuang/p/10282265.html
Copyright © 2011-2022 走看看