直接在函数中更改对象在 python 中是反模式吗?
Change object directly in function is anti-pattern in python?
假设我们必须获取一些值并从函数中更改它。
方式一
def change_b(obj):
obj['b'] = 4
result = {'a': 1, 'b': 2}
change_b(obj=result)
print(result)
如您所知,函数 change_b()
直接在函数中更改 result['b']
的值。
方式二
from copy import deepcopy
def change_b(obj):
temp = deepcopy(obj)
temp['b'] = 4
return temp
result = {'a': 1, 'b': 2}
result = change_b(obj=result)
print(result)
但是方法 2 将对象复制到新对象并替换新对象的值。
所以,原始对象不会影响任何东西。 (另外,没有副作用)
也许 Way-2 更安全,因为它不会改变原始对象。
我想知道哪一个更通用和 pythonic 方式?
谢谢。
总结
如果 API 明确表示它正在更新其输入,则 Way-1 很好且可取:add_route(route_map, new_route)
.
如果 API 主要是为了做其他事情,那么 Way-2 可以避免意外的副作用。
Python
中的示例
Way-1: dict.update() 和 list.sort() 进行就地更新,因为这是他们的主要工作。
Way-2:内置的 sorted() 函数从其输入中生成一个新的排序列表,注意不要更改.大致来说,它是这样做的:
def sorted(iterable, *, key=None, reverse=False):
result = list(iterable) # copy the data
result.sort(key=key, reverse=reverse) # in-place sort
return result
希望澄清何时复制以及何时就地变异:-)
"Explicit is better than implicit"
...
"In the face of ambiguity, refuse the temptation to guess."
- PEP 20
在函数内修改参数不一定是坏事。 糟糕的是没有充分的理由这样做。如果您清楚函数名称和文档表明参数将在函数内被修改,那很好。如果函数在没有任何迹象表明它正在尝试这样做的情况下修改了参数,那就不太好了。
在这种情况下,您的 Way-1 更简单、更明确。很明显变量是要改变的,改变的方式看代码就可以很容易地确定。
Way-2更糟,因为名字change_b
会暗示参数要被修改,而不是。在不修改原始参数的情况下返回参数的修改版本是 python 中的标准设计模式,但最好对其进行明确说明。
例如,python的内置set
数据结构有对应的方法:set.difference(other)
和set.difference_update(other)
。在这两种情况下,它们都做同样的事情:计算这个集合和给定集合之间的差异。在前一种情况下,返回该结果而不修改原始集。在后一种情况下,原始集被修改并且没有返回任何内容。弄清楚哪个做什么是非常简单的。
一般来说,您可能应该避免更新值 和 返回相同的值,因为这更不明确。请注意大多数 python 方法是如何做一个或另一个,而不是两者(那些同时做这两个事情的方法,如 list.pop()
,明智地这样做,返回的对象不是被修改的对象)。
据我了解 Python,解决此问题的最 Pythonic 方法是非常清楚发生了什么。只要你做到了,我相信这不重要。
my_dict = {'a': 3, 'b': 4}
double_values_in_dict(my_dict)
# Some other code
这是一个人为设计的示例,但即使不包含方法定义,也很清楚这里打算发生什么。
不清楚的是,如果您将 double_values_in_dict
的 return 值分配给新变量;那时我不知道您可能对原始 dict
对象做了什么,我必须开始深入研究该方法以弄清楚它的实际工作原理。
假设我们必须获取一些值并从函数中更改它。
方式一
def change_b(obj):
obj['b'] = 4
result = {'a': 1, 'b': 2}
change_b(obj=result)
print(result)
如您所知,函数 change_b()
直接在函数中更改 result['b']
的值。
方式二
from copy import deepcopy
def change_b(obj):
temp = deepcopy(obj)
temp['b'] = 4
return temp
result = {'a': 1, 'b': 2}
result = change_b(obj=result)
print(result)
但是方法 2 将对象复制到新对象并替换新对象的值。
所以,原始对象不会影响任何东西。 (另外,没有副作用)
也许 Way-2 更安全,因为它不会改变原始对象。
我想知道哪一个更通用和 pythonic 方式?
谢谢。
总结
如果 API 明确表示它正在更新其输入,则 Way-1 很好且可取:add_route(route_map, new_route)
.
如果 API 主要是为了做其他事情,那么 Way-2 可以避免意外的副作用。
Python
中的示例Way-1: dict.update() 和 list.sort() 进行就地更新,因为这是他们的主要工作。
Way-2:内置的 sorted() 函数从其输入中生成一个新的排序列表,注意不要更改.大致来说,它是这样做的:
def sorted(iterable, *, key=None, reverse=False):
result = list(iterable) # copy the data
result.sort(key=key, reverse=reverse) # in-place sort
return result
希望澄清何时复制以及何时就地变异:-)
"Explicit is better than implicit"
...
"In the face of ambiguity, refuse the temptation to guess."
- PEP 20
在函数内修改参数不一定是坏事。 糟糕的是没有充分的理由这样做。如果您清楚函数名称和文档表明参数将在函数内被修改,那很好。如果函数在没有任何迹象表明它正在尝试这样做的情况下修改了参数,那就不太好了。
在这种情况下,您的 Way-1 更简单、更明确。很明显变量是要改变的,改变的方式看代码就可以很容易地确定。
Way-2更糟,因为名字change_b
会暗示参数要被修改,而不是。在不修改原始参数的情况下返回参数的修改版本是 python 中的标准设计模式,但最好对其进行明确说明。
例如,python的内置set
数据结构有对应的方法:set.difference(other)
和set.difference_update(other)
。在这两种情况下,它们都做同样的事情:计算这个集合和给定集合之间的差异。在前一种情况下,返回该结果而不修改原始集。在后一种情况下,原始集被修改并且没有返回任何内容。弄清楚哪个做什么是非常简单的。
一般来说,您可能应该避免更新值 和 返回相同的值,因为这更不明确。请注意大多数 python 方法是如何做一个或另一个,而不是两者(那些同时做这两个事情的方法,如 list.pop()
,明智地这样做,返回的对象不是被修改的对象)。
据我了解 Python,解决此问题的最 Pythonic 方法是非常清楚发生了什么。只要你做到了,我相信这不重要。
my_dict = {'a': 3, 'b': 4}
double_values_in_dict(my_dict)
# Some other code
这是一个人为设计的示例,但即使不包含方法定义,也很清楚这里打算发生什么。
不清楚的是,如果您将 double_values_in_dict
的 return 值分配给新变量;那时我不知道您可能对原始 dict
对象做了什么,我必须开始深入研究该方法以弄清楚它的实际工作原理。