การกำหนดขอบเขตใน Python 'เป็น' ลูป


177

ฉันไม่ได้ถามเกี่ยวกับกฎการกำหนดขอบเขตของไพ ธ อน ฉันเข้าใจโดยทั่วไปว่าการกำหนดขอบเขตทำงานใน Python สำหรับลูป คำถามของฉันคือทำไมการตัดสินใจออกแบบในลักษณะนี้ ตัวอย่างเช่น (ไม่มีการเล่นสำนวนเจตนา):

for foo in xrange(10):
    bar = 2
print(foo, bar)

ด้านบนจะพิมพ์ (9,2)

สิ่งนี้ทำให้ฉันแปลกประหลาด: 'foo' เป็นเพียงการควบคุมวงและ 'บาร์' ถูกกำหนดไว้ในวง ฉันสามารถเข้าใจได้ว่าทำไมมันอาจจำเป็นสำหรับ 'บาร์' ที่จะสามารถเข้าถึงได้นอกลูป (มิฉะนั้นสำหรับลูปจะมีฟังก์ชันที่ จำกัด มาก) สิ่งที่ฉันไม่เข้าใจคือสาเหตุที่ตัวแปรควบคุมยังคงอยู่ในขอบเขตหลังจากวนออก จากประสบการณ์ของฉันมันเพียงแค่ตัดเนมสเปซส่วนกลางและทำให้การติดตามข้อผิดพลาดที่ล่ามในภาษาอื่น ๆ ทำได้ยากขึ้น


6
หากคุณไม่ต้องการให้forลูปกระทบกับเนมสเปซส่วนกลางของคุณให้ห่อในฟังก์ชัน ปิดเยอะแยะ!
jathanism

24
ถ้าคุณกำลังทำงานวงใน namespace ทั่วโลก (ผิดปกติ) ให้มันเกะกะท้องถิ่น namespace
Glenn Maynard

3
หากสิ่งนี้ไม่มีอยู่คุณจะดำเนินการอย่างไรต่อในภายหลังในจุดที่คุณเหลือไว้ในลูป เพียงแค่กำหนดตัวแปรควบคุมก่อนลูป
endolith

9
@endolith ใช่ ... ทำไมไม่ต้องการมัน?
Steven Lu

3
ผู้คนก็จะชอบสิ่งที่พวกเขาเคยทำ ฉันว่าแบบนี้เจ็บ coder หลามที่คุ้นเคยกับสิ่งนี้และต้องผ่านกระบวนการที่เจ็บปวดเมื่อเปลี่ยนเป็นภาษาอื่น สำหรับพวกเราที่เหลือมันเป็นทางลัดที่เรียบร้อย
Steven Lu

คำตอบ:


107

คำตอบที่น่าชอบที่สุดก็คือมันช่วยให้ไวยากรณ์นั้นง่ายไม่เป็นอุปสรรคต่อการนำไปใช้และหลาย ๆ คนก็มีความสุขที่ไม่ต้องแยกแยะขอบเขตของชื่อที่เป็นของชื่อเมื่อมอบหมายให้มันในโครงสร้างของลูป ตัวแปรจะไม่ถูกประกาศภายในขอบเขตโดยนัยของที่ตั้งของคำสั่งที่ได้รับมอบหมาย globalคำหลักที่มีอยู่เพียงแค่เหตุผลนี้ (ที่มีความหมายที่ได้รับมอบหมายที่ทำในขอบเขตทั่วโลก)

ปรับปรุง

นี่คือการอภิปรายที่ดีในหัวข้อ: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

ข้อเสนอก่อนหน้านี้ในการสร้างตัวแปร for-loop ในลูปนั้นเกิดปัญหากับโค้ดที่มีอยู่ซึ่งอาศัยตัวแปรลูปที่รักษาค่าไว้หลังจากออกจากลูปและดูเหมือนว่านี่จะเป็นคุณสมบัติที่พึงประสงค์

ในระยะสั้นคุณอาจตำหนิได้ในชุมชน Python: P


