python:无意中修改传递给函数的参数

max*_*max 12 python coding-style

有几次我意外地将输入修改为一个函数.由于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)
Run Code Online (Sandbox Code Playgroud)

当然修复是在更改之前复制参数:

  def __init__(self, fields, raw_data):
    fields = copy.copy(fields)
    # but copy.copy is safer and more generally applicable than .copy 
    # ...
Run Code Online (Sandbox Code Playgroud)

但它很容易忘记.

我正在考虑在每个函数的开头创建每个参数的副本,除非参数可能引用大型数据集,复制可能很昂贵,或者除非要修改参数.这几乎可以消除这个问题,但是在每个函数开始时会导致大量无用的代码.此外,它基本上会覆盖Python通过引用传递参数的方法,这可能是出于某种原因而完成的.

Win*_*ert 13

第一个一般规则: 不要修改容器:创建新的容器.

因此,不要修改传入的字典,使用键的子集创建新的字典.

self.fields = dict( key, value for key, value in fields.items()
                     if accept_key(key, data) )
Run Code Online (Sandbox Code Playgroud)

这些方法通常稍微更有效,然后通过并删除坏元素.更一般地说,它通常更容易避免修改对象而是创建新对象.

第二个一般规则: 在传递容器后不要修改容器.

您通常不能假设您已传递数据的容器已创建自己的副本.因此,请勿尝试修改您提供的容器.在处理数据之前应该进行任何修改.一旦你将容器传递给其他人,你就不再是它的唯一主人了.

第三个一般规则: 不要修改你没有创建的容器.

如果你通过某种容器,你不知道还有谁在使用容器.所以不要修改它.使用未修改的版本或调用rule1,创建具有所需更改的新容器.

第四条一般规则:(从Ethan Furman偷来)

一些函数应该修改列表.那是他们的工作.如果是这种情况,请在函数名称中明确表示(例如list方法追加和扩展).

把它们放在一起:

一段代码只应修改容器,因为它是唯一可以访问该容器的代码段.

  • 第四个一般规则:如果你的函数*修改了传入的容器,那么在函数名中创建那个apparant(例如`list`方法`append`和`extend`). (2认同)