zoukankan      html  css  js  c++  java
  • python继承实现原理封装property

    ---恢复内容开始---

    在Python中继承顺序有两种:深度优先和广度优先

    没有共同父类的继承:

    class E:
        def test(self):
            print('from E')
    class A(E):  #步骤4 A(E) #from E
        # def test(self):
        #     print('from A') #步骤2 from B
        pass
    class B:
        # def test(self):
        #     print('from B')  #步骤3 from C
        pass
    class C:
        # def test(self):
        #     print('from C')
        pass
    class D(A,B,C):
        # def test(self):
        #     print('from D')  #步骤1 from A
        pass
    t=D() #实例化对象t
    t.test()

    这种类型的继承新式类和经典类的顺序是一样的都是深度优先:D--->A--->E--->B--->C

    共同父类的继承

    class D(object):
        def test(self):
            print('from D')
        # pass
    class C(D):
        def test(self):
            print('from C')
        # pass
    class B(C):
        def test(self):
            print('from B')
        # pass
    class F(D):
        def test(self):
            print('from F')
        # pass
    class E(F):
        def test(self):
            print('from E')
        # pass
    class H(D):
        def test(self):
            print('from H')
        # pass
    class G(H):
        def test(self):
            print('from G')
        # pass
    
    class A(B,E,G):
        def test(self):
            print('from A')
        # pass
    
    obj=A()
    obj.test()
    print(A.mro())
    #经典类不继承object
    class D:
        def test(self):
            print('from D')
        # pass
    class C(D):
        def test(self):
            print('from C')
        # pass
    class B(C):
        def test(self):
            print('from B')
        # pass
    class F(D):
        def test(self):
            print('from F')
        # pass
    class E(F):
        def test(self):
            print('from E')
        # pass
    class H(D):
        def test(self):
            print('from H')
        # pass
    class G(H):
        def test(self):
            print('from G')
        # pass
    
    class A(B,E,G):
        def test(self):
            print('from A')
        # pass
    
    obj=A()
    obj.test()

    在这种类型继承下新式类和经典类的顺序不同。

    新式类采取广度优先:A--->B--->C--->E--->F--->G--->H--->D--->object

    经典类(python2中才有经典类的概念,python3中都是新式类)使用的是深度优先的方式A--->B--->C--->D--->E--->F--->G

    mro():

    只有新式类才具有的方法

    print(A.mro())
    执行结果
    [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.G'>, 
    <class '__main__.H'>, <class '__main__.D'>, <class 'object'>]

    可以通过该方法来查看父类的继承顺序

    子类调用父类的两种方法:

    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
        def foo(self):
            print('from parent')
    
    class Teacher(People):
        def __init__(self,name,age,sex,level,salary):
            # People.__init__(self,name,age,sex)  #方法一
            super().__init__(name,age,sex) #super(Teacher,self).__init__(name,age,sex) #方法二
            self.level=level
            self.salary=salary
        def foo(self):
            super().foo()
            print('from child')

    封装

    封装是一种隐藏的方式,包括数据封装和功能封装,即类里的数据属性和功能属性,隐藏数据和功能是为了限制直接调用,通过人为的添加调用接口进行数据和功能的调用

    封装的变形操作只在类的定义阶段或者对象的实例化阶段

    封装的主要原因:

    1.保护隐私

    2.隔离复杂度,提供简单的接口

    class Teacher:
        def __init__(self,name,salary):
            self.name=name
            self.__salary=salary
        def foo(self):
            print('balabala',self.__salary)
    
    t=Teacher('xiaolan',5000)
    print(t.salary)
    执行结果
    AttributeError: 'Teacher' object has no attribute 'salary'
    print(t.__dict__)
    print(t._Teacher__salary)
    t.foo()
    执行结果
    {'name': 'xiaolan', '_Teacher__salary': 5000}
    5000
    balabala 5000
    class A:
        def foo(self):
            print('from A.foo')
            self.__bar()
        def __bar(self):
            print('from A.bar')
    
    class B(A):
        def bar(self):
            print('from B.bar')
        pass
    b=B()
    b.foo()
    执行结果
    from A.foo
    from A.bar

    在封装后对象的数据属性和函数属性以‘_类名__属性’名的形式保存

    class Foo:
        def __func(self): #_Foo__func
            print('from Foo')
    
    class Bar(Foo):
        def __func(self): #_Bar__func
            print('from Bar')
    b=Bar()
    b._Foo__func()
    b._Bar__func()

    在父类和子类有相同的属性时不会担心子类的属性将父类的属性覆盖调用

    class People:
        def __init__(self,name,age,sex,height,weight):
            self.__name=name
            self.__age=age
            self.__sex=sex
            self.__height=height
            self.__weight=weight
    #name、age、sex、height、weight都是经过封装后保存,所以外部调用的时候没办法直接调用
        def tell_name(self):
            print(self.__name)
    #通过手动创建接口的方式返回name的内容,屏蔽了直接调用
        def set_name(self,val):
            if not isinstance(val,str):
                raise TypeError('type must be str')
            self.__name=val
    #通过手动创建修改接口修改name的属性值,屏蔽了直接调用
        def tell_info(self):
            print('''
            ---------%s info
            name:%s
            age:%s
            sex:%s
            height:%s
            weight:%s
            ''' %(self.__name,
                  self.__name,
                  self.__age,
                  self.__sex,
                  self.__height,
                  self.__weight))
    #通过手动创建接口,展示所有的信息

    property:封装的特性之一

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

    property的构造方法中有个四个参数

    • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
    • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
    • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
    • 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
    class People:
        def __init__(self,name,age,sex,height,weight):
            self.__name=name
            self.__age=age
            self.__sex=sex
            self.__height=height
            self.__weight=weight
    
        @property    #bmi=property(bmi),是一个内置函数,本质就是个装饰器
        def bmi(self):
            res=self.__weight / (self.__height ** 2)
            return res
    xiaobai=People('xiaobai',22,'male',1.80,67)
    print(xiaobai.bmi)
    执行结果
    20.679012345679013
    class People:
        def __init__(self,name,age,sex,height,weight,permission=False):
            self.__name=name
            self.__age=age
            self.__sex=sex
            self.__height=height
            self.__weight=weight
            self.permission=permission
        @property
        def name(self):
            return self.__name
        @name.setter            #支持obj.name='NAME'的方式执行
        def name(self,val):
            if not isinstance(val,str):
                raise  TypeError('must be str')
            self.__name=val
        @name.deleter        #支持del删除操作
        def name(self):
            if not self.permission:
                raise PermissionError('不让删')
            del self.__name
    xiaobai=People('xiaobai',22,'male',1.80,67)
    print(xiaobai.name)
    xiaobai.name='xiaobai Lyn'
    print(xiaobai.__dict__)
    xiaobai.permission=True
    del xiaobai.name
    print(xiaobai.__dict__)
    执行结果
    xiaobai
    {'_People__name': 'xiaobai Lyn', '_People__age': 22, '_People__sex': 'male', '_People__height': 1.8, '_People__weight': 67, 'permission': False}
    {'_People__age': 22, '_People__sex': 'male', '_People__height': 1.8, '_People__weight': 67, 'permission': True}
    class Foo:
    
        def get_bar(self):
            return 'xiaobai'
    
        # *必须两个参数
        def set_bar(self, value): 
            return 'set value' + value
    
        def del_bar(self):
            return 'xiaobai'
    
        BAR = property(get_bar, set_bar, del_bar, 'description...')
    
    obj = Foo()
    
    obj.BAR              # 自动调用第一个参数中定义的方法:get_bar
    obj.BAR = "youzi"     # 自动调用第二个参数中定义的方法:set_bar方法,并将“youzi”当作参数传入
    del Foo.BAR          # 自动调用第三个参数中定义的方法:del_bar方法
    obj.BAE.__doc__      # 自动获取第四个参数中设置的值:description...
  • 相关阅读:
    用Python完成一个汇率转换器
    鸿蒙如何用JS开发智能手表App
    鸿蒙如何用JS开发智能手表App
    SAP Spartacus SplitViewComponent Migration 的一个具体例子
    SAP Spartacus B2B 页面 Popover Component 的条件显示逻辑
    SAP Spartacus 升级时关于 schematics 的更新
    SAP Spartacus B2B 页面 Disable 按钮的显示原理
    SAP Spartacus B2B 页面 Disable Confirmation 对话框的显示原理
    通过 Feature Level 动态控制 SAP Spartacus 的页面显示
    SAP Commerce Cloud Build Manifest Components
  • 原文地址:https://www.cnblogs.com/c491873412/p/7127244.html
Copyright © 2011-2022 走看看