ขอบเขตของตัวแปรที่เริ่มต้นในคำสั่ง if คืออะไร


266

ฉันใหม่กับ Python ดังนั้นนี่อาจเป็นคำถามที่ง่าย รหัสต่อไปนี้ในไฟล์ Python (โมดูล) ทำให้ฉันสับสนเล็กน้อย:

if __name__ == '__main__':
    x = 1

print x

ในภาษาอื่น ๆ ที่ฉันเคยทำงานรหัสนี้จะทำให้เกิดข้อยกเว้นเนื่องจากxตัวแปรอยู่ในifคำสั่งและไม่ควรอยู่นอก แต่รหัสนี้ทำงานและพิมพ์ 1. ทุกคนสามารถอธิบายพฤติกรรมนี้ได้หรือไม่? ตัวแปรทั้งหมดถูกสร้างในโมดูลโกลบอล / มีให้สำหรับโมดูลทั้งหมดหรือไม่?


17
มุมแหลมอื่นที่คุณอาจจะไม่ได้ตระหนักถึง: ถ้าifคำสั่งดังกล่าวไม่ถือเป็นจริง (เช่น__name__เป็นไม่ได้ '__main__'ตัวอย่างเช่นเมื่อคุณนำเข้าโมดูลแทนการรันมันระดับบนสุด) แล้วxจะไม่ได้รับการผูกไว้และต่อมาprint xคำสั่ง NameError: name 'x' is not definedจะโยน
Santa

คำตอบ:


302

ตัวแปร Python ถูกกำหนดขอบเขตไว้ที่ฟังก์ชันชั้นในสุดคลาสหรือโมดูลที่ได้รับมอบหมาย บล็อกควบคุมเช่นifและwhileบล็อกไม่นับรวมดังนั้นตัวแปรที่กำหนดภายในifยังคงถูกกำหนดขอบเขตให้กับฟังก์ชันคลาสหรือโมดูล

(ฟังก์ชั่นโดยปริยายที่กำหนดโดยการแสดงออกกำเนิดหรือรายการ / ชุด / Dict เข้าใจทำนับเช่นเดียวกับการแสดงออกแลมบ์ดา. คุณไม่สามารถสิ่งที่เป็นคำสั่งที่ได้รับมอบหมายลงในใด ๆ ของเหล่านั้น แต่พารามิเตอร์แลมบ์ดาและforเป้าหมายข้อที่มีการกำหนดโดยปริยาย.)



105

ใช่พวกเขาอยู่ใน "ขอบเขตภายใน" เดียวกันและรหัสจริงเช่นนี้เป็นเรื่องธรรมดาใน Python:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

โปรดทราบว่าxจะไม่ถูกประกาศหรือเตรียมใช้งานก่อนเงื่อนไขเช่นใน C หรือ Java

กล่าวอีกนัยหนึ่ง Python ไม่มีขอบเขตระดับบล็อก แต่ระวังด้วยตัวอย่างเช่น

if False:
    x = 3
print(x)

ซึ่งจะทำให้เกิดNameErrorข้อยกเว้นอย่างชัดเจน


42

ขอบเขตในหลามตามคำสั่งนี้:

  • ค้นหาขอบเขตในเครื่อง

  • ค้นหาขอบเขตของฟังก์ชั่นการปิดล้อม

  • ค้นหาขอบเขตทั่วโลก

  • ค้นหาในตัว

(ที่มา )

โปรดสังเกตว่าifและการสร้างลูป / การแยกสาขาอื่น ๆ ไม่อยู่ในรายการคลาสเท่านั้นฟังก์ชันและโมดูลมีขอบเขตใน Python ดังนั้นสิ่งใดก็ตามที่ประกาศในifบล็อกจะมีขอบเขตเดียวกับสิ่งที่ประกาศนอกบล็อก ตัวแปรไม่ได้ถูกตรวจสอบ ณ เวลารวบรวมซึ่งเป็นสาเหตุที่ภาษาอื่น ๆ ส่งข้อยกเว้น ในไพ ธ อนตราบใดที่ตัวแปรมีอยู่ในเวลาที่คุณต้องการมันจะไม่มีข้อยกเว้นเกิดขึ้น


9

ดังที่ Eli กล่าวว่า Python ไม่ต้องการการประกาศตัวแปร ใน C คุณจะพูดว่า:

int x;
if(something)
    x = 1;
else
    x = 2;

แต่ในการประกาศ Python นั้นมีความหมายโดยนัยดังนั้นเมื่อคุณกำหนดให้กับ x มันจะถูกประกาศโดยอัตโนมัติ เป็นเพราะไพ ธ อนพิมพ์แบบไดนามิก - มันจะไม่ทำงานในภาษาที่พิมพ์แบบคงที่เพราะขึ้นอยู่กับเส้นทางที่ใช้ตัวแปรอาจถูกนำมาใช้โดยไม่ต้องมีการประกาศ สิ่งนี้จะถูกรวบรวมในภาษาที่พิมพ์แบบคงที่ แต่ด้วยภาษาที่พิมพ์แบบไดนามิกจะได้รับอนุญาต

เหตุผลเดียวที่ภาษาที่พิมพ์แบบสแตติกถูก จำกัด ให้ประกาศตัวแปรนอกifข้อความในเนื่องจากปัญหานี้ โอบกอดแบบไดนามิก!


9

ซึ่งแตกต่างจากภาษาเช่น C, ตัวแปร Python อยู่ในขอบเขตสำหรับฟังก์ชั่นทั้งหมด (หรือคลาสหรือโมดูล) ที่มันปรากฏไม่เพียง แต่ใน "บล็อก" ด้านในสุด ราวกับว่าคุณประกาศint xที่ด้านบนของฟังก์ชั่น (หรือคลาสหรือโมดูล) ยกเว้นว่าใน Python คุณไม่จำเป็นต้องประกาศตัวแปร

โปรดทราบว่าการมีอยู่ของตัวแปรxนั้นจะถูกตรวจสอบเฉพาะตอนรันไทม์นั่นคือเมื่อคุณไปที่print xคำสั่ง ถ้า__name__ไม่ได้เท่ากับแล้วคุณจะได้รับการยกเว้น"__main__"NameError: name 'x' is not defined


คลาสไม่สร้างขอบเขต ตัวแปร "local" ในคลาสนั้นถูกเพิ่มเข้ากับ dict ของคลาสเมื่อสร้าง
chepner

3

ใช่. มันเป็นความจริงสำหรับforขอบเขต แต่ไม่ใช่ฟังก์ชั่นแน่นอน

ในตัวอย่างของคุณ: หากเงื่อนไขในifคำสั่งเป็นเท็จxจะไม่ถูกกำหนด


2

คุณกำลังรันโค้ดนี้จากบรรทัดคำสั่งดังนั้นifเงื่อนไขเป็นจริงและxตั้งค่าไว้ เปรียบเทียบ:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined

0

และโปรดทราบว่าเนื่องจากประเภท Python ถูกตรวจสอบเฉพาะตอนรันไทม์คุณจึงสามารถมีรหัสดังนี้:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

แต่ฉันมีปัญหาในการคิดวิธีอื่น ๆ ที่รหัสจะทำงานโดยไม่มีข้อผิดพลาดเนื่องจากปัญหาประเภท

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.