self.arg = arg 和 self.__dict__['arg'] = Python 中的 arg 之间的区别



当我进行类定义时,我总是去

Class A(object):
    def __init__(self, arg):
        self.arg = arg
    def print_arg(self):
        print(self.arg)

a = a('Hello')

打印a.arg

'你好'

但是我在第133和134行中发现的东西 https://github.com/pylons/webob/blob/master/src/webob/request.py让我认为我在A级A中所做的事情有什么区别:

Class B(object):
    def __init__(self, arg):
        self.__dict__['arg'] = arg
    def print_arg(self):
            print(self.arg)

b = b('Goodbye')

打印b.arg

'再见'

有几个主要含义:

  1. 使用self.__dict__添加属性绕开__setattr__,该属性可能会与某些地方可能要避免的某种行为重载。

    In [15]: class Test(object):
        ...:     def __init__(self, a, b):
        ...:         self.a = a
        ...:         self.__dict__['b'] = b
        ...:     def __setattr__(self, name, value):
        ...:         print('Setting attribute "{}" to {}'.format(name, value))
        ...:         super(Test, self).__setattr__(name, value)
        ...:               
    In [16]: t = Test(1, 2)
    Setting attribute "a" to 1
    

    您可以看到,属性b没有打印任何东西。

  2. 在某些情况下它的灵活性降低

    In [9]: class WithSlots(object):
       ...:     __slots__ = ('a',)
       ...:     def __init__(self, a):
       ...:         self.__dict__['a'] = a
       ...:         
    In [10]: instance = WithSlots(1)
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-10-c717fcc835a7> in <module>()
    ----> 1 instance = WithSlots(1)
    <ipython-input-9-2d23b670e0fc> in __init__(self, a)
          2     __slots__ = ('a',)
          3     def __init__(self, a):
    ----> 4         self.__dict__['a'] = a
          5 
    AttributeError: 'WithSlots' object has no attribute '__dict__'
    In [11]: class WithSlots(object):
        ...:     __slots__ = ('a',)
        ...:     def __init__(self, a):
        ...:         self.a = a
        ...:         
        ...:         
    In [12]: instance = WithSlots(1) # -> works fine
    
  3. 您不能在类定义之外执行此操作。

总体目的是规避python设置变量的默认方式。该技术的特定用例是隐藏属性值。比较以下两个类:

class Exposed:
    def __init__(self, x):
        self._x = x
    @property
    def x(self):
        rerurn self._x
class Hidden:
    def __init__(self, x):
        self.__dict__['x'] = x
    @property
    def x(self):
        return self.__dict__['x']

两个类都定义了只读属性x。但是,第一个最终带有额外的_x属性,该属性由用户直接修改,而第二个则没有。虽然在Python中没有什么是真正的私人,但第二类可以更好地近似真正的读取值,并且不会扩散不必要的可见属性。

没有查看request中的代码,对对象的__dict__的直接访问可能是有目的地放置在该对象的正常属性查找层次结构的地方。

最新更新