Câu hỏi Làm cách nào để chuyển một biến theo tham chiếu?


Tài liệu Python có vẻ không rõ ràng về việc liệu các tham số có được chuyển qua tham chiếu hay giá trị hay không và mã sau đây tạo ra giá trị không thay đổi 'Gốc'

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

Có cái gì tôi có thể làm để vượt qua biến bằng cách tham khảo thực tế?


2055
2018-06-12 10:23


gốc


Để giải thích / làm rõ ngắn, hãy xem câu trả lời đầu tiên cho câu hỏi stackoverflow này. Vì chuỗi không thay đổi, chúng sẽ không bị thay đổi và biến mới sẽ được tạo, do đó biến "bên ngoài" vẫn có cùng giá trị. - PhilS
Mã trong câu trả lời của BlairConrad là tốt, nhưng lời giải thích được cung cấp bởi DavidCournapeau và DarenThomas là chính xác. - Ethan Furman
Trước khi đọc câu trả lời đã chọn, vui lòng xem xét đọc văn bản ngắn này Các ngôn ngữ khác có "biến", Python có "tên". Hãy suy nghĩ về "tên" và "đối tượng" thay vì "biến" và "tham chiếu" và bạn nên tránh rất nhiều vấn đề tương tự. - lqc
Tại sao điều này không cần thiết sử dụng một lớp học? Đây không phải là Java: P - Peter R
một cách giải quyết khác là tạo một tham chiếu 'wrapper' như thế này: ref = type ('', (), {'n': 1}) stackoverflow.com/a/1123054/409638 - robert


Các câu trả lời:


Đối số là được chuyển giao theo bài tập. Lý do đằng sau này là gấp đôi:

  1. thông số được truyền vào thực tế là tài liệu tham khảo cho một đối tượng (nhưng tham chiếu được truyền theo giá trị)
  2. một số loại dữ liệu có thể thay đổi, nhưng các loại dữ liệu khác không

Vì thế:

  • Nếu bạn vượt qua có thể thay đổi đối tượng vào một phương thức, phương thức này được tham chiếu đến cùng một đối tượng đó và bạn có thể biến nó thành sự thỏa mãn của trái tim, nhưng nếu bạn rebind tham chiếu trong phương thức, phạm vi bên ngoài sẽ không biết gì về nó, và sau khi bạn hoàn thành, tham chiếu ngoài sẽ vẫn trỏ vào đối tượng gốc.

  • Nếu bạn vượt qua không thay đổi đối tượng với một phương thức, bạn vẫn không thể rebind tham chiếu ngoài, và bạn thậm chí không thể thay đổi đối tượng.

Để làm cho nó rõ ràng hơn, hãy có một số ví dụ.

Danh sách - loại có thể thay đổi

Hãy cố gắng sửa đổi danh sách đã được chuyển đến một phương thức:

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)

Đầu ra:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

Vì tham số được truyền vào là tham chiếu đến outer_list, không phải là bản sao của nó, chúng ta có thể sử dụng các phương thức liệt kê biến đổi để thay đổi nó và có các thay đổi được phản ánh trong phạm vi bên ngoài.

Bây giờ hãy xem điều gì sẽ xảy ra khi chúng tôi cố gắng thay đổi tham chiếu đã được chuyển thành tham số:

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)

Đầu ra:

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']

Kể từ khi the_list tham số được truyền theo giá trị, gán một danh sách mới cho nó không có hiệu lực là mã bên ngoài phương thức có thể thấy. Các the_list là một bản sao của outer_list và chúng tôi đã có the_list chỉ vào một danh sách mới, nhưng không có cách nào để thay đổi vị trí outer_list nhọn.

Chuỗi - một loại bất biến

Nó không thay đổi, vì vậy không có gì chúng ta có thể làm để thay đổi nội dung của chuỗi

Bây giờ, hãy thử thay đổi tham chiếu

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)

Đầu ra:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

