|
ython 文档似乎不清楚参数是通过引用传输还是通过值传输,以下代码生成未更改的值 ‘Original’' \4 }( ~' W! i" R
class PassByReference: def __init__(self): self.variable = 'Original self.change(self.variable) print(self.variable) def change(self,var): var = 'Changed'
9 O2 I( G/ k Q3 F$ r 通过实际引用传输变量,我能做些什么?
& {" B$ R7 ]+ f+ x# W8 a5 q C* Q e3 B* k: ]2 J
解决方案:
3 v8 L6 k( y1 ` 参数通过 assignment 传输。这背后的原因是双重的:
7 u7 F, @7 K: B$ S1 s* a+ [, L; c# f[ol]传入参数实际上是一个对象引用(但引用是按值传递的), H8 a& o5 {4 h/ ~! n$ M
有些数据类型是可变的,但有些不是[/ol]所以:$ ~$ U0 O0 M6 s# |/ x0 E
假如你要一个可变对象传递给一种方法,可以引用同一对象,可以随意改变,但如果重新绑定引用,外部作用域将一无所知,完成后,外部引用仍将指向原始对象。6 V& |7 }- i) ?) a" B, `! ^
如果将不可变对象传递给方法,仍然不能重新绑定外部引用,甚至不能改变对象。让我们举一些例子,以便更清楚。
7 @2 S% w+ R. @' Y% V2 j5 dList - 可变类型让我们尝试修改传递给方法的列表:/ G& t3 ^: V1 i0 [: @
def 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)
; a# l% ^* f% ]8 W8 n5 v4 {1 ^% f 输出:
+ X( e# z2 Y+ p1 D vbefore,outer_list = ['one','two','three']got ['one','two','three']changed to ['one','two','three','four']after,outer_list = ['one','two','three','four']
0 b' G$ I) [# t/ P, s h9 L 因为引入的参数是引用 outer_list,我们可以使用 而不是它的副本mutating list 改变方法,并在外部范围内反映改变。
5 Z F8 l9 L* c7 {0 ?现在让我们看看当我们试图将其更改为参数引用时会发生什么:, P0 B3 n3 d U! n2 `+ E6 C
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)2 ^& S& }. z* o; j4 m
输出:) x! L" ?9 A1 i/ t. `8 N5 v$ I
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']4 \ I/ G$ V" ?
由于the_list参数是按值传递的,所以分配新列表对方法外的代码没有影响。the_list是outer_list我们引用的副本the_list指向新列表,但不能更改outer_list指向位置。' U+ F/ q# q7 g
String - 不可变类型它是不可改变的,所以我们不能改变字符串的内容3 l5 M0 a2 d" A' ?. V( M
现在,让我们试着改变参考
+ Q0 i& _+ r0 Z. N, _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)
0 k, M2 Z# a& a* T e2 k 输出:$ I+ Y7 X" q7 x a. G
before,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 ago3 p) h8 j b, v* n4 z
同样,由于the_string参数是按值传递的,因此分配新字符串对方法外部代码没有影响。the_string是引用副本,outer_string我们the_string指向新字符串,但不能更改outer_string指向位置。
3 k4 s& n8 `1 }; t+ y( |$ A, j我希望这能澄清一点。: y( x* G# h+ I8 Q+ ~' W9 C7 i
编辑:有人指出没有回答@David 最初的问题,我能做些什么来通过实际引用传输变量?。让我们继续努力。
- y9 l6 V3 p. X3 w如何解决这个问题?正如@Andrea 的答案显示,您可以返回新值。这不会改变传递事物的方式,但它可以让你得到你想要的信息:
# N7 a+ j/ A5 w) E6 Ddef 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)
, y: H, H7 S$ C* i. [ 如果您真的想避免使用返回值,您可以创建一个类来保存您的值并将其传递给函数或使用现有类,如列表:
( l+ d+ f7 i6 Z- Hdef 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])
5 y" {' H% r% c: k3 A1 q3 t, c 虽然看上去有点麻烦。 |
|