测开之面向对象进阶篇・《属性自省》

Posted 七月的小尾巴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了测开之面向对象进阶篇・《属性自省》相关的知识,希望对你有一定的参考价值。

私有属性

类里面定义的变量叫做属性,那么类属性有两种,分为:公有属性和私有属性。

私有属性的定义:

  • 单下滑线开头:_attr
  • 双下划线开头:__attr

其中单下划线开头的在外部可以直接访问,双下滑线,在外部访问不了,因为在python底层修改了属性的名称。


在上方图中,我们可以看到,双下滑定义的私有属性,名称被改成了 _Test__test ,如果想要访问该属性方法,需要调用 _Test__test 才能访问。

在python中,并没有偶正真的是私有化支持,但可用下划线得到伪私有。在python 的使用习惯中,通常下划线定义的属性,都不会强制性进行修改。

python中__dict__方法

类调用 __dict__方法,会以字典的形式,返回类所有属性的方法
实例调用 __dict__方法,返回的值实例相关的实例属性。

内置属性__slots__

默认情况下,类的实例有一个字典用于存储属性。这个对于具有很少实例变量的对象会浪费空间。当创建大量实例时,控件消耗可能会变的尖锐。

可以通过在类定义中,定义 __slots__来覆盖默认 __dict__的行为。 __slots__ 声明接受一个实例变量序列,并在每个实例中只保留足够保存每个变量值的空间。因为没有每个实例创建 __dict__ ,所以节省空间。

class MyTest(object):
    pass


t = MyTest()
# 查看该类的所有属性和方法
print(MyTest.__dict__)


class Mytest(object):
    __slots__ = ['attr', 'name']
    
    
t = MyTest()
# 报错,此时 __dict__ 没有创建,被 slots 覆盖了
print(MyTest.__dict__)

我们可以通过 slots 属性来限制类实例的属性,只能绑定 slots 指定的属性。

自定义访问属性

可以定义下面的方法来自定义类实例的属性方法的含义。

  • object.__getatter__ : 当属性查找到在通常的地方,没有找到属性时调用
  • object.__getattribute__: 查找属性时,第一时间会调用该方法
  • object.__setattr__:设置属性方法时,调用该方法设置的属性
  • object.__delattr__:删除属性
class Test:
    def __getattr__(self, item):
        print("没有找到属性,触发 AttributeError 异常时会调用此方法")
        
    def __getattribute__(self, item):
        print("没有设置属性,会调用此方法")
        object.__getattribute__(self, item)
        
    def __delattr__(self, item):
        print("属性被删除了")
        object.__delattr__(self, item)
        
    def __setattr__(self, key, value):
        print("查看属性,首先会进入该方法")
        object.__setattr__(self, key, value)

习题

了解了python的内置属性之后,我们来做一道习题,方便我们更好的理解内置属性。


自定义一个类
1、对这个类创建的对象,进行属性限制,对象只能设置这个三个属性: title money data
2、通过相关机制对设置的属性类型进行限制,title只能设置字符串类型数据
money设置为int类型数据 data可以设置为任意类型
3、通过相关机制实现,data 属性不能进行删除
4、当money设置的值少于0时,确保查询出来的值为0


class MyClass(object):

    __slots__ = ['title', 'money', 'data']

    def __init__(self, title, money, data):
        self.title = title
        self.money = money
        self.data = data

    def __getattr__(self, item):
        return "类中未定义{}属性".format(item)

    def __setattr__(self, key, value):
        # 判断 title 只能设置字符串
        if key == "title":
            if isinstance(value, str):
                super().__setattr__(key, value)
            else:
                raise TypeError("title 属性只能设置字符串")

        # 判断 money 只能设置为 int
        elif key == 'money':
            if isinstance(value, int):
                super().__setattr__(key, value)
            else:
                raise TypeError("money 属性只能设置为 int")

        else:
            super().__setattr__(key, value)

    def __getattribute__(self, item):
        # 获取 money 属性
        if item == 'money':
            value = super().__getattribute__(item)
            # 判断如果 money 的值小于0,则返回0
            if value < 0:
                value = 0
                return value
            
        return super().__getattribute__(item)

    def __delattr__(self, item):
        # 判断当 data 属性被删除时,raise 异常
        if item == 'data':
            raise AttributeError("{0}属性不能被删除".format(item))
        super().__delattr__(item)


if __name__ == '__main__':
    m = MyClass("22", 0, 0)
    print(m.title, m.money1, m.data)
    del m.money

以上是关于测开之面向对象进阶篇・《属性自省》的主要内容,如果未能解决你的问题,请参考以下文章

测开之面向对象进阶篇・《魔术方法》

测开之数据类型进阶篇・第三篇《推导式》

测开之数据类型进阶篇・第四篇《生成器和迭代器》

测开之函数进阶篇・第七篇《装饰器》

测开之函数进阶篇・第六篇《闭包》

测开之数据类型进阶篇・第二篇《字典和集合的原理应用》