Một lần nữa, kể từ khi the_string tham số được truyền theo giá trị, gán một chuỗi mới cho nó không có hiệu lực là mã bên ngoài phương thức có thể thấy. Các the_string là một bản sao của outer_string và chúng tôi đã có the_string trỏ đến một chuỗi mới, nhưng không có cách nào thay đổi vị trí outer_string nhọn.

Tôi hy vọng điều này sẽ làm rõ mọi thứ một chút.

CHỈNH SỬA: Nó được lưu ý rằng điều này không trả lời câu hỏi mà @David ban đầu hỏi, "Có điều gì tôi có thể làm để vượt qua biến bằng tham chiếu thực tế?". Hãy làm việc trên đó.

Làm thế nào để chúng ta có được điều này?

Như câu trả lời của @ Andrea, bạn có thể trả về giá trị mới. Điều này không thay đổi cách mọi thứ được truyền vào, nhưng cho phép bạn nhận được thông tin bạn muốn trả về:

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 like
my_string = return_a_whole_new_string(my_string)

Nếu bạn thực sự muốn tránh sử dụng giá trị trả lại, bạn có thể tạo một lớp để giữ giá trị của bạn và chuyển nó vào hàm hoặc sử dụng lớp hiện có, như danh sách:

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
    new_string = something_to_do_with_the_old_string(stuff_to_change[0])
    stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

Mặc dù điều này có vẻ hơi cồng kềnh.


2225
2018-06-12 11:18



Sau đó, tương tự là trong C, khi bạn vượt qua "bằng cách tham khảo" bạn đang thực sự đi qua theo giá trị tham chiếu ... Xác định "theo tham chiếu": P - Andrea Ambu
Tôi không chắc tôi hiểu các điều khoản của bạn. Tôi đã ra khỏi trò chơi C trong một thời gian, nhưng khi tôi ở trong đó, không có "vượt qua tham chiếu" - bạn có thể vượt qua mọi thứ, và nó luôn vượt qua giá trị, vì vậy bất cứ điều gì nằm trong danh sách tham số đã được sao chép. Nhưng đôi khi điều đó là một con trỏ, cái mà có thể đi theo mảnh bộ nhớ (nguyên thủy, mảng, cấu trúc, bất cứ điều gì), nhưng bạn không thể thay đổi con trỏ được sao chép từ phạm vi bên ngoài - khi bạn đã hoàn thành với hàm , con trỏ ban đầu vẫn trỏ đến cùng một địa chỉ. C ++ giới thiệu tài liệu tham khảo, hoạt động khác nhau. - Blair Conrad
@Zac Bowling Tôi không thực sự hiểu được những gì bạn đang nói là có liên quan, theo nghĩa thực tế, cho câu trả lời này. Nếu một người mới sử dụng Python muốn biết về việc chuyển qua ref / val, thì takeaway từ câu trả lời này là: 1- Bạn có thể sử dụng tham chiếu mà hàm nhận được dưới dạng đối số của nó, để sửa đổi giá trị 'bên ngoài' của một biến, miễn là bạn không gán lại tham số để tham chiếu đến một đối tượng mới. 2- Chỉ định cho loại không thay đổi sẽ luôn luôn tạo một đối tượng mới, phá vỡ tham chiếu mà bạn đã có với biến bên ngoài. - Cam Jackson
@CamJackson, bạn cần một ví dụ tốt hơn - các con số cũng là các đối tượng bất biến trong Python. Bên cạnh đó, sẽ không đúng khi nói rằng bất kì phép gán mà không có chỉ số ở phía bên trái của equals sẽ gán lại tên cho một đối tượng mới cho dù đó là bất biến hay không? def Foo(alist): alist = [1,2,3]sẽ không phải sửa đổi nội dung của danh sách từ góc độ người gọi. - Mark Ransom
-1. Mã hiển thị là tốt, giải thích như thế nào là hoàn toàn sai. Xem câu trả lời của DavidCournapeau hoặc DarenThomas để được giải thích chính xác về lý do tại sao. - Ethan Furman


