参数是通过引用传递还是通过值传递?如何通过引用传递,以便下面的代码输出“Changed”而不是“Original”?
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
另请参阅:为什么函数可以修改调用者感知的某些参数,而不能修改其他参数?
Python为每个对象分配一个唯一的标识符,可以使用Python的内置id()函数找到该标识符。可以验证函数调用中的实际参数和正式参数是否具有相同的id值,这表明伪参数和实际参数引用了相同的对象。注意,实际参数和对应的伪参数是引用同一对象的两个名称。如果将伪参数重新绑定到函数范围中的新值/对象,这不会影响实际参数仍然指向原始对象的事实,因为实际参数和伪参数是两个名称。以上两个事实可以概括为“参数通过赋值传递”。即。,
dummy_argument = actual_argument
如果将dummy_argument重新绑定到函数体中的新对象,则actual_argument仍然引用原始对象。如果使用dummy_argument[0]=some_thing,那么这也将修改actual_argument[0]。因此,“通过引用传递”的效果可以通过修改传入的对象引用的组件/属性来实现。当然,这需要传递的对象是可变对象。
为了与其他语言进行比较,您可以说Python以与C相同的方式按值传递参数,其中当您“按引用”传递时,实际上是按值传递引用(即指针)
简单答案:
在类似于python的c++中,当您创建一个对象实例并将其作为参数传递时,不会复制实例本身,因此您可以从函数的外部和内部引用相同的实例,并且可以修改相同对象实例的组件基准,因此外部可以看到更改。
对于基本类型,python和c++的行为也相同,因为现在创建了实例的副本,所以外部看到/修改的实例与函数内部不同。因此,外部看不到内部的变化。
下面是python和c++之间的真正区别:
c++具有地址指针的概念,而c++允许您传递指针,这绕过了对基本类型的复制,因此函数内部可以影响与外部相同的实例,因此外部也可以看到更改。这在python中没有等价的,因此如果没有变通方法(例如创建包装器类型)是不可能的。
这样的指针在python中很有用,但不像在c++中那样有必要,因为在c++中,您只能返回一个实体,而在python中,您可以返回用逗号分隔的多个值(即元组)。因此,在python中,如果您有变量a、b和c,并希望函数持久地修改它们(相对于外部),您可以这样做:
a=4
b=3
c=8
a,b,c=somefunc(a,b,c)
# a,b,c now have different values here
这样的语法在c++中是不容易实现的,因此在c++中您可以这样做:
int a=4
int b=3
int c=8
somefunc(&a,&b,&c)
// a,b,c now have different values here
从技术上讲,Python始终使用引用传递值。我将重复我的另一个回答,以支持我的发言。
Python始终使用引用传递值。没有任何例外。任何变量赋值都意味着复制参考值。没有例外。任何变量都是绑定到引用值的名称。总是
您可以将参考值视为目标对象的地址。地址在使用时自动取消引用。这样,使用引用值时,似乎可以直接使用目标对象。但在两者之间总是有一个参考点,多跳一步就可以到达目标。
下面的示例证明了Python使用的是通过引用传递:
如果参数是按值传递的,则无法修改外部lst。绿色是目标对象(黑色是存储在内存中的值,红色是对象类型),黄色是内存中的参考值,如箭头所示。蓝色实心箭头是传递给函数的参考值(通过蓝色虚线箭头路径)。丑陋的深黄色是内部字典。(实际上它也可以画成一个绿色椭圆。颜色和形状只表示它是内部的。)
您可以使用id()内置函数来了解引用值是什么(即目标对象的地址)。
在编译语言中,变量是能够捕获类型值的内存空间。在Python中,变量是绑定到引用变量的名称(内部捕获为字符串),该引用变量保存目标对象的引用值。变量的名称是内部字典中的键,该字典项的值部分存储目标的引用值。
引用值在Python中隐藏。没有任何用于存储引用值的显式用户类型。但是,您可以使用列表元素(或任何其他合适容器类型的元素)作为引用变量,因为所有容器都将元素存储为对目标对象的引用。换句话说,元素实际上不包含在容器中——只有对元素的引用。