为什么列表变量有时不受函数更改的影响,因为我认为 python3 可以通过引用传递列表变量?

如何解决为什么列表变量有时不受函数更改的影响,因为我认为 python3 可以通过引用传递列表变量?

对于python3,我原本需要从一个列表中提取奇数和偶数位置并将其分配给新列表,然后清除原始列表。我认为列表会受到通过“通过引用传递”的函数调用的影响。测试一些场景,它有时会起作用。有人可以解释一下python3在这里是如何工作的吗?

案例 1:空列表按预期填充了字符串。

def func1(_in):
    _in.append('abc')

mylist = list()
print(f"Before:\nmylist = {mylist}")
func1(mylist)
print(f"After:\nmylist = {mylist}")

输出案例 1:

Before:
mylist = []
After:
mylist = ['abc']

情况 2:中间列表元素按预期替换为字符串。

def func2(_in):
    _in[1] = 'abc'

mylist = list(range(3))
print(f"Before:\nmylist = {mylist}")
func2(mylist)
print(f"After:\nmylist = {mylist}")

输出案例2:

Before:
mylist = [0,1,2]
After:
mylist = [0,'abc',2]

案例3:为什么函数调用后列表不为空?

def func3(_in):
    _in = list()

mylist = list(range(3))
print(f"Before:\nmylist = {mylist}")
func3(mylist)
print(f"After:\nmylist = {mylist}")

输出案例 3:

Before:
mylist = [0,2]

案例 4:完全按预期工作,但请注意,我已从函数中返回了所有三个列表。

def func4_with_ret(_src,_dest1,_dest2):
    _dest1 = [val for val in _src[0:len(_src):2]]
    _dest2 = [val for val in _src[1:len(_src):2]]
    _src = list()
    return _src,_dest2

source = list(range(6))
evens,odds = list(),list()
print(f"Before function call:\nsource = {source}\nevens = {evens}\nodds = {odds}")
source,evens,odds = func4_with_ret(source,odds)
print(f"\nAfter function call:\nsource = {source}\nevens = {evens}\nodds = {odds}")

输出案例 4:

Before function call:
source = [0,2,3,4,5]
evens = []
odds = []

After function call:
source = []
evens = [0,4]
odds = [1,5]

案例5:如果我没有从函数调用中显式返回,为什么对函数外的变量没有影响?

def func5_no_ret(_src,_dest2):
    _dest1 = [val for val in _src[0:len(_src):2]]
    _dest2 = [val for val in _src[1:len(_src):2]]
    _src = list()

source = list(range(6))
evens,list()
print(f"Before function call:\nsource = {source}\nevens = {evens}\nodds = {odds}")
func5_no_ret(source,odds)
print(f"\nAfter function call:\nsource = {source}\nevens = {evens}\nodds = {odds}")

输出案例 5:

Before function call:
source = [0,5]
evens = []
odds = []

After function call:
source = [0,5]
evens = []
odds = []

谢谢。

解决方法

您的最终问题是将(就地)变异重新绑定混淆(也称为“重新分配”)。

在更改在函数外部不可见的所有情况下,您回滚函数内部的名称。当你这样做时:

name = val

name 中过去的内容并不重要;它反弹val,并且对旧对象的引用被丢弃。当它是最后一个引用时,这会导致对象被清理;在您的情况下,参数 used 用于别名的对象也绑定到调用者中的名称,但在重新绑定后,该别名关联丢失。

对于 C/C++ 人员来说:重新绑定就像分配给一个指针变量,例如int *px = pfoo;(初始绑定),后面跟着 px = pbar;(重新绑定),其中 pfoopbar 本身都是指向 int 的指针。当 px = pbar; 赋值发生时,px 过去指向与 pfoo 相同的东西并不重要,它现在指向新的东西,并用 {{1 }}(变异,不重新绑定)只影响 *px = 1; 指向的任何东西,而 pbar 的目标保持不变。

相比之下,mutation 不会破坏别名关联,因此:

pfoo

会重新绑定 name[1] = val 本身,但不会重新绑定 name[1];它继续像以前一样引用同一个对象,它只是在原地改变那个对象,保留所有别名不变(因此所有别名同一个对象的名称都会看到更改的结果)。

对于您的具体情况,您可以通过更改为切片分配/删除或其他形式的就地突变来将“损坏的”函数从重新绑定更改为别名,例如:

name

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?