Vấn đề xuất phát từ một sự hiểu lầm về những biến trong Python. Nếu bạn quen với hầu hết các ngôn ngữ truyền thống, bạn có một mô hình tinh thần về những gì xảy ra trong chuỗi sau:

a = 1
a = 2

Bạn có tin rằng a là vị trí bộ nhớ lưu trữ giá trị 1, sau đó được cập nhật để lưu trữ giá trị 2. Đó không phải là cách mọi thứ hoạt động trong Python. Hơn, a bắt đầu như một tham chiếu đến một đối tượng có giá trị 1, sau đó được gán lại như một tham chiếu đến một đối tượng có giá trị 2. Hai vật thể đó có thể tiếp tục cùng tồn tại mặc dù a không đề cập đến cái đầu tiên nữa; trên thực tế, chúng có thể được chia sẻ bởi bất kỳ số tham chiếu nào khác trong chương trình.

Khi bạn gọi hàm có tham số, tham chiếu mới được tạo cho biết đối tượng được truyền vào. Điều này tách biệt khỏi tham chiếu được sử dụng trong hàm gọi, vì vậy không có cách nào cập nhật tham chiếu đó và làm cho nó tham chiếu đến đối tượng mới. Trong ví dụ của bạn:

def __init__(self):
    self.variable = 'Original'
    self.Change(self.variable)

def Change(self, var):
    var = 'Changed'

self.variable là một tham chiếu đến đối tượng chuỗi 'Original'. Khi bạn gọi Change bạn tạo tham chiếu thứ hai var cho đối tượng. Bên trong hàm bạn gán lại tham chiếu var đối tượng chuỗi khác 'Changed', nhưng tham khảo self.variable là riêng biệt và không thay đổi.

Cách duy nhất xung quanh điều này là để vượt qua một đối tượng có thể thay đổi. Bởi vì cả hai tham chiếu đều đề cập đến cùng một đối tượng, bất kỳ thay đổi nào đối tượng được phản ánh ở cả hai vị trí.

def __init__(self):         
    self.variable = ['Original']
    self.Change(self.variable)

def Change(self, var):
    var[0] = 'Changed'

530
2017-11-15 17:45



Giải thích ngắn gọn. Đoạn của bạn "Khi bạn gọi một hàm ..." là một trong những giải thích tốt nhất mà tôi đã nghe về cụm từ khá khó hiểu rằng 'tham số hàm Python là tham chiếu, được truyền theo giá trị.' Tôi nghĩ nếu bạn hiểu đoạn đó một mình, mọi thứ khác chỉ có ý nghĩa và chảy như một kết luận hợp lý từ đó. Sau đó, bạn chỉ cần phải nhận thức được khi bạn đang tạo một đối tượng mới và khi bạn đang sửa đổi một đối tượng hiện có. - Cam Jackson
Nhưng làm cách nào bạn có thể gán lại tham chiếu? Tôi nghĩ bạn không thể thay đổi địa chỉ của 'var' nhưng chuỗi của bạn "Thay đổi" bây giờ sẽ được lưu trữ trong địa chỉ bộ nhớ 'var'. Mô tả của bạn làm cho nó có vẻ như "Thay đổi" và "Gốc" thuộc về những nơi khác nhau trong bộ nhớ thay vào đó và bạn chỉ cần chuyển 'var' sang một địa chỉ khác. Đúng không? - Glassjawed
@ Glassjawed, tôi nghĩ rằng bạn đang nhận được nó. "Đã thay đổi" và "Gốc" là hai đối tượng chuỗi khác nhau tại các địa chỉ bộ nhớ khác nhau và các thay đổi 'var' từ trỏ đến một để trỏ đến điểm khác. - Mark Ransom
đây là giải thích tốt nhất và nên là câu trả lời được chấp nhận. Ngắn gọn, ngắn gọn và rõ ràng. Những người khác đồng xu các thuật ngữ mới, khó hiểu như 'tham chiếu được truyền theo giá trị', 'gọi là đối tượng', v.v. Câu trả lời này xóa mọi thứ. Cảm ơn :) - ajay
sử dụng hàm id () giúp làm rõ các vấn đề, bởi vì nó làm cho nó rõ ràng khi Python tạo một đối tượng mới (vì vậy tôi nghĩ, dù sao). - Tim Richardson


