如何防止设置类成员值时的拼写错误?
考虑以下示例:
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 个回答
防止打错字的最好方法是使用一些工具,比如pyflakes或pylint。这些工具会检查你的代码,告诉你像变量a.superImportantSesssssionnnn
这样的东西是否没有被再次使用,还有很多其他的检查。
如果你坚持要在代码中处理这个问题,有两个选择:
可以使用
__slots__
--__slots__
的主要目的是为了节省内存,特别是当你需要创建成百上千甚至上百万个对象时,能让你的对象占用的内存尽可能小。如果选择这个方法,记得把__weakref__
也加到允许的名称中,这样弱引用就能继续工作。可以使用
__setattr__
--__setattr__
的主要目的是允许代码运行来验证、处理数据,或者把给定的数据转换成正确的格式以便存储。
再强调一下,上面这两个选项并不是用来当拼写检查器的。如果你试图限制代码的可用性,只允许使用你自己用的那些属性名称,可能在别人尝试支持你没想到的用例时,会让人觉得不太方便。
你可以定义一个叫做 __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'
你可以重写 __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的优势。如果你担心会打错字而被忽略,那么花时间为你的代码写单元测试要比试图限制类的使用要好得多。