如何避免意外创建类属性

eSu*_*ake 1 python-3.x

我知道座右铭是“我们都同意这里的成年人。”

但这是我花了一天时间解决的一个问题。我通过了一个包含 100 多个属性的类。我已经指定其中之一被称为“run_count”。前端有一个地方可以输入run_count。

不知何故,人们决定将前端/后端包称为“run_iterations”。

所以,我的问题是我正在编写单元测试软件,我这样做了:

passed_parameters.run_count = 100
result = do_the_thing(passed_parameters)
assert result == 99.75
Run Code Online (Sandbox Code Playgroud)

现在,问题当然是 Python 愿意让我设置这个名为“run_count”的“新”属性。但是,在深入研究 10 个级别的代码后,我发现函数“do_the_thing”(显然)从不查看“run_count”,而是使用“passed_pa​​ramaters.run_iterations”。

是否有一些简单的方法可以避免允许自己在类中创建新属性或字典中的新条目,当您天真地假设您知道属性名称(或字典键),并意外地创建了一个从未创建过的新条目时被人看?

在理想的世界中,无论多么动态,Python 都允许您“锁定”一个对象或实例。然后,尝试为不存在的属性设置新值会引发属性错误,让您知道您正在尝试更改不存在的内容,而不是让您创建一个从未使用过的新属性。

Jos*_*aCS 5

使用__setattr__, 并检查属性是否存在,否则抛出错误。如果这样做,当您在 中定义这些属性时会收到错误消息__init__,因此您必须解决这种情况。我找到了 4 种方法。首先,在类中定义这些属性,这样,当您尝试设置它们的初始值时,它们将已经被定义。第二,object.__setattr__直接打电话。第三,添加第四个布尔参数来__setattr__指示是否绕过检查。第四,将先前的布尔标志定义为类范围,将其设置为True,初始化字段并将标志设置回False。这是代码:

代码

class A:
  f = 90
  a = None

  bypass_check = False

  def __init__(self, a, b, c, d1, d2, d3, d4):
    # 1st workaround
    self.a = a

    # 2nd workaround
    object.__setattr__(self, 'b', b)

    # 3rd workaround
    self.__setattr__('c', c, True)

    # 4th workaround
    self.bypass_check = True 
    self.d1 = d1
    self.d2 = d2
    self.d3 = d3
    self.d4 = d4
    self.bypass_check = False

  def __setattr__(self, attr, value, bypass=False):
    if bypass or self.bypass_check or hasattr(self, attr):
      object.__setattr__(self, attr, value)
    else:
      # Throw some error
      print('Attribute %s not found' % attr)

a = A(1, 2, 3, 4, 5, 6, 7)
a.f = 100
a.d1 = -1
a.g = 200
print(a.f, a.a, a.d1, a.d4)
Run Code Online (Sandbox Code Playgroud)

输出

Attribute g not found
100 1 -1 7
Run Code Online (Sandbox Code Playgroud)