• Python __slots__限制动态添加变量


    Python是一种非常灵活的动态语言,有时感觉太灵活以至于不知道遵循什么样的规则去驾驭。不过Python已经是非常完备的语言,想实现什么样的功能都是有方法的,而且也很容易,比如限制一个类动态添加成员变量。

    一般情况下,我们定义完一个类,如果不加任何限制,还可以动态地为该类的对象或该类添加成员变量。

     1 class Employee:
     2     def __init__(self,name=''):
     3         self.name = name
     4 
     5 if __name__ == "__main__":
     6     try:
     7         employee1 = Employee('Bob')
     8         #动态为一个对象添加成员变量
     9         employee1.tel = '11111111'
    10         print(employee1.name,employee1.tel)
    11         employee2 = Employee('Tom')
    12         #employee2对象没有tel成员变量
    13         print(employee2.name,employee2.tel)
    14     except AttributeError as e:
    15         print(e)
    16     #动态为一个类添加成员变量
    17     Employee.tel = []
    18     print(employee2.name,employee2.tel)
    19 
    20 #Bob 11111111
    21 #'Employee' object has no attribute 'tel'
    22 #Tom []

    看起来很方便,不过如果我们如果不想使用者破坏类的结构、随便添加成员变量,要怎么做呢?

    答案是,可以使用__slots__对象。

    在类中,__slots__是一个以元组形式被定义的,只有在元组里的属性,才可以被赋值,不在元组里的属性赋值时会报错。

     1 class Employee:
     2     __slots__ = ('name')
     3     def __init__(self,name=''):
     4         self.name = name
     5 
     6 if __name__ == "__main__":
     7     employee1 = Employee('Bob')
     8     #动态为一个对象添加成员变量,但不在__slots__定义的元组内,会报异常
     9     employee1.tel = '11111111'
    10     print(employee1.name,employee1.tel)
    11 
    12 #AttributeError: 'Employee' object has no attribute 'tel'

    __solts__不能被子类继续,如果想限制子类的成员变量,子类也要定义__slots__变量,同时会继承父类的__slots__

     1 class Employee:
     2     __slots__ = ('name')
     3     def __init__(self,name=''):
     4         self.name = name
     5 
     6 class Manager1(Employee):
     7     pass
     8 class Manager2(Employee):
     9     __slots__ = ('addr')
    10 
    11 if __name__ == "__main__":
    12     manager1 = Manager1('Bill')
    13     #动态为一个对象添加成员变量
    14     manager1.tel = '22222222'
    15     print(manager1.name,manager1.tel)
    16     manager2 = Manager2()
    17     manager2.name = 'David'
    18     manager2.addr = 'BJ'
    19     print(manager2.name,manager2.addr)
    20     #动态为一个对象添加成员变量,不在__slots__里,会报异常
    21     manager2.tel = '33333333'
    22     print(manager2.tel)
    23 
    24 #Bill 22222222
    25 #David BJ
    26 #AttributeError: 'Manager2' object has no attribute 'tel'

    如果想进一步限制对成员变量的使用,可以重载__setattr__, __getattr__,__getattribute__函数,__setattr__函数可以在赋值前拦截;__getattr__在找不到属性时被调用;__getattribute__则在获取属性值时无条件被调用,同时__getattr__不再被调用。注意不要在__getattribute__里使用self.attr来访问变量,这会导致无限递归循环。

    class Employee:
        __slots__ = ('name')
        def __init__(self,name=''):
            self.name = name
    
    class Manager2(Employee):
        __slots__ = ('addr')
        def __setattr__(self,name,value):
            if name == 'tel':
                raise AttributeError('manager has no tel')
            object.__setattr__(self, name, value)
        def __getattr__(self,name):
            if name == 'tel':
                return 0
            object.__getattribute__(self, name)
    if __name__ == "__main__":
        manager2 = Manager2('Jone')
        manager2.name = 'David'
        manager2.addr = 'BJ'
        try:
            manager2.tel = '11111111'
        except Exception as e:
            print(e)
        print(manager2.name,manager2.addr,manager2.tel)
    
    #manager has no tel
    #David BJ 0

     参考资料:

    https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868200605560b1bd3c660bf494282ede59fee17e781000

    https://www.cnblogs.com/rainfd/p/slots.html

  • 相关阅读:
    JavaScript-循环
    JavaScript-条件判断
    JavaScript-对象
    Vue快速入门
    Typora中的MarkDown语法
    (已解决)ERROR: In file './docker-compose.yml', service 'networks' must be a mapping not an array
    mac常用快捷键
    Python数据分析
    Python列表和元组
    Selenium工具爬取商品
  • 原文地址:https://www.cnblogs.com/zhaoshizi/p/9384430.html
Copyright © 2020-2023  润新知