如果方法(或函数)在调用时会改变变量,你怎么知道?

Mil*_*ane 6 python methods

我是R的新手.我最近花了很多时间阅读Python中的所有内容如何成为对象,对象可以自己调用方法,方法是类中的函数,yada yada yada.

这是我不明白的.请使用以下简单代码:

mylist = [3, 1, 7]
Run Code Online (Sandbox Code Playgroud)

如果我想知道7号出现的次数,我可以这样做:

mylist.count(7)
Run Code Online (Sandbox Code Playgroud)

当然,这会返回1.如果我想将计数保存到另一个变量:

seven_counts = mylist.count(7)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.除了语法之外,行为类似于R.但是,假设我正在考虑在我的列表中添加一个数字:

mylist.append(9)
Run Code Online (Sandbox Code Playgroud)

等一下,该方法实际上改变了变量本身!(即,"mylist"已被更改,现在包含数字9作为列表中的第四个数字.)将代码分配给新变量(就像我使用seven_counts一样)会产生垃圾:

newlist = mylist.append(9)
Run Code Online (Sandbox Code Playgroud)

我发现这种行为的不一致有点奇怪,坦率地说是不可取的.(假设我想先看看附加的结果是什么样的,然后可以选择决定是否要将其分配给新变量.)

我的问题很简单:

有没有办法事先知道调用特定方法是否会实际改变你的变量(对象)?

Sha*_*ger 3

除了阅读文档(对于某些方法将包括指定返回值的类型注释)或在交互式解释器中使用该方法(包括help()用于检查文档字符串中的类型注释)之外,不,您无法预先知道只要看方法就可以了。

也就是说,您所看到的行为是故意的。Python 方法要么返回对象的新修改副本,要么就地修改对象;至少在内置函数中,它们永远不会同时执行这两种操作(某些方法会改变对象并返回非值None,但它绝不是刚刚改变的对象;andpop的方法就是这种情况的一个示例)。dictlist

这种非此即彼的行为是故意的;如果他们不遵守这个规则,你就会遇到一个更加令人困惑和难以识别的问题,即确定是否append改变了它所调用的值,或者返回了一个新对象。你肯定回来了list,但它是新的list还是一样的list?如果它改变了它所调用的值,那么

newlist = mylist.append(9)
Run Code Online (Sandbox Code Playgroud)

有点奇怪;newlist并且mylist将是相同的别名list(那么为什么有两个名字呢?)。你可能有一段时间都没有注意到;你会继续使用newlist,认为它独立于mylist,结果却mylist发现它全乱了。通过让所有此类“就地修改”方法返回None(或者至少不是原始对象),可以更快/更轻松地发现错误;如果您尝试使用newlist,并错误地认为它是 a list,您将立即得到TypeErrors 或AttributeErrors。

基本上,提前了解的唯一方法是阅读文档。对于名称指示修改操作的方法,您可以检查返回值,并且通常可以了解它们是否正在发生变化。首先了解哪些类型是可变的会有所帮助;listdict和都是可变的,并且它们所拥有的不可变对应项setbytearray除了dict,它没有不可变对应项)所缺乏的方法往往会就地改变对象。

默认情况下往往是就地改变对象,因为这样更有效;如果你有一个 100,000 个元素listappend那么创建一个新的 100,001 个元素list并返回它的默认行为将是极其低效的(并且没有明显的方法来避免它)。对于不可变类型(例如str,,,),这是不可避免的,如果您想保证对象永远不会就地改变,您可以使用这些类型,但它的代价是不必要的对象创建和销毁,这会减慢您的速度tuplefrozenset大多数情况下的代码。