Tôi tìm thấy các câu trả lời khác khá dài và phức tạp, vì vậy tôi đã tạo ra sơ đồ đơn giản này để giải thích cách Python xử lý các biến và tham số. enter image description here


243
2017-09-04 16:05



Sơ đồ của bạn làm sáng tỏ khái niệm cơ bản tốt mặc dù tôi sẽ không gọi các câu trả lời khác dài và phức tạp. - Bruce Wayne
Một lời giải thích rất tao nhã. Tôi nghĩ các câu trả lời khác cũng dài và phức tạp. Làm tốt lắm! - kirk.burleson
Nó không quan trọng nếu A có thể thay đổi hay không. Nếu bạn gán thứ gì đó khác với B, A không thay đổi. Nếu một đối tượng có thể thay đổi, bạn có thể thay đổi nó, chắc chắn. Nhưng điều đó không liên quan gì đến việc gán trực tiếp vào một cái tên .. - Martijn Pieters♦
Cảm ơn bạn đã cập nhật, tốt hơn nhiều! Điều gây nhầm lẫn cho hầu hết mọi người là gán cho một thuê bao; ví dụ. B[0] = 2, so với chuyển nhượng trực tiếp, B = 2. - Martijn Pieters♦
"A được gán cho B." Đó không phải là mơ hồ? Tôi nghĩ bằng tiếng Anh thông thường có thể có nghĩa là A=B hoặc là B=A. - Hatshepsut


Nó không phải là pass-by-value hoặc pass-by-reference - nó là call-by-object. Xem này, bởi Fredrik Lundh:

http://effbot.org/zone/call-by-object.htm

Dưới đây là một trích dẫn quan trọng:

"... biến [tên] là không phải các đối tượng; chúng không thể được biểu thị bằng các biến khác hoặc được gọi bởi các đối tượng. "

Trong ví dụ của bạn, khi Change phương thức được gọi là - a không gian tên được tạo ra cho nó; và var trở thành một tên, trong không gian tên đó, cho đối tượng chuỗi 'Original'. Đối tượng đó sau đó có một tên trong hai không gian tên. Kế tiếp, var = 'Changed' liên kết var đối tượng chuỗi mới và do đó không gian tên của phương thức quên về 'Original'. Cuối cùng, không gian tên đó bị lãng quên và chuỗi 'Changed' cùng với nó.


220
2018-06-12 12:55



Tôi thấy khó mua. Đối với tôi cũng giống như Java, các tham số là con trỏ tới các đối tượng trong bộ nhớ, và các con trỏ đó được truyền qua ngăn xếp hoặc các thanh ghi. - Luciano
Đây không phải là java. Một trong những trường hợp mà nó không giống nhau là các đối tượng bất biến. Hãy suy nghĩ về hàm lambda x: x. Áp dụng điều này cho x = [1, 2, 3] và x = (1, 2, 3). Trong trường hợp đầu tiên, giá trị trả về sẽ là bản sao của đầu vào và giống hệt trong trường hợp thứ hai. - David Cournapeau
Không, đó là chính xác giống như ngữ nghĩa của Java cho các đối tượng. Tôi không chắc chắn ý bạn là gì "Trong trường hợp đầu tiên, giá trị trả lại sẽ là bản sao của dữ liệu đầu vào và giống hệt trong trường hợp thứ hai." nhưng tuyên bố đó có vẻ không chính xác. - Mike Graham
Nó chính xác giống như trong Java. Các tham chiếu đối tượng được truyền theo giá trị. Bất kỳ ai nghĩ khác nên đính kèm mã Python cho swap chức năng có thể hoán đổi hai tham chiếu, như sau: a = [42] ; b = 'Hello'; swap(a, b) # Now a is 'Hello', b is [42] - cayhorstmann
Nó chính xác giống như Java khi bạn truyền các đối tượng trong Java. Tuy nhiên, Java cũng có các nguyên thủy, được truyền bằng cách sao chép giá trị của nguyên thủy. Vì vậy, chúng khác nhau trong trường hợp đó. - Claudiu


