简体   繁体   English

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

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

I am new to Python from R. I have recently spent a lot of time reading up on how everything in Python is an object, objects can call methods on themselves, methods are functions within a class, yada yada yada. 我是R的新手。我最近花了很多时间阅读Python中的所有内容如何成为对象,对象可以自己调用方法,方法是类中的函数,yada yada yada。

Here's what I don't understand. 这是我不明白的。 Take the following simple code: 请使用以下简单代码:

mylist = [3, 1, 7]

If I want to know how many times the number 7 occurs, I can do: 如果我想知道7号出现的次数,我可以这样做:

mylist.count(7)

That, of course, returns 1. And if I want to save the count number to another variable: 当然,这会返回1.如果我想将计数保存到另一个变量:

seven_counts = mylist.count(7)

So far, so good. 到现在为止还挺好。 Other than the syntax, the behavior is similar to R. However, let's say I am thinking about adding a number to my list: 除了语法之外,行为类似于R.但是,假设我正在考虑在我的列表中添加一个数字:

mylist.append(9)

Wait a minute, that method actually changed the variable itself! 等一下,该方法实际上改变了变量本身! (ie, "mylist" has been altered and now includes the number 9 as the fourth digit in the list.) Assigning the code to a new variable (like I did with seven_counts) produces garbage: (即,“mylist”已被更改,现在包含数字9作为列表中的第四个数字。)将代码分配给新变量(就像我使用seven_counts一样)会产生垃圾:

newlist = mylist.append(9)

I find the inconsistency in this behavior a bit odd, and frankly undesirable. 我发现这种行为的不一致有点奇怪,坦率地说是不可取的。 (Let's say I wanted to see what the result of the append looked like first and then have the option to decide whether or not I want to assign it to a new variable.) (假设我想先看看附加的结果是什么样的,然后可以选择决定是否要将其分配给新变量。)

My question is simple: 我的问题很简单:

Is there a way to know in advance if calling a particular method will actually alter your variable (object)? 有没有办法事先知道调用特定方法是否会实际改变你的变量(对象)?

Aside from reading the documentation (which for some methods will include type annotations specifying the return value) or playing with the method in the interactive interpreter (including using help() to check the docstring for a type annotation), no, you can't know up front just by looking at the method. 除了阅读文档(对于某些方法将包括指定返回值的类型注释)或在交互式解释器中使用方法(包括使用help()来检查类型注释的文档字符串),不,你不能通过查看方法来了解前方。

That said, the behavior you're seeing is intentional. 也就是说,你所看到的行为是故意的。 Python methods either return a new modified copy of the object or modify the object in place; Python方法要么返回对象的修改副本, 要么修改对象; at least among built-ins, they never do both (some methods mutate the object and return a non- None value, but it's never the object just mutated; the pop method of dict and list is an example of this case). 至少在内置函数中,它们从不同时执行这两种操作 (某些方法会改变对象并返回非None值,但它永远不会是刚刚变异的对象; dictlistpop方法就是这种情况的一个示例)。

This either/or behavior is intentional; 这种或/或行为都是有意的; if they didn't obey this rule, you'd have had an even more confusing and hard to identify problem, namely, determining whether append mutated the value it was called on, or returned a new object. 如果他们不服从这个规则,你就会有一个更加困惑和难以识别的问题,即确定append是否突变了调用它的值,或者返回一个新对象。 You definitely got back a list , but is it a new list or the same list ? 你肯定得到了一个list ,但它是一个新list还是相同的list If it mutated the value it was called on, then 如果它改变了它被调用的值,那么

newlist = mylist.append(9)

is a little strange; 有点奇怪; newlist and mylist would be aliases to the same list (so why have both names?). newlistmylist将是同一list别名(为什么这两个名称都是?)。 You might not even notice for a while; 你可能连一段时间都没注意到; you'd continue using newlist , thinking it was independent of mylist , only to look at mylist and discover it was all messed up. 你会继续使用newlist ,认为它是独立的mylist ,只要看看mylist ,发现这是所有搞砸。 By having all such "modify in place" methods return None (or at least, not the original object), the error is discovered more quickly/easily; 通过使所有这样的“就地修改”方法返回None (或者至少不是原始对象),可以更快/更容易地发现错误; if you try and use newlist , mistakenly believing it to be a list , you'll immediately get TypeError s or AttributeError s. 如果你尝试使用newlist ,错误地认为它是一个list ,你会立即得到TypeError s或AttributeError s。

