如何防止在Python中错误命名对象属性?
有个朋友在学习Python的时候遇到了麻烦,现在他觉得这个语言有点问题。
他在用一个库的时候,修改了一个对象的属性值(这个类是在那个库里的),但是他把属性名写错了。结果他花了很长时间才搞清楚问题出在哪里。因此,他对Python的不满就是,它允许人们不小心给对象添加错误的属性。
单元测试并不能解决这个问题。因为我们通常不会针对正在使用的API写单元测试。虽然可以为这个类创建一个模拟对象,但这个模拟对象也可能会有同样的拼写错误或者对属性名的错误理解。
可以使用__setattr__()
来防止这种情况发生,但据我所知,似乎没有人这么做。
我能告诉我朋友的唯一一点是,经过几年的全职Python编程,我不记得自己曾经遇到过这个问题。我还能告诉他什么呢?
8 个回答
你可以使用 __slots__
这个类属性来限制实例可以拥有的属性。如果你试图设置一个没有明确列出的属性,就会出现 AttributeError
错误。不过,在子类化的时候会有一些复杂的情况。想了解更多细节,可以查看 Python 数据模型参考。
有一些代码分析工具,比如 pylint,如果你在 __init__
方法之外添加属性,它会给你发出警告。PyDev 对这个功能支持得很好。其实,这种错误用调试工具也很容易找到。
“改变一个对象的属性值”可能会引发问题。这是大家都知道的事情。你现在也知道了。这并不是说这个语言有问题,而是你在动态语言编程中学到了一个重要的教训。
单元测试绝对能发现这个问题。你并不需要模拟所有的库类。有些人说,只有在完全隔离的情况下测试才算单元测试。这种说法很傻。你必须信任库模块——这是你架构的一部分。与其模拟它们,不如直接使用它们。(为你自己新开发的库写模拟是很重要的。模拟那些需要高成本API调用的库也很重要。)
在大多数情况下,你可以(而且应该)用真实的库模块来测试你的类。这能帮你发现拼写错误的属性名。
而且,现在你知道属性是动态的,验证属性是否存在变得非常简单。怎么做呢?
使用交互式Python在写太多代码之前先探索一下类。
记住,Python不是Java,也不是C。你可以交互式地执行Python,立刻确认你是否拼错了什么。在没有进行任何交互确认的情况下写大量代码——简单来说——是错误的使用Python方式。
稍微进行一些交互式探索就能找到拼写错误的属性名。
最后,对于你自己的类,你可以把可更新的属性封装成属性。这让调试拼写错误的属性名变得更容易。再说一次,你知道要检查这个。你可以使用交互式开发来确认属性名。
在使用__setattr__
时会产生问题。在某些情况下,我们确实需要给对象添加属性。为什么?因为在某些特殊情况下,维护更多的状态信息比创建一个完整的子类要简单。
你还可以说其他事情:
我曾经遇到过一个C程序,根本无法正常工作,因为______
。[在这里插入任何已知的C语言问题,比如没有数组边界检查] 这是否意味着C语言致命缺陷?
我曾经遇到过一个数据库管理员,他改了一个列名,结果所有的SQL都坏了。单元测试所有这些真是痛苦。这是否意味着关系数据库有致命缺陷?
我曾经遇到过一个系统管理员,他改了一个目录的权限,我的应用程序坏了。几乎不可能找到问题。这是否意味着操作系统有致命缺陷?
我曾经遇到过一个COBOL程序,有人改了拷贝本,忘了重新编译程序,而我们无法调试,因为源代码看起来完美。然而,COBOL确实是有致命缺陷的,所以这个例子并不好。