zoukankan      html  css  js  c++  java
  • day26 python学习 对象的接口,封装,私用属性 property

    # 抽象类和接口类 #**
    #不崇尚接口类
    #python本身支持多继承,没有接口专用的语法。但是我知道接口的概念

    # 接口类:
    # 是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现
    # 接口类不能被实例化,它只能被继承
    # 支持多继承

    from abc import ABCMeta,abstractmethod
    class Payment(metaclass=ABCMeta): #模板,接口类
        @abstractmethod  #装饰接口类中方法的,加上这个装饰器,自动检测子类中的方法名
        def pay(self,money): #模板样式
            pass
    
        # @abstractmethod
        # def get(self):pass
    
    class Apple_Pay(Payment):
        def pay(self,money):
            print('您使用苹果支付支付了%s元'%money)
    
    class Ali_Pay(Payment):
        def pay(self, money):
            print('您使用支付宝支付了%s元' % money)
    
    class WeChat_Pay(Payment):#  调用接口
        def fuqian(self,money):   #这里没有严格按照接口中的形式去写,后续执行它的时候就报错了
            print('您使用微信支付了%s元' % money)
    
    def pay(obj,money):
        return obj.pay(money)
    
    # apple = Apple_Pay()
    # # ali = Ali_Pay()
    #
    # apple.pay(100)
    # pay(apple,100)   #apple.pay(100)
    wechat = WeChat_Pay()
    pay(wechat,200)  
    #执行的时候就会报此错误,  因为def fuqian(self,money):  这里没有严格按照接口的样式来写
    #改成 def pay(self,money)这种形式就可以了
    # TypeError: Can't instantiate abstract class WeChat_Pay with abstract methods pay
    接口——支付宝例子

    封装

    【封装】

             隐藏对象的属性和实现细节,仅对外提供公共访问方式。

    【好处】 

    1. 将变化隔离; 

    2. 便于使用;

    3. 提高复用性; 

    4. 提高安全性;

    【封装原则】

          1. 将不需要对外提供的内容都隐藏起来;

          2. 把属性都隐藏,提供公共方法对其访问。

    私有变量和私有方法

    在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

    私有变量

    class Dog:
        __role='看门狗'  #私用静态属性
        def __func(self):  #私有方法
            print('见人就旺旺')
        def func1(self):
            print(Dog.__role)
            self.__func()
    #g=Dog()
    print(Dog._Dog__role)  #看门狗  #想要在外边调用类中的私有属性只能用此方法,
    # 但是这种方法最好不用,一般不会在外边查看类的私有属性
    # g.func1()
    # print(Dog.__dict__)  #打印类中的属性可以看到没有找到__role 这个,
    # # 说明他隐身了,不能被外界直接看到,调用
    # print(g.__dict__)

    3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

    class A:
        def __func(self):
            print('a')
    class B(A):
        # def __func(self):
        #     print('b')
        def __init__(self):#当Class B 中没有__func()的时候,
            #执行这句话,就会报错AttributeError:
            #  'B' object has no attribute '_B__func'
            #意思为没有这个属性,而没有去引用寻找父类A
            #中的__func  说明这是私有化的,不能被继承
            self.__func()
    
    b=B()

    #私有的
    #私有的静态属性、方法、对象属性
    #使用__名字的方式调用,保证在类内部可以调用,外部不行
    #私有的 不能被继承
    # 当有一个名字,不想被外部使用也不想被子类继承,只想在内部使用的时候就定义私有的

    封装与扩展性

    封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

    #类的设计者
    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)
    >>> r1.tell_area() #使用者调用接口tell_area
    
    
    #类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
    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.tell_area()

    property属性

    什么是特性property

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

    可以将方法伪装成属性

    class Ibm:
        def __init__(self,high,weight):
            self.high=high
            self.weight=weight
        @property
        def func(self):
            return self.high*self.weight
    alxe=Ibm(178,140)
    print(alxe.func)#当使用@property的时候,调用方法的时候
    # 就不用写成alxe.func()这种形式, 因为@property把方法伪装成了属性

    为什么要用property

    将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

    #  商场买苹果水果
    class Goods:
        __discount = 0.8
        def __init__(self,name,price1):
            self.__name=name
            self.__price1=price1
        @property
        def price(self):
            return self.__discount*self.__price1
        @price.setter
        def price(self,new_price):  #*****设置一个与上边同名的函数,在这里修改,即使可以在外部通过apple._Goods__price=20这种形式修改
            # 但是如果将价格改成'aaa'会不安全会。
            if type(new_price) is int:#*****可以在这里可以对传入的数据进行判断,会比直接改安全
                self.__price1=new_price
    apple=Goods('苹果',10)
    print(apple.price)
    apple.price=20#  这里要注意要写成这种形式
    print(apple.price)

    #封装
    # __私有+property
    #让对象的属性变得更安全了
    #获取到的对象的值可以进行一些加工   
    #修改对象的值的同时可以进行一些验证

    一个静态属性property本质就是实现了get,set,delete三种方法

    复制代码
    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
    复制代码

     classmethod

    类方法
    #调用:不需要实例化 直接用类名调用就好
    #定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类
    #什么时候用类方法?
    #需要使用静态变量 且 不需要和对象相关的任何操作的时候

    class Goods:
        __discount=0.7
        @classmethod#  类方法 ,用此方法可以在外部不实例化一个对象就可以修改类
        # 的静态属性,  尤其是修改私有化属性
        def change_discount(cls,new_discount):  #这里的cls指的就是Goods这个类
            cls.__discount=new_discount
        @classmethod
        def get_discount(cls):
            print(cls.__discount)
    Goods.get_discount()
    Goods.change_discount(0.5)#  在外部用类名就可以调用函数然后完成修改,
    Goods.get_discount()

     #静态方法

    静态方法
    #如果这个方法 既不需要操作静态变量
    # 也不需要使用对象相关的操作,
    # 就使用静态方法

    class A:
    @staticmethod
    def func(name): #静态方法
    print(123)
    A.func('alex')

    #面向对象编程:专门为面向对象编程提供的一个方法——staticmethod
    #它完全可以当做普通函数去用,只不过这个函数要通过类名.函数名调用
    #其他 传参 返回值 完全没有区别

    #绑定方法 和 非绑定方法
    
    class A:
        @staticmethod
        def func1(name):  #静态方法
            print(123)
    
        @classmethod
        def func2(cls):  #类方法
            print(123)
    
        def func3(self):pass  #普通方法
    a = A()
    print(a.func1)  #静态方法
    print(a.func2)  #类方法 : 绑定到A类的func
    print(a.func3)  #普通方法:绑定到A类对象的func
    
    #静态方法和类方法 都是直接可以使用类名调用
    #普通方法:对象调用

     静态方法和类方法,也可以使用对象来调用,但是能用类来调用的没有必要实例化一个对象来调用,所以一般用类直接调用

    但是普通方法必须要用对象来调用

  • 相关阅读:
    ExtJS面向对象
    简单理解Ext.DomQuery操作CSS3选择器
    简单理解Ext.extend
    Pycharm去掉项目所有 # 注释
    windows 杀死进程
    mongo官方企业版安装及数据库授权使用
    python中赋值,深拷贝,浅拷贝区别
    测试驱动开发简单理解
    Flask与WSGI
    Python直接改变实例化对象的列表属性的值 导致在flask中接口多次请求报错
  • 原文地址:https://www.cnblogs.com/wangkun122/p/7879947.html
Copyright © 2011-2022 走看看