在Python中通过引用传递整数

Cod*_*lus 70 python function pass-by-reference pass-by-value

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

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

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

mgi*_*son 87

它在Python中并不是那么有用.Python传递对象的引用.在你的函数里面你有一个对象 - 你可以自由地改变那个对象(如果可能的话).但是,整数是不可变的.一种解决方法是在可以变异的容器中传递整数:

def change(x):
    x[0] = 3

x = [1]
change(x)
print x
Run Code Online (Sandbox Code Playgroud)

这充其量是丑陋/笨拙的,但你不会在Python中做得更好.原因是因为在Python中,assign(=)接受任何对象是右侧的结果,并将其绑定到左侧的任何对象*(或将其传递给适当的函数).

理解这一点,我们可以看到为什么没有办法在函数内部改变不可变对象的值 - 你不能改变它的任何属性,因为它是不可变的,你不能只是将"变量"分配给一个新的值因为那时你实际上是在创建一个新对象(与旧对象不同)并为它赋予旧对象在本地名称空间中的名称.

通常,解决方法是简单地返回您想要的对象:

def multiply_by_2(x):
    return 2*x

x = 1
x = multiply_by_2(x)
Run Code Online (Sandbox Code Playgroud)

*在上面的第一个示例中,3实际上传递给了x.__setitem__.

  • "Python传递对象." 不,Python传递引用(指向对象的指针). (10认同)
  • @ user102008 - 公平点.我觉得这时的语义变得非常混乱.最终,它们也不是"指针".至少,肯定与你在'C`中没有相同的意义.(例如,它们不必被解除引用).在我的心理模型中,将事物想象为"名称"和"对象"更容易.赋值将左侧的"名称"绑定到右侧的"对象".调用函数时,传递"对象"(有效地将其绑定到函数中的新本地名称). (4认同)
  • Python 引用与 Java 引用完全相同。Java 引用是根据对象的 JLS 指针进行的。Java/Python 引用和 C++ 指向对象的指针在语义上基本上是完全双射的,没有其他东西也描述了这种语义。“它们不必取消引用”好吧,`.` 运算符只是取消引用左侧。不同语言中的运算符可能不同。 (4认同)
  • 难怪我们会对术语感到困惑。在这里,我们将其描述为 [call-by-object](http://stackoverflow.com/questions/10262920/understanding-pythons-call-by-object-style-of-passing-function-arguments),这里是描述为 [pass-by-value](http://stackoverflow.com/a/986145/748858)。在其他地方,它被称为“通过引用传递”,并在实际含义上加上星号......基本上,问题在于社区还没有弄清楚*如何称呼它* (2认同)
  • @RonInbar——我不太确定你在这里得到了什么。Python 不是具有装箱和拆箱概念的 C#(或 Java)。在参考实现中,_everything_ 只是一个 `PyObject`。当您调用 python 函数时,python 不知道(或关心)正在传递的类型。事实上,您可以使用不同的类型多次调用同一函数(考虑内置的“str”)。AFAIK 函数接口级别的原语没有特殊的大小写。是的,这就是相比之下 python 函数调用有点昂贵的原因之一。 (2认同)

Gab*_*abe 25

您需要通过引用传递的大多数情况是您需要将多个值返回给调用者的位置."最佳实践"是使用多个返回值,这在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
Run Code Online (Sandbox Code Playgroud)


Uri*_*Uri 11

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

x = 7
def my_method():
    nonlocal x
    x += 1
my_method()
print(x) # 8
Run Code Online (Sandbox Code Playgroud)

注意事项:

  • nonlocal 在python 3中引入
  • 如果封闭范围是全局范围,请使用global代替nonlocal


aba*_*ert 6

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

如果你需要快速进行黑客攻击,那么最快的方法是传递一个list持有整数,并坚持[0]使用它,就像mgilson的回答所示.

如果你需要为更重要的事情做一些事情,那就写一个class具有int属性的东西,这样你就可以设置它.当然这会迫使你为这个类提出一个好名字,对于属性 - 如果你想不出任何东西,那就回去再读一遍这句话,然后再使用list.

更一般地说,如果你试图将一些Java习惯用法直接移植到Python,你就错了.即使存在直接对应的东西(与static/一样@staticmethod),你仍然不想在大多数Python程序中使用它,因为你在Java中使用它.


mhe*_*man 6

也许比 list-of-length-1 技巧更自我说明的是旧的空类型技巧:

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

x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
Run Code Online (Sandbox Code Playgroud)


小智 6

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

import ctypes

def incr(a):
    a += 1

x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
Run Code Online (Sandbox Code Playgroud)


小智 6

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

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)

Run Code Online (Sandbox Code Playgroud)


Tri*_*een 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)
Run Code Online (Sandbox Code Playgroud)

输出:

7
Run Code Online (Sandbox Code Playgroud)