zoukankan      html  css  js  c++  java
  • 面向对象进阶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'
  • 相关阅读:
    26 转义符 re模块 方法 random模块 collection模块的Counter方法
    25 正则表达式
    24 from 模块 import 名字
    24 from 模块 import 名字
    24 from 模块 import 名字
    23 析构方法 items系列 hash方法 eq方法
    21 isinstance issubclass 反射 _str_ _new_ _len_ _call_
    20 属性, 类方法, 静态方法. python2与python3的区别.
    python(1)
    python之字符串格式化
  • 原文地址:https://www.cnblogs.com/Hades123/p/11066773.html
Copyright © 2011-2022 走看看