有几次我不小心修改了函数的输入。由于 Python 没有常量引用,我想知道哪些编码技术可以帮助我避免经常犯这种错误?
例子:
class Table:
def __init__(self, fields, raw_data):
# fields is a dictionary with field names as keys, and their types as value
# sometimes, we want to delete some of the elements
for field_name, data_type in fields.items():
if some_condition(field_name, raw_data):
del fields[field_name]
# ...
# in another module
# fields is already initialized here to some dictionary
table1 = Table(fields, raw_data1) # fields is corrupted by Table's __init__
table2 = Table(fields, raw_data2)
当然,解决方法是在我更改参数之前复制该参数:
def __init__(self, fields, raw_data):
fields = copy.copy(fields)
# but copy.copy is safer and more generally applicable than .copy
# ...
但是很容易忘记。
我有一半的想法是在每个函数的开头复制每个参数,除非该参数可能引用一个复制成本很高的大型数据集,或者除非要修改该参数。这几乎可以消除问题,但会导致在每个函数的开头出现大量无用的代码。此外,它基本上会覆盖 Python 通过引用传递参数的方法,这大概是出于某种原因。
最佳答案
第一条一般规则: 不要修改容器:创建新容器。
所以不要修改传入的字典,使用键的子集创建一个新字典。
self.fields = dict( key, value for key, value in fields.items()
if accept_key(key, data) )
这种方法通常比遍历并删除坏元素更有效。更一般地说,避免修改对象并创建新对象通常更容易。
第二条一般规则: 不要在假冒后修改容器。
您通常不能假设您向其传递数据的容器已经制作了它们自己的副本。因此,不要试图修改您提供给他们的容器。任何修改都应该在传递数据之前完成。一旦您将容器交给其他人,您就不再是它的唯一主人。
第三条一般规则: 不要修改不是您创建的容器。
如果您通过了某种容器,您将不知道还有谁在使用该容器。所以不要修改它。使用未修改的版本或调用规则 1,创建具有所需更改的新容器。
第四条一般规则:(从 Ethan Furman 那里偷来的)
有些函数应该修改列表。那是他们的工作。如果是这种情况,在函数名称中明确说明(例如列表方法追加和扩展)。
综合起来:
当一段代码是唯一可以访问该容器的代码时,它应该只修改该容器。
关于python:无意中修改传递给函数的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7379991/