如何防止设置类成员值时的拼写错误?

8 投票
3 回答
833 浏览
提问于 2025-04-16 00:12

考虑以下示例:

class A():
    def __init__(self):
        self.veryImportantSession = 1

a = A()
a.veryImportantSession = None # ok

# 200 lines below
a.veryImportantSessssionnnn = 2 # I wanna exception here!! It is typo!

我该怎么做才能在尝试设置一个在 __init__ 中没有初始化的成员时抛出异常呢?

上面的代码在执行时不会出错,但让我在调试问题时感到很烦恼。

就像处理字符串一样:

>>> s = "lol"
>>> s.a = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'a'

谢谢!

3 个回答

2

防止打错字的最好方法是使用一些工具,比如pyflakespylint。这些工具会检查你的代码,告诉你像变量a.superImportantSesssssionnnn这样的东西是否没有被再次使用,还有很多其他的检查。

如果你坚持要在代码中处理这个问题,有两个选择:

  • 可以使用__slots__ -- __slots__的主要目的是为了节省内存,特别是当你需要创建成百上千甚至上百万个对象时,能让你的对象占用的内存尽可能小。如果选择这个方法,记得把__weakref__也加到允许的名称中,这样弱引用就能继续工作。

  • 可以使用__setattr__ -- __setattr__的主要目的是允许代码运行来验证、处理数据,或者把给定的数据转换成正确的格式以便存储。

再强调一下,上面这两个选项并不是用来当拼写检查器的。如果你试图限制代码的可用性,只允许使用你自己用的那些属性名称,可能在别人尝试支持你没想到的用例时,会让人觉得不太方便。

3

你可以定义一个叫做 __slots__ 的类变量。想了解更多信息,可以查看 语言参考

__slots__ 只在新式类中有效,所以在这个例子中你需要写成 class A(object),而不是 class A

class A(object):
    __slots__ = ['x']
    def __init__(self):
        self.x = 1

>>> a = A()
>>> a.x = 2
>>> a.y = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'y'
8

你可以重写 __setattr__ 这个方法,只允许使用一个定义好的名字列表中的属性名。

class A(object):
    def __setattr__(self, name, value):
        allowed = ('x',)
        if name in allowed:
            self.__dict__[name]  = value
        else:
            raise AttributeError('No attribute: %s' % name) 

具体操作如下:

>>> a = A()
>>> a.x = 5
>>> a.other = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "myc.py", line 7, in __setattr__
    raise AttributeError('No attribute: %s' % name)
AttributeError: No attribute: other   

不过,正如 msw 所说,试图让Python的行为更像Java或C++通常不是个好主意,这样会失去很多Python的优势。如果你担心会打错字而被忽略,那么花时间为你的代码写单元测试要比试图限制类的使用要好得多。

撰写回答