如何在 Python 中通过引用传递整数?
我想修改传递给函数的变量的值。我读过 Python 中的所有内容都是按值传递的,但必须有一个简单的技巧。例如,在 Java 中,您可以传递 、 等的引用Integer
类型Long
。
- 如何通过引用将整数传递给函数?
- 最佳实践是什么?
如何在 Python 中通过引用传递整数?
我想修改传递给函数的变量的值。我读过 Python 中的所有内容都是按值传递的,但必须有一个简单的技巧。例如,在 Java 中,您可以传递 、 等的引用Integer
类型Long
。
它在 Python 中并不是这样工作的。Python 传递对对象的引用。在你的函数内部你有一个对象——你可以自由地改变那个对象(如果可能的话)。但是,整数是不可变的。一种解决方法是在可以变异的容器中传递整数:
def change(x):
x[0] = 3
x = [1]
change(x)
print x
这充其量是丑陋/笨拙,但你不会在 Python 中做得更好。原因是因为在 Python 中,赋值 ( =
) 获取右侧结果的任何对象并将其绑定到左侧的任何对象 *(或将其传递给适当的函数)。
理解了这一点,我们就可以明白为什么无法在函数内部改变不可变对象的值——你不能改变它的任何属性,因为它是不可变的,你不能仅仅给“变量”分配一个新的值,因为那时您实际上是在创建一个新对象(与旧对象不同)并为其赋予旧对象在本地命名空间中的名称。
通常解决方法是简单地返回您想要的对象:
def multiply_by_2(x):
return 2*x
x = 1
x = multiply_by_2(x)
*在上面的第一个示例中,3
实际上被传递给x.__setitem__
.
大多数需要通过引用传递的情况是需要将多个值返回给调用者。“最佳实践”是使用多个返回值,这在 Python 中比在 Java 等语言中要容易得多。
这是一个简单的例子:
def RectToPolar(x, y):
r = (x ** 2 + y ** 2) ** 0.5
theta = math.atan2(y, x)
return r, theta # return 2 things at once
r, theta = RectToPolar(3, 4) # assign 2 things at once
不完全直接传递一个值,而是像传递一样使用它。
x = 7
def my_method():
nonlocal x
x += 1
my_method()
print(x) # 8
注意事项:
nonlocal
在 python 3 中引入global
而不是nonlocal
.真的,最好的做法是退后一步,问问你是否真的需要这样做。为什么要修改传递给函数的变量的值?
如果您需要快速破解,最快的方法是传递 alist
持有整数,并[0]
在每次使用它时粘贴 a ,正如 mgilson 的回答所证明的那样。
如果您需要为更重要的事情执行此操作,请编写class
具有 anint
作为属性的 a,这样您就可以设置它。当然,这迫使你为类和属性想出一个好名字——如果你什么都想不出来,回去再读几遍句子,然后使用list
.
更一般地说,如果你试图将一些 Java 习语直接移植到 Python,那么你做错了。即使有直接对应的东西(如static
/ @staticmethod
),你仍然不想在大多数 Python 程序中使用它,因为你会在 Java 中使用它。
也许这不是pythonic方式,但你可以这样做
import ctypes
def incr(a):
a += 1
x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
一个numpy 单元素数组是可变的,但在大多数情况下,它可以像一个数值 python 变量一样被评估。因此,它是一个比单元素列表更方便的按引用编号容器。
import numpy as np
def triple_var_by_ref(x):
x[0]=x[0]*3
a=np.array([2])
triple_var_by_ref(a)
print(a+1)
输出:
7
在 Python 中,每个值都是一个引用(指向对象的指针),就像 Java 中的非基元一样。此外,与 Java 一样,Python 也只有按值传递。因此,从语义上讲,它们几乎相同。
既然您在问题中提到了 Java,我想看看您如何在 Java 中实现您想要的。如果你可以在 Java 中展示它,我可以向你展示如何在 Python 中完全等价地做到这一点。
class PassByReference:
def Change(self, var):
self.a = var
print(self.a)
s=PassByReference()
s.Change(5)
可能比 list-of-length-1 技巧更能自我记录的是旧的空类型技巧:
def inc_i(v):
v.i += 1
x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
正确的答案是使用一个类并将值放在类中,这可以让您完全按照您的意愿通过引用。
class Thing:
def __init__(self,a):
self.a = a
def dosomething(ref)
ref.a += 1
t = Thing(3)
dosomething(t)
print("T is now",t.a)
在 Python 中,一切都是按值传递的,但如果您想修改某些状态,可以更改传递给方法的列表或对象中的整数值。
class Obj:
def __init__(self,a):
self.value = a
def sum(self, a):
self.value += a
a = Obj(1)
b = a
a.sum(1)
print(a.value, b.value)// 2 2
整数在 python 中是不可变的,一旦它们被创建,我们就不能通过对变量使用赋值运算符来更改它们的值,我们让它指向其他地址而不是前一个地址。
在 python 中,一个函数可以返回多个值,我们可以使用它:
def swap(a,b):
return b,a
a,b=22,55
a,b=swap(a,b)
print(a,b)
要更改变量指向的引用,我们可以将不可变数据类型(int、long、float、complex、str、bytes、truple、frozenset)包装在可变数据类型(bytearray、list、set、dict)中。
#var is an instance of dictionary type
def change(var,key,new_value):
var[key]=new_value
var =dict()
var['a']=33
change(var,'a',2625)
print(var['a'])