Basically, the only way to know in advance is to read the documentation. 基本上,提前知道的唯一方法是阅读文档。 For methods whose name indicates a modifying operation, you can check the return value and often get an idea as to whether they're mutating. 对于名称表示修改操作的方法,您可以检查返回值,并经常了解它们是否发生变异。 It helps to know what types are mutable in the first place; 它有助于首先了解哪些类型是可变的; list , dict , set and bytearray are all mutable, and the methods they have that their immutable counterparts (aside from dict , which has no immutable counterpart) lack tend to mutate the object in place. listdictsetbytearray都是可变的,并且它们具有的不可变对应方法(除了dict ,没有不可变对应方)缺乏的方法往往会使对象变异。

The default tends to be to mutate the object in place simply because that's more efficient; 默认情况往往是简单地改变对象,因为它更有效; if you have a 100,000 element list , a default behavior for append that made a new 100,001 element list and returned it would be extremely inefficient (and there would be no obvious way to avoid it). 如果你有一个100,000元素list ,那么append的默认行为会产生一个新的100,001元素list并返回它将是非常低效的(并且没有明显的方法可以避免它)。 For immutable types (eg str , tuple , frozenset ) this is unavoidable, and you can use those types if you want a guarantee that the object is never mutate in place, but it comes at a cost of unnecessary creation and destruction of objects that will slow down your code in most cases. 对于不可变类型(例如strtuplefrozenset ),这是不可避免的,如果你想要保证对象永远不会变异,你可以使用这些类型,但是它会以不必要的创建和破坏对象为代价。在大多数情况下减慢代码速度。

Just checkout the doc: 只需查看文档:

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

There isn't really an easy way to tell, but: 有一种简单的说法,但是:

immutable object --> no way of changing through method calls 不可变对象 - >无法通过方法调用进行更改

So, for example, tuple has no methods which affect the tuple as it is unchangeable so methods can only return new instances. 因此,例如, tuple没有影响元组的方法,因为它是不可更改的,因此方法只能返回新实例。

And if you "wanted to see what the result of the append looked like first and then have the option to decide whether or not I want to assign it to a new variable" then you can concatenate the list with a new list with one element. 如果你“想先看看附加的结果是什么,然后决定是否要将它分配给一个新变量”,那么你可以将列表与一个元素的新列表连接起来。

ie

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

Not from merely your invocation (your method call). 不仅仅是你的调用(你的方法调用)。 You can guarantee that the method won't change the object if you pass in only immutable objects, but some methods are defined to change the object -- and will either not be defined for the one you use, or will fault in execution. 如果只传入不可变对象,则可以保证方法不会更改对象,但是定义了一些方法来更改对象 - 并且不会为您使用的对象定义,也不会在执行时出错。

I Real Life, you look at the method's documentation: that will tell you exactly what happens. 我真实的生活,你看看方法的文档:这将告诉你究竟发生了什么。

[I was about to include what Joe Iddon's answer covers ...] [我即将包括Joe Iddon的答案涵盖...]

暂无
暂无

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

相关问题 在将类分配给变量和函数内部时,如何调用类的方法? - How do you call a class's method when it is assigned to a variable and inside a function? 你如何在python的循环中改变变量名? - How do you alter a variable name in a loop in python? 当您事先知道某些输入会出现问题时,使用 try/except 块来检查 function 是否可以安全运行是一种好习惯吗? - Is it good practice to use try/except blocks to check if a function can safely be run when you know in advance some input will be problematic? 当我事先不知道char编码时,如何打印字符串列表? - How do I print a list of strings, when I can't know the char encoding in advance? 我不知道如何在 function 中编写 A 元组的格式,以便将我想要的任何日期作为元组。 先感谢您 - I don't know how to write the format for A tuple in the function in order to put any date I want as a tuple. Thank you in advance 你怎么知道你导入的模块是函数还是类? - How do you know that module you are importing is function or class? 如果应该使用列表或变量调用模块,如何在 Python 中调用模块的函数? - How do you call a function of a module in Python if the module should be called with a list or variable? 某些方法如何知道事先接受争论? - How do certain methods know to take an argument in advance? 使用sqlalchemy时如何进行高级联接? - How to do advance joins when using sqlalchemy? 你如何改变 Pytorch 数据集的大小? - How do you alter the size of a Pytorch Dataset?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM