อาร์กิวเมนต์จะมีการส่งผ่านไปตามที่ได้รับมอบหมาย เหตุผลที่อยู่เบื้องหลังนี้คือสองเท่า:
- พารามิเตอร์ที่ส่งผ่านเป็นจริงการอ้างอิงไปยังวัตถุ (แต่การอ้างอิงถูกส่งผ่านตามค่า)
- ชนิดข้อมูลบางอย่างไม่แน่นอน แต่บางประเภทไม่
ดังนั้น:
หากคุณส่งวัตถุที่ไม่แน่นอนลงในวิธีการวิธีการได้รับการอ้างอิงไปยังวัตถุเดียวกันและคุณสามารถกลายพันธุ์เพื่อความสุขของหัวใจของคุณ แต่ถ้าคุณ rebind อ้างอิงในวิธีการที่ขอบเขตด้านนอกจะไม่รู้อะไรเกี่ยวกับมันและหลังจาก คุณทำเสร็จแล้วการอ้างอิงภายนอกจะยังคงชี้ไปที่วัตถุต้นฉบับ
หากคุณส่งวัตถุที่เปลี่ยนรูปไม่ได้ไปยังวิธีการคุณยังคงไม่สามารถเชื่อมโยงการอ้างอิงภายนอกและคุณไม่สามารถกลายพันธุ์วัตถุได้
เพื่อให้ชัดเจนยิ่งขึ้นลองมาตัวอย่าง
รายการ - ประเภทที่ไม่แน่นอน
ลองแก้ไขรายการที่ส่งผ่านไปยังเมธอด:
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)
เอาท์พุท:
before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']
เนื่องจากพารามิเตอร์ที่ส่งผ่านเป็นการอ้างอิงouter_list
ไม่ใช่สำเนาเราจึงสามารถใช้วิธีรายการเปลี่ยนแปลงเพื่อเปลี่ยนแปลงและมีการเปลี่ยนแปลงที่สะท้อนในขอบเขตด้านนอก
ทีนี้มาดูกันว่าจะเกิดอะไรขึ้นเมื่อเราพยายามเปลี่ยนการอ้างอิงที่ผ่านเป็นพารามิเตอร์:
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)
เอาท์พุท:
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']
เนื่องจากthe_list
พารามิเตอร์ถูกส่งผ่านตามค่าการกำหนดรายการใหม่ให้กับมันจึงไม่มีผลกระทบใด ๆ ที่โค้ดภายนอกเมธอดสามารถมองเห็นได้ นี่the_list
เป็นสำเนาของouter_list
ข้อมูลอ้างอิงและเราได้the_list
ชี้ไปที่รายการใหม่ แต่ไม่มีวิธีการเปลี่ยนแปลงที่outer_list
ชี้ไป
String - ชนิดไม่เปลี่ยนรูป
มันไม่เปลี่ยนรูปดังนั้นจึงไม่มีอะไรที่เราสามารถทำได้เพื่อเปลี่ยนเนื้อหาของสตริง
ตอนนี้เราลองเปลี่ยนการอ้างอิง
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)
เอาท์พุท:
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
อีกครั้งเนื่องจากthe_string
พารามิเตอร์ถูกส่งผ่านตามค่าการกำหนดสตริงใหม่ให้กับมันจะไม่มีผลกระทบใด ๆ ที่โค้ดภายนอกเมธอดสามารถมองเห็นได้ นี่the_string
เป็นสำเนาของการouter_string
อ้างอิงและเราได้the_string
ชี้ไปที่สตริงใหม่ แต่ไม่มีวิธีใดที่จะเปลี่ยนแปลงouter_string
ได้
ฉันหวังว่าสิ่งนี้จะช่วยล้างสิ่งเล็กน้อย
แก้ไข:มีการตั้งข้อสังเกตว่าสิ่งนี้ไม่ตอบคำถามที่ @David ถาม แต่เดิมว่า "มีสิ่งที่ฉันสามารถทำได้เพื่อส่งผ่านตัวแปรโดยการอ้างอิงจริงหรือไม่" มาทำงานกันดีกว่า
เราจะไปรอบนี้ได้อย่างไร
@ @ Andrea แสดงให้เห็นว่าคุณสามารถคืนค่าใหม่ สิ่งนี้จะไม่เปลี่ยนวิธีการส่งผ่านสิ่งต่างๆ แต่จะช่วยให้คุณได้รับข้อมูลที่คุณต้องการกลับมา:
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)
หากคุณต้องการหลีกเลี่ยงการใช้ค่าส่งคืนคุณสามารถสร้างคลาสเพื่อเก็บค่าของคุณและส่งไปยังฟังก์ชันหรือใช้คลาสที่มีอยู่เช่นรายการ:
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])
แม้ว่ามันจะดูยุ่งยากไปหน่อย