119

如何在 Python 中通过引用传递整数?

我想修改传递给函数的变量的值。我读过 Python 中的所有内容都是按值传递的,但必须有一个简单的技巧。例如,在 Java 中,您可以传递 、 等的引用Integer类型Long

  1. 如何通过引用将整数传递给函数?
  2. 最佳实践是什么?
4

13 回答 13

141

它在 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__.

于 2013-03-01T00:50:51.860 回答
33

大多数需要通过引用传递的情况是需要将多个值返回给调用者。“最佳实践”是使用多个返回值,这在 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
于 2013-03-01T04:21:28.420 回答
13

不完全直接传递一个值,而是像传递一样使用它。

x = 7
def my_method():
    nonlocal x
    x += 1
my_method()
print(x) # 8

注意事项:

  • nonlocal在 python 3 中引入
  • 如果封闭范围是全局范围,请使用global而不是nonlocal.
于 2018-08-19T12:15:37.797 回答
9

真的,最好的做法是退后一步,问问你是否真的需要这样做。为什么要修改传递给函数的变量的值?

如果您需要快速破解,最快的方法是传递 alist持有整数,并[0]在每次使用它时粘贴 a ,正如 mgilson 的回答所证明的那样。

如果您需要为更重要的事情执行此操作,请编写class具有 anint作为属性的 a,这样您就可以设置它。当然,这迫使你为类和属性想出一个好名字——如果你什么都想不出来,回去再读几遍句子,然后使用list.

更一般地说,如果你试图将一些 Java 习语直接移植到 Python,那么你做错了。即使有直接对应的东西(如static/ @staticmethod),你仍然不想在大多数 Python 程序中使用它,因为你会在 Java 中使用它。

于 2013-03-01T00:53:38.013 回答
8

也许这不是pythonic方式,但你可以这样做

import ctypes

def incr(a):
    a += 1

x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
于 2019-06-07T14:15:16.667 回答
5

一个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
于 2018-02-16T03:52:10.193 回答
4

在 Python 中,每个值都是一个引用(指向对象的指针),就像 Java 中的非基元一样。此外,与 Java 一样,Python 也只有按值传递。因此,从语义上讲,它们几乎相同。

既然您在问题中提到了 Java,我想看看您如何在 Java 中实现您想要的。如果你可以在 Java 中展示它,我可以向你展示如何在 Python 中完全等价地做到这一点。

于 2013-03-01T04:15:41.177 回答
3
class PassByReference:
    def Change(self, var):
        self.a = var
        print(self.a)
s=PassByReference()
s.Change(5)     
于 2014-02-04T06:44:41.817 回答
3

可能比 list-of-length-1 技巧更能自我记录的是旧的空类型技巧:

def inc_i(v):
    v.i += 1

x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
于 2017-04-27T13:50:01.823 回答
3

正确的答案是使用一个类并将值放在类中,这可以让您完全按照您的意愿通过引用。

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)

于 2020-09-02T04:23:29.840 回答
0

在 Python 中,一切都是按值传递的,但如果您想修改某些状态,可以更改传递给方法的列表或对象中的整数值。

于 2013-03-01T00:46:50.803 回答
0
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
于 2021-02-02T12:01:15.030 回答
0

整数在 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'])
于 2021-10-31T05:41:32.773 回答