• 面向对象进阶2


    类的封装

    封装是什么

    封装就是把东西放在一起然后封起来,别人就拿不到了

    封装的两个层面

    第一个层面

    • 第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装

    第二个层面

    • 第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

    在python中用双下划线的方式实现隐藏属性(设置成私有的)

    类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

    class A:
        __count = 0
        
        def __init__(self,name):
            self.name = name
            
        def __f1(self):
            print('from A.__f1')
            A.__count += 1
            print(A.__count)
            
            
        def bar(self):
            self.__f1()
            
    a = A('hades')
    print(a.__count)  # 报错,拿不到__count,这是封装在类内部,外部不能调用
            
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-59-3b81c13cf856> in <module>
         15 
         16 a = A('hades')
    ---> 17 print(a.__count)  # 报错,拿不到__count,这是封装在类内部,外部不能调用
         18 
    
    
    AttributeError: 'A' object has no attribute '__count'
    
    a.bar()  # 这是在类内部进行操作,才可以拿到
    
    from A.__f1
    1
    
    • 注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了

    这种变形需要注意的是:

    1. 这种机制并没有真正意义上的限制我们从外部直接访问属性,我们可以通过实例化对象名._类名__属性名进行访问
    a._A__count += 10  # 此时的_A__count是对象a的属性,相当于a._A_count = a._A__count + 10
                       # 此时等号后面的a._A__count会先去a这个对象进行查找_A__count,找不到就去类里面找,找到了就进行运算
    print(a.__dict__)
    print(a._A__count)
    
    {'name': 'hades', '_A__count': 11}
    11
    
    a._A__f1()   # 这个访问的是A._A__count
    
    from A.__f1
    2
    
    1. 变形的过程只在类的定义的时候发生一次,在定义后的赋值操作,不会变形

    私有模块

    同样的,我们模块也是有私有属性的,也是通过加下划线的方式进行封装,但只是一个下划线

    # m1.py
    
    _X = 10
    
    y = 20
    
    # m2.py
    
    from m1 import *
    
    print(y)  # 20
    
    print(_X) 进行报错
    
    from m1 import _X
    
    print(_X) # 10
    

    类的property特性

    什么是property特性

    • property装饰器用于将被装饰的方法伪装成一个数据类型,在使用的时候可以不加括号而直接使用

    注意:这种只适合类内部除了self参数外没有其他参数的函数

    class Foo:
        def func(self):
            print('from func')
           
        @property
        def pro(self):
            print('from pro')
            
            
    f = Foo()
    f.func()  # 正常调用类的方法
    f.pro  # 将类的方法当成属性使用
    
    from func
    from pro
    

    property属性的定义和调用要注意一下几点:

    1. 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数

    2. 调用时,无需括号

    property属性的两种方式

    1. 装饰器:在方法上应用装饰器
    2. 类属性:在类中定义值为property对象的类属性

    装饰器

    1. 经典类只具有@property这一种方法

    2. 新式类中具有@property,@方法名.setter,@方法名.deleter这三种方法

    class Goods:
        def __init__(self, name):
            self.name = name
            self.goods_price = 125
    
        @property
        def price(self):
            print(self.goods_price)
    
        @price.setter
        def price(self, value):
            self.goods_price = value
            print('from good_price')
            return self.goods_price
    
        @price.deleter
        def price(self):
            del self.goods_price
    
    
    obj = Goods('clothes')
    print(obj.__dict__)
    obj.price  # 自动调用@property装饰的函数
    
    obj.price = 250 # 自动调用@price.setter装饰的函数
    obj.price
    
    del obj.price # 自动调用@price.deleter装饰的函数
    print(obj.__dict__)
    
    {'name': 'clothes', 'goods_price': 125}
    125
    from good_price
    250
    {'name': 'clothes'}
    

    类与对象的绑定方法和非绑定方法

    绑定方法

    对象的绑定方法

    在类中,没有被任何装饰器修饰的方法就是 绑定到对象的方法,这类方法专门为对象定制

    class People:
        country = 'china'
        
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
        def discribe(self):
            print(f'{self.name} is {self.age} years old')
            
    p = People('hades',27)
    p.discribe()   # 通过对象进行调用
    
    hades is 27 years old
    

    discribe即为对象的绑定方法,这个方法不在对象的名称空间,而是在类的名称空间中

    • 通过对象调用绑定到对象的方法,会有一个自动传值的过程,即自动将当前对象传递给方法的第一个参数(self,一般都叫self,也可以写成别的名称);若是使用类调用,则第一个参数需要手动传值。
    People.discribe(p)  # 通过类进行调用,就需要把对象传进去
    
    hades is 27 years old
    

    类的绑定方法

    • 类中使用 @classmethod 修饰的方法就是绑定到类的方法。这类方法专门为类定制。通过类名调用绑定到类的方法时,会将类本身当做参数传给类方法的第一个参数。
    class A:
        count = 1
        
        @classmethod
        def f1(cls,obj):
            print(cls.count)
            cls.f2(obj)
            
        def f2(self):
            print(self,'from f2')
            
    a = A()
    
    A.f1(a)
    
    1
    <__main__.A object at 0x0000024E75EDDBA8> from f2
    
    a.f1(a)
    
    1
    <__main__.A object at 0x0000024E75EDDBA8> from f2
    

    非绑定方法

    • 在类内部使用 @staticmethod 修饰的方法即为非绑定方法,这类方法和普通定义的函数没有区别,不与类或对象绑定,谁都可以调用,且没有自动传值的效果。
    class A:
        count = 1
        
        def __init__(self, name, age):
            self.name = name
            self.age = age
        
        @classmethod
        def f1(cls,obj):
            print(cls.count)
            cls.f2(obj)
            
        @staticmethod
        def f2(self):
            print(self,'from f2')
            
            
    a = A('hades',27)
    
    A.f2(a)
    a.f2()  # 报错,因为没有进行传参,也就证明了这个方法不是对象的绑定方法
    
    <__main__.A object at 0x0000024E760BD198> from f2
    
    
    
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
    <ipython-input-96-632f4a11ba55> in <module>
         19 
         20 A.f2(a)
    ---> 21 a.f2()  # 报错,因为没有进行传参,也就证明了这个方法不是对象的绑定方法
    
    
    TypeError: f2() missing 1 required positional argument: 'self'
  • 相关阅读:
    Lambda Expression in C#
    DirectorySearcher LDAP
    摘录 LDAP
    The return types for the following stored procedures could not be detected
    无法调试存储过程,无法启动T-SQL调试
    根据窗口句柄显示窗体
    还原数据库时提示空间不足
    xml格式发送
    ../ 上一级目录
    匿名函数 invoke
  • 原文地址:https://www.cnblogs.com/Hades123/p/11066773.html
Copyright © 2020-2023  润新知