Zen of Python ระบุว่าควรมีเพียงวิธีเดียวในการทำสิ่งต่างๆ แต่บ่อยครั้งที่ฉันประสบปัญหาในการตัดสินใจว่าจะใช้ฟังก์ชันเมื่อใดเทียบกับเมื่อใดควรใช้วิธีการ
ลองดูตัวอย่างเล็กน้อย - วัตถุ ChessBoard สมมติว่าเราต้องการวิธีการบางอย่างเพื่อให้ได้การเคลื่อนไหวของกษัตริย์ตามกฎหมายทั้งหมดที่มีอยู่บนกระดาน เราเขียน ChessBoard.get_king_moves () หรือ get_king_moves (chess_board)?
นี่คือคำถามที่เกี่ยวข้องบางส่วนที่ฉันดู:
คำตอบที่ฉันได้รับส่วนใหญ่สรุปไม่ได้:
เหตุใด Python จึงใช้เมธอดสำหรับฟังก์ชันบางอย่าง (เช่น list.index ()) แต่ฟังก์ชันอื่น ๆ (เช่น len (รายการ))
เหตุผลสำคัญคือประวัติศาสตร์ ฟังก์ชั่นถูกใช้สำหรับการดำเนินการที่เป็นแบบทั่วไปสำหรับกลุ่มของประเภทและมีจุดมุ่งหมายเพื่อใช้งานได้แม้กระทั่งกับอ็อบเจ็กต์ที่ไม่มีเมธอดเลย (เช่นทูเปิล) นอกจากนี้ยังสะดวกที่จะมีฟังก์ชันที่สามารถนำไปใช้กับคอลเลกชันอสัณฐานได้อย่างง่ายดายเมื่อคุณใช้คุณสมบัติการทำงานของ Python (map (), apply () et al)
ในความเป็นจริงการนำ len (), max (), min () มาใช้เป็นฟังก์ชันในตัวนั้นมีโค้ดน้อยกว่าการนำไปใช้เป็นวิธีการสำหรับแต่ละประเภท เราสามารถเล่นลิ้นเกี่ยวกับแต่ละกรณีได้ แต่เป็นส่วนหนึ่งของ Python และมันสายเกินไปที่จะทำการเปลี่ยนแปลงพื้นฐานดังกล่าวในตอนนี้ ฟังก์ชันจะต้องยังคงอยู่เพื่อหลีกเลี่ยงการแตกโค้ดจำนวนมาก
ในขณะที่น่าสนใจข้างต้นไม่ได้บอกมากนักว่าควรใช้กลยุทธ์ใด
นี่เป็นหนึ่งในเหตุผล - ด้วยวิธีการที่กำหนดเองนักพัฒนาจะมีอิสระที่จะเลือกชื่อเมธอดอื่นเช่น getLength (), length (), getlength () หรืออะไรก็ตาม Python บังคับใช้การตั้งชื่อที่เข้มงวดเพื่อให้สามารถใช้ฟังก์ชันทั่วไป len () ได้
น่าสนใจกว่าเล็กน้อย สิ่งที่ฉันใช้คือฟังก์ชั่นในแง่หนึ่งคืออินเทอร์เฟซเวอร์ชัน Pythonic
สุดท้ายจาก Guido เอง :
การพูดถึงความสามารถ / อินเทอร์เฟซทำให้ฉันนึกถึงชื่อเมธอดพิเศษที่ "โกง" ของเรา ในการอ้างอิงภาษากล่าวว่า "คลาสสามารถใช้การดำเนินการบางอย่างที่เรียกใช้โดยไวยากรณ์พิเศษ (เช่นการดำเนินการทางคณิตศาสตร์หรือการห้อยและการแบ่งส่วน) โดยกำหนดวิธีการที่มีชื่อพิเศษ" แต่มีวิธีการเหล่านี้ทั้งหมดที่มีชื่อพิเศษเช่น
__len__
หรือ__unicode__
ซึ่งดูเหมือนจะถูกจัดเตรียมไว้เพื่อประโยชน์ของฟังก์ชันในตัวแทนที่จะสนับสนุนไวยากรณ์ สันนิษฐานว่าใน Python ที่ใช้อินเทอร์เฟซวิธีการเหล่านี้จะกลายเป็นเมธอดที่มีชื่อประจำบน ABC ดังนั้นจึง__len__
กลายเป็นclass container: ... def len(self): raise NotImplemented
แม้ว่าจะคิดถึงมันมากกว่านี้ แต่ฉันไม่เห็นว่าเหตุใดการดำเนินการทางวากยสัมพันธ์
<
object.lessthan
comparable.lessthan
ทั้งหมดจึงไม่เพียงแค่เรียกใช้เมธอดที่ตั้งชื่อตามปกติที่เหมาะสมใน ABC ที่เฉพาะเจาะจง " " ตัวอย่างเช่นคงจะเรียก " " (หรืออาจจะ " ") ดังนั้นประโยชน์อื่นจะเป็นความสามารถในการหย่านมงูใหญ่ออกไปจากนี้ mangled ชื่อไม่ชอบมาพากลซึ่งดูเหมือนว่าฉันมีการปรับปรุงฮึ่ม ฉันไม่แน่ใจว่าฉันเห็นด้วย (คิดว่า :-)
มีสองบิตของ "Python rationale" ที่ฉันอยากจะอธิบายก่อน
ก่อนอื่นฉันเลือก len (x) มากกว่า x.len () ด้วยเหตุผล HCI (ตาม
def __len__()
มาทีหลัง) มีสองสาเหตุที่เกี่ยวพันกันจริงๆทั้ง HCI:(a) สำหรับการดำเนินการบางอย่างสัญกรณ์นำหน้าจะอ่านได้ดีกว่า postfix - การดำเนินการคำนำหน้า (และ infix!) มีประเพณีอันยาวนานในคณิตศาสตร์ซึ่งชอบสัญกรณ์ที่ภาพช่วยให้นักคณิตศาสตร์คิดเกี่ยวกับปัญหาได้ เปรียบเทียบง่ายที่เราเขียนสูตรเหมือน
x*(a+b)
เข้าไปx*a + x*b
เพื่อความซุ่มซ่ามของการทำสิ่งเดียวกันโดยใช้สัญกรณ์ OO ดิบ(b) เมื่อฉันอ่านรหัสที่ระบุว่า
len(x)
ฉันรู้ว่ากำลังขอความยาวของบางสิ่ง สิ่งนี้บอกฉันสองสิ่ง: ผลลัพธ์คือจำนวนเต็มและอาร์กิวเมนต์คือคอนเทนเนอร์บางประเภท ไปในทางตรงกันข้ามเมื่อฉันอ่านx.len()
ฉันต้องรู้อยู่แล้วว่าเป็นชนิดของภาชนะที่ใช้อินเตอร์เฟซหรือการสืบทอดจากคลาสที่มีมาตรฐานบางอย่างx
len()
เป็นสักขีพยานในความสับสนที่เราพบในบางครั้งเมื่อชั้นเรียนที่ไม่ได้ใช้การทำแผนที่มี aget()
หรือkeys()
method หรือสิ่งที่ไม่ใช่ไฟล์มีwrite()
วิธีการพูดในทำนองเดียวกันว่าฉันเห็นว่า 'len' เป็นการทำงานใน ตัว ฉันเกลียดที่จะสูญเสียสิ่งนั้นไป ฉันไม่สามารถพูดได้อย่างแน่นอนว่าคุณหมายถึงอย่างนั้นหรือไม่ แต่ 'def len (self): ... ' ดูเหมือนว่าคุณต้องการลดระดับเป็นวิธีการธรรมดา ฉันเป็นอย่างยิ่ง -1 สำหรับสิ่งนั้น
บิตที่สองของงูหลามเหตุผลฉันสัญญาว่าจะอธิบายคือเหตุผลว่าทำไมผมเลือกวิธีการพิเศษที่จะมองและไม่เพียง
__special__
special
ฉันคาดว่าจะมีการดำเนินการจำนวนมากที่คลาสอาจต้องการแทนที่มาตรฐานบางอย่าง (เช่น__add__
หรือ__getitem__
) บางอย่างไม่เป็นมาตรฐาน (เช่นของดอง__reduce__
เป็นเวลานานไม่มีการรองรับรหัส C เลย) ฉันไม่ต้องการให้หน่วยปฏิบัติการพิเศษเหล่านี้ใช้ชื่อเมธอดธรรมดาเพราะจากนั้นคลาสที่มีอยู่แล้วหรือคลาสที่เขียนโดยผู้ใช้โดยไม่มีหน่วยความจำสารานุกรมสำหรับวิธีการพิเศษทั้งหมดจะต้องรับผิดชอบต่อการกำหนดการดำเนินการโดยไม่ได้ตั้งใจซึ่งไม่ได้ตั้งใจจะใช้ ซึ่งอาจส่งผลร้ายตามมา Ivan Krstićอธิบายสิ่งนี้อย่างกระชับมากขึ้นในข้อความของเขาซึ่งมาถึงหลังจากที่ฉันเขียนทั้งหมดนี้- - Guido van Rossum (โฮมเพจ: http://www.python.org/~guido/ )
ความเข้าใจของฉันเกี่ยวกับเรื่องนี้คือในบางกรณีสัญกรณ์นำหน้าจะมีความหมายมากกว่า (กล่าวคือ Duck.quack มีความหมายมากกว่าการต้มตุ๋น (Duck) จากมุมมองทางภาษา) และอีกครั้งฟังก์ชั่นอนุญาตสำหรับ "อินเทอร์เฟซ"
ในกรณีเช่นนี้ฉันเดาว่าจะใช้ get_king_moves ตามจุดแรกของ Guido เท่านั้น แต่นั่นยังทิ้งคำถามที่เปิดอยู่มากมายเกี่ยวกับการพูดการใช้สแต็กและคลาสคิวด้วยวิธีการพุชและป๊อปที่คล้ายกัน - ควรเป็นฟังก์ชันหรือวิธีการหรือไม่? (ที่นี่ฉันจะเดาฟังก์ชั่นเพราะฉันต้องการส่งสัญญาณอินเทอร์เฟซแบบพุชป๊อป)
TLDR: ใครสามารถอธิบายได้ว่ากลยุทธ์ในการตัดสินใจว่าจะใช้ฟังก์ชันกับวิธีการควรเป็นอย่างไร
X.frob
หรือX.__frob__
และยืนfrob
อิสระ