Hãy suy nghĩ về những thứ được truyền bằng cách gán thay vì bằng tham chiếu / theo giá trị. Bằng cách đó, nó là allways rõ ràng, những gì đang xảy ra miễn là bạn hiểu những gì xảy ra trong phân công bình thường.

Vì vậy, khi chuyển danh sách sang một hàm / phương thức, danh sách được gán cho tên tham số. Việc thêm vào danh sách sẽ dẫn đến danh sách bị sửa đổi. Chỉ định lại danh sách phía trong chức năng sẽ không thay đổi danh sách gốc, vì:

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b      # prints [1, 2, 3, 4] ['a', 'b']

Vì các loại bất biến không thể sửa đổi được, chúng hình như giống như được truyền theo giá trị - chuyển một int vào một hàm có nghĩa là gán int cho tham số hàm. Bạn chỉ có thể gán lại điều đó, nhưng nó sẽ không thay đổi giá trị biến ban đầu.


142
2018-06-12 12:17



Thoạt nhìn, câu trả lời này dường như đã bỏ qua câu hỏi ban đầu. Sau một lần đọc thứ hai tôi đã nhận ra rằng điều này làm cho vấn đề khá rõ ràng. Theo dõi khái niệm "gán tên" tốt có thể tìm thấy ở đây: Code Giống như Pythonista: Python độc đáo - Christian Groleau


Effbot (còn gọi là Fredrik Lundh) đã mô tả phong cách chuyển biến của Python như là một đối tượng gọi: http://effbot.org/zone/call-by-object.htm

Các đối tượng được phân bổ trên heap và các con trỏ tới chúng có thể được truyền đi khắp mọi nơi.

  • Khi bạn thực hiện một nhiệm vụ như x = 1000, một mục từ điển được tạo ra để ánh xạ chuỗi "x" trong không gian tên hiện tại tới một con trỏ tới đối tượng số nguyên chứa một nghìn.

  • Khi bạn cập nhật "x" với x = 2000, một đối tượng số nguyên mới được tạo và từ điển được cập nhật để trỏ vào đối tượng mới. Một nghìn đối tượng cũ không thay đổi (và có thể hoặc không thể sống tùy thuộc vào việc có bất kỳ điều gì khác đề cập đến đối tượng) hay không.

  • Khi bạn thực hiện một nhiệm vụ mới như y = x, một mục từ điển mới "y" được tạo ra trỏ đến cùng một đối tượng như mục nhập cho "x".

  • Các đối tượng như chuỗi và số nguyên là không thay đổi. Điều này đơn giản có nghĩa là không có phương thức nào có thể thay đổi đối tượng sau khi nó được tạo ra. Ví dụ, một khi đối tượng số nguyên một nghìn được tạo ra, nó sẽ không bao giờ thay đổi. Toán được thực hiện bằng cách tạo các đối tượng số nguyên mới.

  • Các đối tượng như danh sách có thể thay đổi. Điều này có nghĩa rằng nội dung của đối tượng có thể được thay đổi bởi bất cứ điều gì trỏ đến đối tượng. Ví dụ, x = []; y = x; x.append(10); print y sẽ in [10]. Danh sách trống đã được tạo. Cả hai "x" và "y" trỏ đến cùng một danh sách. Các nối thêm phương thức thay đổi (cập nhật) đối tượng danh sách (như thêm bản ghi vào cơ sở dữ liệu) và kết quả hiển thị cho cả "x" và "y" (giống như cập nhật cơ sở dữ liệu sẽ hiển thị cho mọi kết nối đến cơ sở dữ liệu đó).

