Đối số được thông qua bởi sự phân công . Lý do đằng sau này là gấp đôi:
- tham số được truyền vào thực sự là một tham chiếu đến một đối tượng (nhưng tham chiếu được truyền theo giá trị)
- một số loại dữ liệu có thể thay đổi, nhưng một số khác thì không
Vì thế:
Nếu bạn truyền một đối tượng có thể thay đổi vào một phương thức, phương thức đó sẽ tham chiếu đến cùng một đối tượng đó và bạn có thể biến đổi nó thành niềm vui của trái tim bạn, nhưng nếu bạn bật lại 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 đó bạn đã hoàn thành, tham chiếu bên ngoài vẫn sẽ trỏ vào đối tượng ban đầu.
Nếu bạn truyền một đối tượng bất biến cho một phương thức, bạn vẫn không thể bật lại tham chiếu bên ngoài và thậm chí bạn 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 - một loại đột biến
Hãy thử sửa đổi danh sách đã được truyền cho 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 tham số, chúng ta có thể sử dụng các phương thức danh sách đột biến để thay đổi tham số 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ì xảy ra khi chúng ta cố gắng thay đổi tham chiếu được truyền vào dưới dạng 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']
Do the_list
tham số được truyền theo giá trị, việc gán một danh sách mới cho nó không có tác dụng mà mã bên ngoài phương thức có thể nhìn thấy. Đây the_list
là một bản sao của outer_list
tài liệu tham khảo và chúng tôi đã the_list
chỉ ra một danh sách mới, nhưng không có cách nào để thay đổi nơi outer_list
chỉ.
Chuỗi - một loại bất biến
Điều đó là bất biến, vì vậy chúng tôi không thể làm gì để 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, vì the_string
tham số được truyền theo giá trị, việc gán một chuỗi mới cho nó không có tác dụng mà mã bên ngoài phương thức có thể nhìn thấy. Đây the_string
là một bản sao của outer_string
tài liệu tham khảo và chúng tôi đã the_string
chỉ ra một chuỗi mới, nhưng không có cách nào để thay đổi nơi outer_string
chỉ.
Tôi hy vọng điều này sẽ làm sáng tỏ mọi thứ một chút.
EDIT: Lưu ý rằng điều này không trả lời câu hỏi mà ban đầu @David đã 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ế không?". Hãy làm việc đó.
Làm thế nào để chúng ta có được xung quanh này?
Như câu trả lời của @ Andrea cho thấy, 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 không cho phép bạn lấy lại thông tin bạn muốn:
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ả về, bạn có thể tạo một lớp để giữ giá trị của mình và chuyển nó vào hàm hoặc sử dụng một lớp hiện có, như một 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.