我刚从R开始接触Python。最近我花了很多时间阅读Python中的所有东西是如何成为对象的,对象可以自己调用方法,方法是类中的函数,yada yada yada。你知道吗
我不明白的是。以下面的简单代码为例:
mylist = [3, 1, 7]
如果我想知道数字7出现了多少次,我可以:
mylist.count(7)
当然,返回1。如果我想把计数保存到另一个变量中:
seven_counts = mylist.count(7)
到目前为止,还不错。除了语法之外,行为类似于R。但是,假设我正在考虑向列表中添加一个数字:
mylist.append(9)
等等,那个方法实际上改变了变量本身!(也就是说,“mylist”已经被修改了,现在包含了数字9作为列表中的第四个数字。)将代码赋给一个新的变量(就像我对七个\u计数所做的那样)会产生垃圾:
newlist = mylist.append(9)
我发现这种行为的不一致性有点奇怪,坦率地说是不可取的。(假设我想先看看append的结果是什么样的,然后可以选择是否将其赋给一个新变量。)
我的问题很简单:
有没有办法提前知道调用一个特定的方法是否会改变你的变量(对象)?你知道吗
不仅仅是调用(方法调用)。如果只传入不可变的对象,则可以保证方法不会更改对象,但有些方法是定义的来更改对象的,并且不会为您使用的方法定义,或者在执行时会出错。你知道吗
在现实生活中,你看看这个方法的文档:它会告诉你到底发生了什么。你知道吗
[我正要把乔·伊登的回答包括在内…]
除了阅读文档(对于某些方法,它将包含指定返回值的类型注释)或在交互式解释器中使用方法(包括使用
help()
检查docstring中的类型注释)之外,不,您不能仅仅通过查看方法就预先知道。你知道吗也就是说,你看到的行为是故意的。Python方法要么返回对象的新的修改过的副本要么就地修改对象;至少在内置方法中,它们从不同时执行这两个操作(有些方法会修改对象并返回一个非
None
值,但它决不是刚刚修改过的对象;dict
和list
的pop
方法就是一个例子本案中)。你知道吗这种非此即彼的行为是有意为之的;如果他们不遵守这条规则,那么您将遇到一个更容易混淆和难以识别的问题,即确定
append
是否改变了调用它的值,或者返回了一个新对象。你肯定得到了一个list
,但它是一个新的list
还是相同的list
?如果它改变了所调用的值有点奇怪;
newlist
和mylist
是同一个list
的别名(为什么两个名字都有?)。你可能一段时间都没有注意到;你会继续使用newlist
,以为它独立于mylist
,结果看到mylist
就发现一切都搞砸了。通过让所有这些“modify in place”方法返回None
(或者至少不是原始对象),可以更快/更容易地发现错误;如果您尝试使用newlist
,错误地认为它是list
,您会立即得到TypeError
或AttributeError
基本上,提前知道的唯一方法就是阅读文档。对于名称指示修改操作的方法,您可以检查返回值,并经常了解它们是否在发生变化。首先,它有助于了解哪些类型是可变的;
list
、dict
、set
和bytearray
都是可变的,并且它们不可变的对应项(除了没有不可变的对应项的dict
)所缺少的方法往往会在适当的位置对对象进行变异。你知道吗默认情况下,只需简单地对对象进行适当的修改就可以了,因为这样效率更高;如果有100000个元素
list
,那么append
的默认行为会生成一个新的100001个元素list
并返回它,这将是非常低效的(而且没有明显的方法可以避免它)。对于不可变的类型(例如str
、tuple
、frozenset
),这是不可避免的,如果您希望保证对象永远不会原地突变,那么可以使用这些类型,但是这样做的代价是不必要地创建和销毁对象,这在大多数情况下会减慢代码的速度。你知道吗只需签出文档:
其实没有一个简单的方法来判断,但是:
例如,
tuple
没有影响元组的方法,因为元组是不可更改的,所以方法只能返回新实例。你知道吗如果你“想先看看append的结果是什么样的,然后可以选择我是否想把它赋给一个新的变量”,那么你可以把这个列表和一个新的列表和一个元素连接起来。你知道吗
即
相关问题 更多 >
编程相关推荐