Hy vọng rằng làm rõ vấn đề cho bạn.


53
2018-03-29 04:41



Tôi thực sự đánh giá cao việc học về điều này từ một nhà phát triển. Có đúng là id() hàm trả về giá trị của con trỏ (tham chiếu đối tượng), như câu trả lời của pepr gợi ý? - Honest Abe
@HonestAbe Có, trong CPython ID() trả về địa chỉ. Nhưng trong pythons khác như PyPy và Jython, ID() chỉ là một định danh đối tượng duy nhất. - Raymond Hettinger
Những câu trả lời khác khiến tôi ngạc nhiên và bối rối. Điều này xóa tất cả lên. Cảm ơn. - shongololo
câu trả lời này, cộng với gợi ý sử dụng id () cho thấy khi một bài tập liên kết một tên hiện có với một đối tượng mới, là tốt nhất trong toàn bộ chuỗi. - Tim Richardson
Câu trả lời này không được tiết lộ. - wandadars


Về mặt kỹ thuật, Python luôn sử dụng thông qua các giá trị tham chiếu. Tôi sẽ lặp lại câu trả lời khác của tôi để hỗ trợ tuyên bố của tôi.

Python luôn sử dụng các giá trị tham chiếu. Không có ngoại lệ. Bất kỳ phép gán nào có nghĩa là sao chép giá trị tham chiếu. Không có ngoại lệ. Biến bất kỳ là tên được gắn với giá trị tham chiếu. Luôn luôn.

Bạn có thể nghĩ về giá trị tham chiếu làm địa chỉ của đối tượng đích. Địa chỉ được tự động hủy đăng ký khi được sử dụng. Bằng cách này, làm việc với giá trị tham chiếu, có vẻ như bạn làm việc trực tiếp với đối tượng đích. Nhưng luôn luôn có một tham chiếu ở giữa, một bước nữa để nhảy tới mục tiêu.

Dưới đây là ví dụ chứng minh rằng Python sử dụng đi qua tham chiếu:

Illustrated example of passing the argument

Nếu đối số được truyền theo giá trị, bên ngoài lst không thể sửa đổi. Màu xanh lá cây là các đối tượng mục tiêu (màu đen là giá trị được lưu trữ bên trong, màu đỏ là loại đối tượng), màu vàng là bộ nhớ có giá trị tham chiếu bên trong - được vẽ dưới dạng mũi tên. Mũi tên rắn màu xanh lam là giá trị tham chiếu đã được chuyển đến hàm (thông qua đường mũi tên màu xanh đứt quãng). Màu vàng tối xấu xí là từ điển nội bộ. (Nó thực sự có thể được vẽ cũng như một hình elip màu xanh lá cây. Màu sắc và hình dạng chỉ nói rằng nó là nội bộ.)

Bạn có thể dùng id() được xây dựng trong chức năng để tìm hiểu những gì giá trị tham chiếu là (có nghĩa là, địa chỉ của đối tượng mục tiêu).

Trong các ngôn ngữ được biên dịch, một biến là một không gian bộ nhớ có khả năng nắm bắt được giá trị của kiểu. Trong Python, một biến là một tên (được giữ bên trong như một chuỗi) được liên kết với biến tham chiếu chứa giá trị tham chiếu đến đối tượng đích. Tên của biến là khóa trong từ điển nội bộ, phần giá trị của mục từ điển đó lưu trữ giá trị tham chiếu đến đích.