2
ไวยากรณ์จะซับซ้อนอย่างไรถ้าขอบเขตของตัวแปรเหนี่ยวนำถูก จำกัด อยู่ที่เนื้อความของลูป การเปลี่ยนแปลงดังกล่าวจะถูก จำกัด อยู่ที่การวิเคราะห์เชิงความหมายใน Python ไม่ใช่กับไวยากรณ์
ชาร์ลส์

6
ลูปไม่ใช่บล็อกใน Python การเปลี่ยนแปลงพฤติกรรมแบบนี้จะเรียกร้องให้เปลี่ยนไวยากรณ์พื้นฐานหรือเป็นกรณีพิเศษ แนวคิดทั้งหมดของตัวแปรเหนี่ยวนำไม่ได้แสดงในไวยากรณ์ปัจจุบัน ไวยากรณ์ให้สัญญาว่าล่ามจะตีความอย่างไร ประเด็นของฉันคือฉันไม่สามารถล่วงรู้ได้ว่าการเปลี่ยนแปลงในพฤติกรรมนี้สามารถทำได้โดยไม่ต้องใช้ไวยากรณ์ซับซ้อนขึ้น มันเป็นสิ่งที่สงสัยทั้งหมดตั้งแต่ผลข้างเคียงของการตัดสินใจออกแบบกลายเป็นคุณสมบัติ
Jeremy Brown

1
โพสต์นี้ที่นี่mail.python.org/pipermail/python-dev/2005-September/056677.htmlให้รายละเอียดเพิ่มเติมเกี่ยวกับความเร็วและความซับซ้อนที่ Mr. Brown กล่าวถึง
Rajesh

62

Python ไม่มีบล็อกเช่นเดียวกับภาษาอื่น ๆ (เช่น C / C ++ หรือ Java) ดังนั้นหน่วยการกำหนดขอบเขตใน Python จึงเป็นฟังก์ชัน


3
ฉันสับสน - อะไรที่ทำให้ Python ไม่สามารถกำหนดขอบเขตสำหรับลูปในลักษณะเดียวกันกับที่ขอบเขตการทำงาน
chimeracoder

36
ไม่เป็นความจริงเลยมันเป็นเพียงแค่ว่าไวยากรณ์ไม่ได้ไปอย่างบ้าคลั่ง ( docs.python.org/reference/ ...... ) "บล็อกคือข้อความส่วนหนึ่งของโปรแกรม Python ที่ถูกเรียกใช้เป็นหน่วยต่อไปนี้คือบล็อก: โมดูลตัวเนื้อหาของฟังก์ชั่นและคำจำกัดความของคลาส ... "
Jeremy บราวน์

1
@ มือข้างหลังไม่มีอะไรเลย มันก็ถือว่าไม่จำเป็น
habnabit

@ Jeremy Brown - แน่นอน ทราบดี
atzz

6
@thebackhand - ในภาษาที่มีบล็อกforลูปการกำหนดขอบเขตเป็นส่วนขยายตามธรรมชาติของหลักการทั่วไป ในงูหลามมันจะต้องเป็นกรณีพิเศษและกรณีพิเศษจะต้องหลีกเลี่ยงถ้าพวกเขามีผลประโยชน์ที่น่าสนใจ
atzz

39

กรณีที่มีประโยชน์จริง ๆ สำหรับกรณีนี้คือเมื่อใช้งานenumerateและคุณต้องการจำนวนรวมทั้งหมดในที่สุด:

for count, x in enumerate(someiterator, start=1):
    dosomething(count, x)
print "I did something {0} times".format(count)

จำเป็นหรือไม่ ไม่ได้ แต่แน่นอนว่าสะดวก

อีกสิ่งที่ควรระวัง: ใน Python 2 ตัวแปรในรายการความเข้าใจจะรั่วไหลเช่นกัน:

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

แต่ไม่สามารถใช้กับ Python 3 ได้


4
คุณน่าจะทำอย่างนั้นได้ในelseประโยคเช่น else: print "I did something {0} times".format(count)- ก่อนขอบเขตท้องถิ่น (ที่ไม่มีอยู่ใน Python) จะหายไป
Nas Banov

