ไม่มีคำตอบที่นี่ให้รหัสใด ๆ ให้คุณทำงานเพื่อแสดงให้เห็นว่าทำไมสิ่งนี้เกิดขึ้นในดินแดนหลาม และนี่คือความสนุกในการดูในเชิงลึกมากขึ้นดังนั้นที่นี่จะไป
สาเหตุหลักที่ไม่สามารถใช้งานได้ตามที่คุณคาดหวังเพราะใน Python เมื่อคุณเขียน:
i += 1
มันไม่ได้ทำในสิ่งที่คุณคิดว่ามันกำลังทำอยู่ จำนวนเต็มไม่เปลี่ยนรูป สิ่งนี้สามารถเห็นได้เมื่อคุณตรวจสอบสิ่งที่เป็นวัตถุใน Python:
a = 0
print('ID of the first integer:', id(a))
a += 1
print('ID of the first integer +=1:', id(a))
ฟังก์ชัน idแสดงค่าที่ไม่ซ้ำใครและคงที่สำหรับวัตถุในช่วงอายุการใช้งาน โดยทั่วไปแล้วจะจับคู่กับที่อยู่หน่วยความจำใน C / C ++ ใช้รหัสข้างต้น:
ID of the first integer: 140444342529056
ID of the first integer +=1: 140444342529088
ซึ่งหมายความว่ารายการแรกa
ไม่เหมือนกันเป็นครั้งที่สองa
เนื่องจากรหัสของพวกเขาแตกต่างกัน อย่างมีประสิทธิภาพพวกเขาอยู่ในสถานที่ที่แตกต่างกันในหน่วยความจำ
อย่างไรก็ตามด้วยวัตถุสิ่งต่าง ๆ ก็ทำงานต่างกัน ฉันเขียนทับ+=
โอเปอเรเตอร์ที่นี่:
class CustomInt:
def __iadd__(self, other):
# Override += 1 for this class
self.value = self.value + other.value
return self
def __init__(self, v):
self.value = v
ints = []
for i in range(5):
int = CustomInt(i)
print('ID={}, value={}'.format(id(int), i))
ints.append(int)
for i in ints:
i += CustomInt(i.value)
print("######")
for i in ints:
print('ID={}, value={}'.format(id(i), i.value))
การรันผลลัพธ์นี้ในเอาต์พุตต่อไปนี้:
ID=140444284275400, value=0
ID=140444284275120, value=1
ID=140444284275064, value=2
ID=140444284310752, value=3
ID=140444284310864, value=4
######
ID=140444284275400, value=0
ID=140444284275120, value=2
ID=140444284275064, value=4
ID=140444284310752, value=6
ID=140444284310864, value=8
โปรดสังเกตว่าแอตทริบิวต์ id ในกรณีนี้จริง ๆ แล้วเหมือนกันสำหรับการทำซ้ำทั้งสองแม้ว่าค่าของวัตถุจะแตกต่างกัน (คุณยังสามารถค้นหาid
ค่า int ที่วัตถุเก็บไว้ซึ่งจะเปลี่ยนตามที่กลายพันธุ์ - เนื่องจากจำนวนเต็ม ไม่เปลี่ยนรูป)
เปรียบเทียบสิ่งนี้กับเมื่อคุณเรียกใช้แบบฝึกหัดเดียวกันกับวัตถุที่เปลี่ยนรูปไม่ได้:
ints_primitives = []
for i in range(5):
int = i
ints_primitives.append(int)
print('ID={}, value={}'.format(id(int), i))
print("######")
for i in ints_primitives:
i += 1
print('ID={}, value={}'.format(id(int), i))
print("######")
for i in ints_primitives:
print('ID={}, value={}'.format(id(i), i))
ผลลัพธ์นี้:
ID=140023258889248, value=0
ID=140023258889280, value=1
ID=140023258889312, value=2
ID=140023258889344, value=3
ID=140023258889376, value=4
######
ID=140023258889280, value=1
ID=140023258889312, value=2
ID=140023258889344, value=3
ID=140023258889376, value=4
ID=140023258889408, value=5
######
ID=140023258889248, value=0
ID=140023258889280, value=1
ID=140023258889312, value=2
ID=140023258889344, value=3
ID=140023258889376, value=4
สิ่งเล็ก ๆ น้อย ๆ ที่นี่เพื่อแจ้งให้ทราบล่วงหน้า ก่อนอื่นในลูปที่มี+=
, คุณจะไม่เพิ่มวัตถุต้นฉบับอีกต่อไป ในกรณีนี้เนื่องจาก int อยู่ในประเภทที่ไม่เปลี่ยนรูปแบบใน Python , python จึงใช้ id อื่น สิ่งที่น่าสนใจที่จะทราบว่า Python ใช้พื้นฐานที่เหมือนกันid
สำหรับตัวแปรหลายตัวที่มีค่าไม่เปลี่ยนรูปแบบเดียวกัน:
a = 1999
b = 1999
c = 1999
print('id a:', id(a))
print('id b:', id(b))
print('id c:', id(c))
id a: 139846953372048
id b: 139846953372048
id c: 139846953372048
tl; dr - Python มีประเภทที่ไม่เปลี่ยนรูปจำนวนหนึ่งซึ่งทำให้เกิดพฤติกรรมที่คุณเห็น สำหรับประเภทที่ไม่แน่นอนทั้งหมดความคาดหวังของคุณถูกต้อง
i
ไม่เปลี่ยนรูปหรือคุณกำลังดำเนินการไม่เปลี่ยนแปลง รายการที่ซ้อนfor i in a: a.append(1)
จะมีพฤติกรรมที่แตกต่างกัน Python ไม่ได้คัดลอกรายการที่ซ้อนกัน อย่างไรก็ตามจำนวนเต็มไม่เปลี่ยนรูปและการเพิ่มส่งคืนวัตถุใหม่จะไม่เปลี่ยนวัตถุเก่า