Các giá trị tham chiếu được ẩn trong Python. Không có bất kỳ loại người dùng rõ ràng nào để lưu trữ giá trị tham chiếu. Tuy nhiên, bạn có thể sử dụng phần tử danh sách (hoặc phần tử trong bất kỳ loại vùng chứa phù hợp nào khác) làm biến tham chiếu, vì tất cả các thùng chứa đều lưu trữ các phần tử cũng như tham chiếu đến các đối tượng đích. Nói cách khác, các phần tử thực sự không được chứa bên trong thùng chứa - chỉ các tham chiếu đến các phần tử là.


53
2017-09-15 18:53



Trên thực tế, điều này được xác nhận thông qua giá trị tham chiếu. 1 cho câu trả lời này mặc dù ví dụ là không tốt. - BugShotGG
Phát minh thuật ngữ mới (chẳng hạn như "truyền bằng giá trị tham chiếu" hoặc "gọi theo đối tượng" không hữu ích). "Gọi theo (giá trị | tham chiếu | tên)" là các thuật ngữ chuẩn. "tham chiếu" là thuật ngữ chuẩn. Việc truyền tham chiếu theo giá trị mô tả chính xác hành vi của Python, Java và một loạt các ngôn ngữ khác, sử dụng thuật ngữ chuẩn. - cayhorstmann
@cayhorstmann: Vấn đề là Biến Python không có cùng một thuật ngữ như trong các ngôn ngữ khác. Cách này, gọi bằng tham chiếu không vừa ở đây. Ngoài ra, bạn thế nào chính xác Xác định thuật ngữ tài liệu tham khảo? Một cách không chính thức, cách Python có thể dễ dàng được mô tả là truyền địa chỉ của đối tượng. Nhưng nó không phù hợp với việc triển khai Python có khả năng phân tán. - pepr
Tôi thích câu trả lời này, nhưng bạn có thể xem xét nếu ví dụ này thực sự giúp đỡ hoặc làm tổn thương dòng chảy. Ngoài ra, nếu bạn thay thế 'giá trị tham chiếu' bằng 'tham chiếu đối tượng', bạn sẽ sử dụng thuật ngữ mà chúng tôi có thể xem xét 'chính thức', như được thấy ở đây: Định nghĩa hàm - Honest Abe
Có một chú thích ở phần cuối của câu trích dẫn đó: "Thực ra, gọi bằng tham chiếu đối tượng sẽ là một mô tả tốt hơn, vì nếu một đối tượng có thể thay đổi được thông qua, người gọi sẽ thấy bất kỳ thay đổi nào mà callee tạo ra cho nó ... " Tôi đồng ý với bạn rằng sự nhầm lẫn là do cố gắng phù hợp với thuật ngữ được thiết lập với các ngôn ngữ khác. Ngoài ngữ nghĩa, những thứ cần được hiểu là: từ điển / không gian tên, tên hoạt động ràng buộc và mối quan hệ của tên → con trỏ → đối tượng (như bạn đã biết). - Honest Abe


Một mẹo đơn giản mà tôi thường sử dụng là chỉ quấn nó vào một danh sách:

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(Vâng, tôi biết điều này có thể bất tiện, nhưng đôi khi nó đơn giản, đủ để làm điều này.)


36
2017-08-05 22:52



1 cho số lượng văn bản nhỏ đưa ra cách giải quyết cần thiết cho vấn đề của Python không có tham chiếu pass-by-reference. (Như một bình luận / câu hỏi tiếp theo phù hợp ở đây cũng như bất cứ nơi nào trên trang này: Không rõ lý do tại sao python không thể cung cấp từ khóa "ref" như C #, chỉ đơn giản là kết thúc đối số của người gọi trong danh sách như điều này và xử lý các tham chiếu đến đối số bên trong hàm làm phần tử thứ 0 của danh sách.) - M Katz
Tốt đẹp. Để chuyển qua ref, quấn trong []. - Justas
Tuyệt vời, cũng được thực hiện để tránh tất cả các pontification. - Puffin