3
ตัวอย่างที่สองเท่านั้นที่ใช้งานไม่ได้ใน Python 3 ใช่ไหม ครั้งแรกยังคงทำอย่างไร หมายเหตุว่าเพราะเหตุใดจึงถูกลบออกจาก Python 3
endolith

7
สำหรับการนับรายการที่อยู่ในการแจกแจง (a, start = 1): # ดัชนีเริ่มต้นมาจากศูนย์
Tao Zhang

3
ตัวอย่างแรกแทนที่จะเป็นกรณีใช้งานที่ดีนั้นดูเหมือนว่าเป็นหลักฐานว่ากฎการกำหนดขอบเขตนี้มีอันตรายและไม่ควรเชื่อถือ เกิดอะไรขึ้นถ้าsomeiteratorว่างเปล่า
สูงสุด

1
@ Nas ในขณะที่elseประโยคสามารถใช้ในกรณีนี้มันจะไม่ทำงานโดยทั่วไปเนื่องจากร่างกายห่วงสามารถbreakก่อนกำหนด
jamesdlin

2

หากคุณมีคำสั่ง break ในลูป (และต้องการใช้ค่าการวนซ้ำในภายหลังอาจจะเลือกทำดัชนีหรือให้สถานะ) มันจะช่วยคุณประหยัดหนึ่งบรรทัดของรหัสและการมอบหมายหนึ่งครั้งดังนั้นจึงมีความสะดวกสบาย


1

หนึ่งในอิทธิพลหลักสำหรับ Python คือABCซึ่งเป็นภาษาที่พัฒนาขึ้นในประเทศเนเธอร์แลนด์สำหรับการสอนแนวคิดการเขียนโปรแกรมสำหรับผู้เริ่มต้น ผู้สร้าง Python ของ Guido van Rossum ทำงานใน ABC มาหลายปีในช่วงปี 1980 ฉันแทบไม่รู้อะไรเลยเกี่ยวกับ ABC แต่มันมีไว้สำหรับผู้เริ่มต้นฉันคิดว่ามันต้องมีขอบเขตที่ จำกัด เหมือนในช่วงต้น BASIC


-1

สำหรับผู้เริ่มต้นหากตัวแปรอยู่ในท้องถิ่นเป็นลูปลูปเหล่านั้นจะไร้ประโยชน์สำหรับการเขียนโปรแกรมส่วนใหญ่ในโลกแห่งความเป็นจริง

ในสถานการณ์ปัจจุบัน:

# Sum the values 0..9
total = 0
for foo in xrange(10):
    total = total + foo
print total

45อัตราผลตอบแทน ตอนนี้ให้พิจารณาว่าการบ้านทำงานอย่างไรใน Python หากตัวแปรลูปเป็นแบบโลคัล:

# Sum the values 0..9?
total = 0
for foo in xrange(10):
    # Create a new integer object with value "total + foo" and bind it to a new
    # loop-local variable named "total".
    total = total + foo
print total

อัตราผลตอบแทน0เพราะtotalภายในวงหลังจากที่ได้รับมอบหมายไม่ได้เป็นตัวแปรเดียวกับtotalนอกวง สิ่งนี้จะไม่เป็นพฤติกรรมที่ดีที่สุดหรือคาดหวัง


5
ไม่ตอบคำถาม OP ได้ถามเกี่ยวกับ foo ไม่ใช่ทั้งหมด (หรือตัวอย่างในบาร์)
James Bradbury

6
@JamesBradbury totalและfooยังคงมีการเชื่อมโยงลูป - โลคัลในสถานการณ์ของ OP และตรรกะก็เหมือนกัน
Kirk Strauser

2
OP: "ฉันเข้าใจได้ว่าทำไมมันอาจจำเป็นสำหรับ 'บาร์' ที่จะสามารถเข้าถึงได้นอกวง (มิฉะนั้นสำหรับลูปจะมีฟังก์ชั่นที่ จำกัด มาก) สิ่งที่ฉันไม่เข้าใจคือสาเหตุที่ตัวแปรการควบคุมยังคงอยู่ ในขอบเขตหลังจากออกจากลูป " (เน้นที่เหมือง)
James Bradbury

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