|
ython 文档似乎不清楚参数是通过引用传输还是通过值传输,以下代码生成未更改的值 ‘Original’+ O z/ o% H+ u9 K8 ^
class PassByReference: def __init__(self): self.variable = 'Original self.change(self.variable) print(self.variable) def change(self,var): var = 'Changed'! A# K5 T! `4 f
通过实际引用传输变量,我能做些什么?2 E( Z3 i* j1 d4 l! _# K
# C) `! M. g7 S. p 解决方案:
4 O$ G3 D+ G3 D! \/ a0 v 参数通过 assignment 传输。这背后的原因是双重的:0 y' v. H/ v2 v+ c r9 \+ Z
[ol]传入参数实际上是一个对象引用(但引用是按值传递的)
4 P- P# a& }" D+ z有些数据类型是可变的,但有些不是[/ol]所以:6 Y1 M3 v7 m- n- K7 N
假如你要一个可变对象传递给一种方法,可以引用同一对象,可以随意改变,但如果重新绑定引用,外部作用域将一无所知,完成后,外部引用仍将指向原始对象。9 B8 _9 _; Q. T! F2 R
如果将不可变对象传递给方法,仍然不能重新绑定外部引用,甚至不能改变对象。让我们举一些例子,以便更清楚。! f5 ?* m$ ]2 C9 Y* s9 W( M
List - 可变类型让我们尝试修改传递给方法的列表:
, `! a; r" W% d3 ?1 D n2 P: l( C) [5 Adef try_to_change_list_contents(the_list): print('got',the_list) the_list.append('four') print('changed to',the_list)outer_list = ['one','two','three']print('before,outer_list =',outer_list)try_to_change_list_contents(outer_list)print('after,outer_list =',outer_list)7 q- z, r+ q) h* C3 a
输出:
$ l( b( A3 w( x: Obefore,outer_list = ['one','two','three']got ['one','two','three']changed to ['one','two','three','four']after,outer_list = ['one','two','three','four']. ^1 X5 v t" w* f$ l' [9 M. U P5 ?
因为引入的参数是引用 outer_list,我们可以使用 而不是它的副本mutating list 改变方法,并在外部范围内反映改变。/ a9 D) m; x* }- G7 |
现在让我们看看当我们试图将其更改为参数引用时会发生什么:! ~" B- L4 i5 r. T
def try_to_change_list_reference(the_list): print('got',the_list) the_list = ['and','we','can','not','lie print('set to',the_list)outer_list = ['we','like','proper','English']print('before,outer_list =',outer_list)try_to_change_list_reference(outer_list)print('after,outer_list =',outer_list)
: ], f! U0 ]: ]% a( c3 u 输出:
& h. c! Z* O. x6 m# `before,outer_list = ['we','like','proper','English']got ['we','like','proper','English']set to ['and','we','can','not','lie']after,outer_list = ['we','like','proper','English']# z1 w; v \# Y6 O. z' ?1 G" z
由于the_list参数是按值传递的,所以分配新列表对方法外的代码没有影响。the_list是outer_list我们引用的副本the_list指向新列表,但不能更改outer_list指向位置。
0 ]7 H+ j! C! ^9 pString - 不可变类型它是不可改变的,所以我们不能改变字符串的内容
. F8 v2 ^- m) l, p9 r! V; }( J7 d, [现在,让我们试着改变参考
, g0 o# i! z( Q* ?def try_to_change_string_reference(the_string): print('got',the_string) the_string = 'In a kingdom by the sea' print('set to',the_string)outer_string = 'It was many and many a year ago'print('before,outer_string =',outer_string)try_to_change_string_reference(outer_string)print('after,outer_string =',outer_string)
2 K7 o0 j' T9 x/ f7 A: x+ { 输出:
- o( t' L5 X; a/ O0 T8 }1 Zbefore,outer_string = It was many and many a year agogot It was many and many a year agoset to In a kingdom by the seaafter,outer_string = It was many and many a year ago6 U6 B0 ?+ e/ F) _! h5 ~$ B
同样,由于the_string参数是按值传递的,因此分配新字符串对方法外部代码没有影响。the_string是引用副本,outer_string我们the_string指向新字符串,但不能更改outer_string指向位置。, W: K+ ]$ @' X1 e- V. u( Y
我希望这能澄清一点。
- U+ W3 k0 X5 C7 G; S4 h编辑:有人指出没有回答@David 最初的问题,我能做些什么来通过实际引用传输变量?。让我们继续努力。
) j% b* Q6 Z/ h- P" k如何解决这个问题?正如@Andrea 的答案显示,您可以返回新值。这不会改变传递事物的方式,但它可以让你得到你想要的信息:6 A' j7 F: s& C$ L
def return_a_whole_new_string(the_string): new_string = something_to_do_with_the_old_string(the_string) return new_string# then you could call it likemy_string = return_a_whole_new_string(my_string)
7 w9 w( @: L6 t1 C: T 如果您真的想避免使用返回值,您可以创建一个类来保存您的值并将其传递给函数或使用现有类,如列表:
4 K; l" Z# h2 j# Cdef use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change): new_string = something_to_do_with_the_old_string(stuff_to_change stuff_to_change[0] = new_string# then you could call it likewrapper = [my_string]use_a_wrapper_to_simulate_pass_by_reference(wrapper)do_something_with(wrapper[0])
% {7 x0 O4 j: C% y' Z- r1 b, V* G 虽然看上去有点麻烦。 |
|