简体   繁体   English

直接在 function 中更改 object 是 python 中的反模式?

[英]Change object directly in function is anti-pattern in python?

Assume that we have to get some value and change it from function.假设我们必须得到一些值并将其从 function 更改。

Way-1方式一

def change_b(obj):
    obj['b'] = 4


result = {'a': 1, 'b': 2}
change_b(obj=result)
print(result)

As you know that function change_b() change result['b'] 's value directly in function.如您所知,function change_b change_b()直接在 function 中更改result['b']的值。

Way-2方式二

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)

But Way-2 copying object to new object and replace value from new object.但是方式 2将 object 复制到新的 object 并从新的 object 替换值。

So, original object doesn't affect anything.所以,原来的 object 不会影响任何东西。 (Also, no side-effect) (而且,没有副作用)

Maybe Way-2 is more safe, because it doesn't change original object.也许Way-2更安全,因为它不会改变原来的object。

I wonder that which one is more general and pythonic way?我想知道哪一种更通用和pythonic的方式?

Thanks.谢谢。

Summary概括

If the API is explicit that it is updating its input, Way-1 is fine and desirable: add_route(route_map, new_route) .如果 API 明确表示它正在更新其输入,则Way-1很好且可取: add_route(route_map, new_route)

If the API is primarily about doing something else, then Way-2 avoids unintended side-effects.如果 API 主要是为了做其他事情,那么Way-2可以避免意外的副作用。

Examples within Python Python 中的示例

Way-1 : The dict.update() and list.sort() do in-place updates because that is their primary job.方式 1dict.update()list.sort()进行就地更新,因为这是它们的主要工作。

Way-2 : The builtin sorted() function produces a new sorted list from its inputs which it takes care not to alter.方式 2 :内置的sorted() function 从其输入中生成一个新的排序列表,注意不要更改。 Roughly, it does this:大致来说,它是这样做的:

def sorted(iterable, *, key=None, reverse=False):
    result = list(iterable)                # copy the data
    result.sort(key=key, reverse=reverse)  # in-place sort
    return result

Hope that clarifies when to copy and when to mutate in-place:-)希望澄清何时复制以及何时就地变异:-)

"Explicit is better than implicit" “显式胜于隐式”
... ...
"In the face of ambiguity, refuse the temptation to guess." “面对模棱两可,拒绝猜测的诱惑。”

- PEP 20 - PEP 20


Modifying a parameter within a function is not necessarily a bad thing.修改 function 中的参数不一定是坏事。 What is bad is to do so with no good reason for doing so.不好的没有充分理由这样做。 If you're clear with your function name and documentation that the parameter will be modified within the function, then that's fine.如果您清楚您的 function 名称和文档将在 function 中修改参数,那很好。 If the function modifies the parameter with no indication it's trying to do so, that's less fine.如果 function 修改了参数而没有任何迹象表明它正在尝试这样做,那就不太好了。

In this case, your Way-1 is simpler and more explicit.在这种情况下,您的Way-1更简单、更明确。 It's obvious that the variable is going to be changed, and the way in which it's going to be changed can be determined easily by looking at the code.很明显,变量将被更改,并且通过查看代码可以轻松确定更改的方式。

Way-2 is worse, because the name change_b would imply that the parameter is going to be modified, and it's not .方式 2更糟糕,因为名称change_b意味着参数将被修改,而不是. Returning a modified version of a parameter without modifying the original is a standard design pattern in python, but it's best to be explicit about it.返回参数的修改版本而不修改原始版本是 python 中的标准设计模式,但最好明确说明。

For example, python's built-in set data structure has counterpart methods: set.difference(other) and set.difference_update(other) .例如,python 内置的set数据结构有对应的方法: set.difference(other)set.difference_update(other) In both cases, they do the same thing: compute the difference between this set and the given set.在这两种情况下,它们都做同样的事情:计算这个集合和给定集合之间的差异。 In the former case, that result is returned without modifying the original set.在前一种情况下,返回结果而不修改原始集。 In the latter case, the original set is modified and nothing is returned.在后一种情况下,原始集合被修改并且不返回任何内容。 It's very straightforward to figure out which does what.弄清楚哪个做什么是非常简单的。

In general, you should probably avoid updating a value and returning that same value, because that's more ambiguous.一般来说,您可能应该避免更新一个值返回相同的值,因为这更加模棱两可。 Note how most python methods do one or the other, but not both (and those that do do both, like list.pop() , do so sensibly, with the returned object not being the object that was modified).请注意大多数 python 方法如何做一个或另一个,但不是两者都做(以及同时做这两个的方法,如list.pop() ,这样做是明智的,返回的 object 不是经过修改的 ZA8CFDE6331BD59EB2AC96F8911C4B666)。

As I understand Python, the most Pythonic way to approach this problem is to make it very clear what is happening.据我了解 Python,解决此问题的最 Pythonic 方法是非常清楚正在发生的事情。 As long as you do that, I don't believe it matters.只要你这样做,我认为这并不重要。

my_dict = {'a': 3, 'b': 4}
double_values_in_dict(my_dict)

# Some other code

This is a contrived example, but it's pretty clear what's intended to happen here, even without the method definition included.这是一个人为的例子,但很清楚这里打算发生什么,即使没有包含方法定义。 What would be unclear is if you assigned the return value of double_values_in_dict to a new variable;不清楚的是,如果您将double_values_in_dict的返回值分配给一个新变量; I wouldn't know then what you may have done to the original dict object, and I'd have to start digging through that method to figure out how it actually works.那时我不知道您可能对原始dict object 做了什么,我必须开始深入研究该方法以弄清楚它是如何工作的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Python中的BaseBean反模式 - BaseBean anti-pattern in Python Python 中的嵌套集和字典是反模式吗? - Are nested sets and dictionaries anti-pattern in Python? 将请求对象发送到Django中的模型方法是否是反模式? - Is it an anti-pattern to send a request object to a model method in Django? Python 装饰器采用附加参数反模式 - Python decorator taking additional argument anti-pattern 带有上下文管理器的生成器是反模式吗? - Are generators with context managers an anti-pattern? Scripts目录是Python中的反模式吗? 如果是这样,进口的正确方法是什么? - Is a Scripts directory an anti-pattern in Python? If so, what's the right way to import? 文件夹名称遮蔽 3rd-party package 名称或 Python 模块名称是反模式吗? - Is folder name shadowing 3rd-party package name or Python module name is an anti-pattern? 在 `__enter__` 中返回除 `self` 以外的值是一种反模式吗? - Is returning a value other than `self` in `__enter__` an anti-pattern? 使用回调满足依赖性的缺点是什么? 而且,这是反模式吗? - What are the drawbacks to using callbacks for satisfying dependencies? And, is this an anti-pattern? 使用 Django ModelField 选择作为字符串的枚举 — 反模式? - Enum using Django ModelField choices as string — anti-pattern?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM