การพิมพ์เป็ดการตรวจสอบข้อมูลและการเขียนโปรแกรมที่เหมาะสมใน Python


10

เกี่ยวกับการพิมพ์เป็ด :

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

เกี่ยวกับการตรวจสอบข้อโต้แย้ง (EAFP: ง่ายกว่าที่จะขอการอภัยมากกว่าการอนุญาต) ตัวอย่างที่ดัดแปลงจากที่นี่ :

... มันเป็นสิ่งที่ต้องทำยิ่งกว่า:

def my_method(self, key):
    try:
        value = self.a_dict[member]
    except TypeError:
        # do something else

ซึ่งหมายความว่าทุกคนที่ใช้รหัสของคุณไม่จำเป็นต้องใช้พจนานุกรมจริงหรือคลาสย่อย - พวกเขาสามารถใช้วัตถุใด ๆ ที่ใช้อินเทอร์เฟซการแมป

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

เกี่ยวกับการเขียนโปรแกรมที่แน่วแน่ :

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

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

  1. การตรวจสอบที่แข็งแกร่ง โดยการตรวจสอบที่แข็งแกร่งฉันหมายถึงการเพิ่มข้อยกเว้นที่กำหนดเอง ( ApiErrorตัวอย่าง) หากฟังก์ชัน / เมธอดของฉันเป็นส่วนหนึ่งของ API สาธารณะจะเป็นการดีกว่าถ้าตรวจสอบอาร์กิวเมนต์เพื่อแสดงข้อความแสดงข้อผิดพลาดที่ดีเกี่ยวกับประเภทที่ไม่คาดคิด โดยการตรวจสอบประเภทที่ฉันไม่ได้หมายถึงการใช้เพียงอย่างเดียวisinstanceแต่ยังถ้าวัตถุผ่านการสนับสนุนอินเทอร์เฟซที่จำเป็น (พิมพ์เป็ด) ในขณะที่ฉันทำเอกสาร API และระบุประเภทที่คาดหวังและผู้ใช้อาจต้องการใช้ฟังก์ชั่นของฉันในทางที่ไม่คาดคิดฉันรู้สึกปลอดภัยยิ่งขึ้นเมื่อฉันตรวจสอบสมมติฐาน ฉันมักจะใช้isinstanceและหากภายหลังฉันต้องการสนับสนุนเป็ดหรือเป็ดชนิดอื่นฉันจะเปลี่ยนตรรกะการตรวจสอบ

  2. การเขียนโปรแกรมที่แน่วแน่ ถ้ารหัสของฉันใหม่ฉันใช้ยืนยันมาก คุณมีคำแนะนำอะไรเกี่ยวกับเรื่องนี้? คุณลบข้อความยืนยันออกจากรหัสในภายหลังหรือไม่

  3. หากฟังก์ชัน / เมธอดของฉันไม่ได้เป็นส่วนหนึ่งของ API แต่ส่งผ่านข้อโต้แย้งบางอย่างไปยังโค้ดอื่นที่ไม่ได้เขียนศึกษาหรือทดสอบโดยฉันฉันจะทำการยืนยันจำนวนมากตามอินเตอร์เฟสที่เรียกใช้ ตรรกะของฉันที่อยู่เบื้องหลังสิ่งนี้ - ล้มเหลวในโค้ดของฉันได้ดีขึ้นจากนั้นอีก 10 ระดับที่ลึกลงไปในสแต็คเทรซที่มีข้อผิดพลาดที่เข้าใจยากซึ่งบังคับให้ดีบั๊กมากและต่อมา

ความคิดเห็นและคำแนะนำเกี่ยวกับเวลาที่จะใช้หรือไม่ใช้การตรวจสอบประเภท / ค่ายืนยันหรือไม่ ขออภัยที่ไม่ใช่คำถามที่ดีที่สุด

ตัวอย่างเช่นพิจารณาฟังก์ชันต่อไปนี้โดยที่Customerเป็นรูปแบบการประกาศ SQLAlchemy:

def add_customer(self, customer):
    """Save new customer into the database.
    @param customer: Customer instance, whose id is None
    @return: merged into global session customer
    """
    # no validation here at all
    # let's hope SQLAlchemy session will break if `customer` is not a model instance
    customer = self.session.add(customer)
    self.session.commit()
    return customer

ดังนั้นมีหลายวิธีในการจัดการการตรวจสอบ:

def add_customer(self, customer):
    # this is an API method, so let's validate the input
    if not isinstance(customer, Customer):
        raise ApiError('Invalid type')
    if customer.id is not None:
        raise ApiError('id should be None')

    customer = self.session.add(customer)
    self.session.commit()
    return customer

หรือ

def add_customer(self, customer):
    # this is an internal method, but i want to be sure
    # that it's a customer model instance
    assert isinstance(customer, Customer), 'Achtung!'
    assert customer.id is None

    customer = self.session.add(customer)
    self.session.commit()
    return customer

คุณจะใช้สิ่งเหล่านี้ในบริบทของการพิมพ์เป็ดเมื่อใดและเพราะเหตุใดการตรวจสอบประเภทการตรวจสอบความถูกต้องของข้อมูล


1
คุณไม่ควรลบการยืนยันเช่นเดียวกับการทดสอบหน่วยเว้นแต่เหตุผลด้านประสิทธิภาพ
ไบรอันเฉิน

คำตอบ:


4

ให้ฉันแนะนำหลักการบางอย่าง

หลักการ # 1 ตามที่อธิบายไว้ในhttp://docs.python.org/2/reference/simple_stmts.htmlโอเวอร์เฮดของประสิทธิภาพของ asserts สามารถลบออกได้ด้วยตัวเลือกบรรทัดคำสั่งในขณะที่ยังคงมีการดีบัก หากประสิทธิภาพเป็นปัญหาให้ทำเช่นนั้น ออกจากการยืนยัน (แต่อย่าทำอะไรสำคัญในการอ้าง!)

หลักการ # 2 หากคุณกำลังทำบางสิ่งบางอย่างและจะมีข้อผิดพลาดร้ายแรงให้ใช้การยืนยัน ไม่มีค่าในการทำอย่างอื่น หากใครบางคนต้องการที่จะเปลี่ยนแปลงในภายหลังพวกเขาสามารถเปลี่ยนรหัสของคุณหรือหลีกเลี่ยงการเรียกวิธีการที่

หลักการ # 3 อย่าห้ามบางสิ่งเพียงเพราะคุณคิดว่าเป็นเรื่องโง่ที่ต้องทำ แล้วถ้าวิธีการของคุณอนุญาตให้มีสายผ่าน? ถ้ามันใช้งานได้ผล

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

ตามหลักการ 2 ข้อแรกเวอร์ชันที่สองของคุณสามารถถูกโยนทิ้งไปได้ อีกสองสิ่งที่คุณชอบคือเรื่องของรสนิยม คุณคิดว่ามีแนวโน้มใดมากขึ้น ใครบางคนจะผ่านไม่ใช่ลูกค้าไปadd_customerและสิ่งที่จะทำลาย (ในกรณีที่รุ่นที่ 3 เป็นที่ต้องการ) หรือว่าบางคนจะต้องการแทนที่ลูกค้าของคุณด้วยวัตถุ proxy บางชนิดที่ตอบสนองต่อวิธีการที่เหมาะสมทั้งหมด (ในกรณีที่รุ่นที่ 1 เป็นที่ต้องการ)

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


ฉันชอบ v.3 โดยเฉพาะอย่างยิ่งเมื่อออกแบบอินเตอร์เฟส - การเขียนคลาสและวิธีการใหม่ นอกจากนี้ฉันพิจารณา v.3 มีประโยชน์สำหรับวิธีการ API - เพราะรหัสของฉันเป็นของใหม่สำหรับผู้อื่น ฉันคิดว่าแนวทางการแสดงออกที่เหมาะสมเป็นการประนีประนอมที่ดีเพราะมันจะถูกลบออกจากการผลิตเมื่อทำงานในโหมดที่ปรับให้เหมาะสม > การระเบิดสิ่งที่มีแนวโน้มจะจับตัวพิมพ์ผิดมากกว่าที่จะหยุดยั้งไม่ให้ใครบางคนทำอะไรที่สมเหตุสมผล <ดังนั้นคุณไม่คิดว่าจะมีการตรวจสอบดังกล่าวหรือไม่
warvariuc

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