繁体   English   中英

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

[英]How do you know in advance if a method (or function) will alter the variable when called?

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

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

mylist = [3, 1, 7]

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

mylist.count(7)

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

seven_counts = mylist.count(7)

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

mylist.append(9)

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

newlist = mylist.append(9)

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

我的问题很简单:

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

除了阅读文档(对于某些方法将包括指定返回值的类型注释)或在交互式解释器中使用方法(包括使用help()来检查类型注释的文档字符串),不,你不能通过查看方法来了解前方。

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

这种或/或行为都是有意的; 如果他们不服从这个规则,你就会有一个更加困惑和难以识别的问题,即确定append是否突变了调用它的值,或者返回一个新对象。 你肯定得到了一个list ,但它是一个新list还是相同的list 如果它改变了它被调用的值,那么

newlist = mylist.append(9)

有点奇怪; newlistmylist将是同一list别名(为什么这两个名称都是?)。 你可能连一段时间都没注意到; 你会继续使用newlist ,认为它是独立的mylist ,只要看看mylist ,发现这是所有搞砸。 通过使所有这样的“就地修改”方法返回None (或者至少不是原始对象),可以更快/更容易地发现错误; 如果你尝试使用newlist ,错误地认为它是一个list ,你会立即得到TypeError s或AttributeError s。

基本上,提前知道的唯一方法是阅读文档。 对于名称表示修改操作的方法,您可以检查返回值,并经常了解它们是否发生变异。 它有助于首先了解哪些类型是可变的; listdictsetbytearray都是可变的,并且它们具有的不可变对应方法(除了dict ,没有不可变对应方)缺乏的方法往往会使对象变异。

默认情况往往是简单地改变对象,因为它更有效; 如果你有一个100,000元素list ,那么append的默认行为会产生一个新的100,001元素list并返回它将是非常低效的(并且没有明显的方法可以避免它)。 对于不可变类型(例如strtuplefrozenset ),这是不可避免的,如果你想要保证对象永远不会变异,你可以使用这些类型,但是它会以不必要的创建和破坏对象为代价。在大多数情况下减慢代码速度。

只需查看文档:

>>> list.count.__doc__
'L.count(value) -> integer -- return number of occurrences of value'
>>> list.append.__doc__
'L.append(object) -> None -- append object to end'

有一种简单的说法,但是:

不可变对象 - >无法通过方法调用进行更改

因此,例如, tuple没有影响元组的方法,因为它是不可更改的,因此方法只能返回新实例。

如果你“想先看看附加的结果是什么,然后决定是否要将它分配给一个新变量”,那么你可以将列表与一个元素的新列表连接起来。

>>> l = [1,2,3]
>>> k = l + [4]
>>> l
[1, 2, 3]
>>> k
[1, 2, 3, 4]

不仅仅是你的调用(你的方法调用)。 如果只传入不可变对象,则可以保证方法不会更改对象,但是定义了一些方法来更改对象 - 并且不会为您使用的对象定义,也不会在执行时出错。

我真实的生活,你看看方法的文档:这将告诉你究竟发生了什么。

[我即将包括Joe Iddon的答案涵盖...]

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM