![](/img/trans.png)
[英]How do you call a class's method when it is assigned to a variable and inside a function?
[英]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
值,但它永远不会是刚刚变异的对象; dict
和list
的pop
方法就是这种情况的一个示例)。
这种或/或行为都是有意的; 如果他们不服从这个规则,你就会有一个更加困惑和难以识别的问题,即确定append
是否突变了调用它的值,或者返回一个新对象。 你肯定得到了一个list
,但它是一个新list
还是相同的list
? 如果它改变了它被调用的值,那么
newlist = mylist.append(9)
有点奇怪; newlist
和mylist
将是同一list
别名(为什么这两个名称都是?)。 你可能连一段时间都没注意到; 你会继续使用newlist
,认为它是独立的mylist
,只要看看mylist
,发现这是所有搞砸。 通过使所有这样的“就地修改”方法返回None
(或者至少不是原始对象),可以更快/更容易地发现错误; 如果你尝试使用newlist
,错误地认为它是一个list
,你会立即得到TypeError
s或AttributeError
s。
基本上,提前知道的唯一方法是阅读文档。 对于名称表示修改操作的方法,您可以检查返回值,并经常了解它们是否发生变异。 它有助于首先了解哪些类型是可变的; list
, dict
, set
和bytearray
都是可变的,并且它们具有的不可变对应方法(除了dict
,没有不可变对应方)缺乏的方法往往会使对象变异。
默认情况往往是简单地改变对象,因为它更有效; 如果你有一个100,000元素list
,那么append
的默认行为会产生一个新的100,001元素list
并返回它将是非常低效的(并且没有明显的方法可以避免它)。 对于不可变类型(例如str
, tuple
, frozenset
),这是不可避免的,如果你想要保证对象永远不会变异,你可以使用这些类型,但是它会以不必要的创建和破坏对象为代价。在大多数情况下减慢代码速度。
只需查看文档:
>>> 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.