มีประโยชน์อะไรบ้างสำหรับ“ คำอธิบายประกอบฟังก์ชั่น” ของ Python3


159

คำอธิบายประกอบฟังก์ชั่น: PEP-3107

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

มันทำงานอย่างไร:

def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
    ... function body ...

ทุกอย่างที่ติดตามโคลอนหลังจากอาร์กิวเมนต์คือ 'คำอธิบายประกอบ' และข้อมูลต่อไปนี้->จะเป็นคำอธิบายประกอบสำหรับค่าส่งคืนของฟังก์ชัน

foo.func_annotations จะส่งคืนพจนานุกรม:

{'a': 'x',
 'b': 11,
 'c': list,
 'return': 9}

การมีสิ่งนี้มีความสำคัญอะไร?



6
@SilentGhost: น่าเสียดายที่ลิงก์จำนวนมากที่มีกรณีการใช้งานจริงเสียหาย มีสถานที่ที่เนื้อหาอาจถูกจัดเก็บหรือมันหายไปตลอดกาล?
สูงสุด

16
ไม่ควรfoo.func_annotations อยู่foo.__annotations__ใน python3 หรือ
zhangxaochen

2
คำอธิบายประกอบไม่มีความหมายพิเศษ สิ่งเดียวที่ Python ทำก็คือใส่ไว้ในพจนานุกรมคำอธิบายประกอบ การกระทำอื่น ๆ ขึ้นอยู่กับคุณ
N Randhawa

สิ่งที่ไม่def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):หมายถึง?
อาลี SH

คำตอบ:


90

ฉันคิดว่านี่ยอดเยี่ยมจริงๆ

มาจากพื้นฐานด้านวิชาการฉันสามารถบอกคุณได้ว่าคำอธิบายประกอบได้พิสูจน์แล้วว่ามีคุณค่าสำหรับการเปิดใช้งานเครื่องมือวิเคราะห์แบบคงที่อัจฉริยะสำหรับภาษาเช่น Java ตัวอย่างเช่นคุณสามารถกำหนดซีแมนทิกส์เช่นข้อ จำกัด ของรัฐ, เธรดที่ได้รับอนุญาตให้เข้าถึง, ข้อ จำกัด ด้านสถาปัตยกรรม, และมีเครื่องมือบางอย่างที่สามารถอ่านสิ่งเหล่านี้และประมวลผลพวกเขาเพื่อให้การรับประกันมากกว่าสิ่งที่คุณได้รับจากคอมไพเลอร์ คุณสามารถเขียนสิ่งต่าง ๆ ที่ตรวจสอบเงื่อนไข / postconditions

ฉันรู้สึกว่านี่เป็นสิ่งจำเป็นอย่างยิ่งใน Python เนื่องจากการพิมพ์ที่อ่อนกว่าของมัน แต่จริงๆแล้วมันไม่มีโครงสร้างที่ทำให้ตรงไปตรงมานี้และเป็นส่วนหนึ่งของไวยากรณ์อย่างเป็นทางการ

มีการใช้งานอื่น ๆ สำหรับการเพิ่มความคิดเห็นนอกเหนือจากการประกัน ฉันเห็นว่าฉันสามารถใช้เครื่องมือที่ใช้ Java กับ Python ได้อย่างไร ตัวอย่างเช่นฉันมีเครื่องมือที่ช่วยให้คุณกำหนดคำเตือนพิเศษให้กับวิธีการและให้ข้อบ่งชี้เมื่อคุณเรียกพวกเขาว่าคุณควรอ่านเอกสารของพวกเขา (เช่นจินตนาการว่าคุณมีวิธีการที่ต้องไม่เรียกใช้ด้วยค่าลบ แต่มันเป็น ไม่ง่ายจากชื่อ) ด้วยคำอธิบายประกอบฉันสามารถ technicall เขียนสิ่งนี้สำหรับ Python ในทำนองเดียวกันเครื่องมือที่จัดระเบียบวิธีการในชั้นเรียนขนาดใหญ่ตามแท็กสามารถเขียนถ้ามีไวยากรณ์อย่างเป็นทางการ


34
ISTM เหล่านี้เป็นประโยชน์ทางทฤษฎีที่สามารถรับรู้ได้ก็ต่อเมื่อไลบรารีมาตรฐานและโมดูลของบุคคลที่สามทั้งหมดใช้คำอธิบายประกอบฟังก์ชั่นและใช้พวกเขาด้วยความหมายที่สอดคล้องกันและใช้ระบบคำอธิบายประกอบที่ดี จนกว่าจะถึงวันนั้น (ซึ่งจะไม่มีวันมาถึง) การใช้งานหลักของคำอธิบายประกอบฟังก์ชั่นของไพ ธ อนจะเป็นการใช้ครั้งเดียวที่อธิบายไว้ในคำตอบอื่น ๆ ในขณะนี้คุณสามารถลืมเกี่ยวกับเครื่องมือวิเคราะห์สมาร์ทคงที่คอมไพเลอร์มั่นใจโซ่เครื่องมือที่ใช้ Java และอื่น ๆ
Raymond Hettinger

4
แม้จะไม่มีทุกสิ่งที่ใช้คำอธิบายประกอบฟังก์ชั่นคุณยังสามารถใช้พวกเขาสำหรับการวิเคราะห์แบบคงที่ภายในรหัสที่มีพวกเขาในอินพุตและกำลังเรียกรหัสอื่น ๆ ที่มีคำอธิบายประกอบในทำนองเดียวกัน ภายในโครงการขนาดใหญ่หรือ codebase นี่อาจเป็นเนื้อหาที่มีประโยชน์อย่างมากสำหรับการวิเคราะห์แบบคงที่ที่มีคำอธิบายประกอบ
gps

1
AFAICT คุณสามารถทำทั้งหมดนี้ได้ด้วยเครื่องมือตกแต่งที่ทำเครื่องหมายกำกับไว้ล่วงหน้า ดังนั้นฉันยังไม่เห็นประโยชน์ ฉันมีคำถามที่แตกต่างออกไปเล็กน้อย: stackoverflow.com/questions/13784713/…
allyourcode

9
กรอไปข้างหน้าสู่ปี 2015 python.org/dev/peps/pep-0484และ mypy-lang.orgกำลังเริ่มพิสูจน์ให้เห็นว่ามีความผิดทั้งหมด
Mauricio Scheffer

1
นอกจากนี้ยังเผยให้เห็นถึงอิทธิพลของ Python ที่มีต่อ Swift มากยิ่งขึ้น
uchuugaka

92

คำอธิบายประกอบฟังก์ชั่นเป็นสิ่งที่คุณทำจากพวกเขา

สามารถใช้เป็นเอกสารประกอบ:

def kinetic_energy(mass: 'in kilograms', velocity: 'in meters per second'):
     ...

สามารถใช้สำหรับการตรวจสอบสภาพล่วงหน้า:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        msg = 'Var: {0}\tValue: {1}\tTest: {2.__name__}'.format(var, value, test)
        assert test(value), msg


def is_int(x):
    return isinstance(x, int)

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    return _between

def f(x: between(3, 10), y: is_int):
    validate(f, locals())
    print(x, y)


>>> f(0, 31.1)
Traceback (most recent call last):
   ... 
AssertionError: Var: y  Value: 31.1 Test: is_int

ดูที่http://www.python.org/dev/peps/pep-0362/เพื่อดูวิธีการตรวจสอบประเภท


18
มันจะดีกว่า docstring สำหรับเอกสารหรือการตรวจสอบประเภทอย่างชัดเจนในฟังก์ชั่น? ดูเหมือนว่าจะไม่มีความซับซ้อนของภาษาโดยไม่มีเหตุผล
endolith

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

4
แทนที่จะส่งผ่านตัวเลขคุณสามารถสร้างประเภทMassและVelocityแทน
rightfold

1
เพื่อแสดงให้เห็นอย่างเต็มที่ฉันจะต้องdef kinetic_energy(mass: 'in kilograms', velocity: 'in meters per second') -> float:แสดงประเภทการส่งคืนด้วย นี่คือคำตอบโปรดของฉันที่นี่
Tommy

ใช้รหัสของคุณมีวิธีการตรวจสอบreturnบันทึกย่อหรือไม่ ดูเหมือนว่าจะไม่ปรากฏในlocals
user189728

46

นี่เป็นวิธีตอบที่ล่าช้า แต่ AFAICT การใช้คำอธิบายประกอบฟังก์ชั่นที่ดีที่สุดในปัจจุบันคือ PEP-0484และMyPy

Mypy เป็นตัวตรวจสอบชนิดคงที่เป็นตัวเลือกสำหรับ Python คุณสามารถเพิ่มคำใบ้ประเภทให้กับโปรแกรม Python ของคุณโดยใช้มาตรฐานที่กำลังจะเกิดขึ้นสำหรับคำอธิบายประกอบประเภทที่แนะนำใน Python 3.5 เบต้า 1 (PEP 484) และใช้ mypy เพื่อพิมพ์ตรวจสอบพวกเขาแบบคงที่

ใช้อย่างนั้น:

from typing import Iterator

def fib(n: int) -> Iterator[int]:
    a, b = 0, 1
    while a < n:
        yield a
        a, b = b, a + b

2
ตัวอย่างเพิ่มเติมได้ที่นี่ตัวอย่าง Mypyและที่นี่คุณจะได้ประโยชน์อย่างไรจากคำแนะนำประเภท
El Ruso

โปรดดูpytype - ตัววิเคราะห์แบบคงที่ตัวอื่นที่ถูกสร้างด้วย PEP-0484 ในใจ
gps

น่าเสียดายที่ประเภทไม่ได้บังคับใช้ ถ้าฉันพิมพ์list(fib('a'))ด้วยฟังก์ชันตัวอย่างของคุณ Python 3.7 ยอมรับอาร์กิวเมนต์อย่างมีความสุขและบ่นว่าไม่มีทางที่จะเปรียบเทียบสตริงและ int
เดนิสเดอ

@DenisdeBernardy ในฐานะ PEP-484 อธิบาย Python ให้คำอธิบายประกอบประเภทเท่านั้น ในการบังคับใช้ประเภทคุณต้องใช้ mypy
ดัสตินไวแอตต์

23

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

# This is in the 'mm' module

registry = {}
import inspect

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        function = self.typemap.get(types)
        if function is None:
            raise TypeError("no match")
        return function(*args)
    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        self.typemap[types] = function

def multimethod(function):
    name = function.__name__
    mm = registry.get(name)
    if mm is None:
        mm = registry[name] = MultiMethod(name)
    spec = inspect.getfullargspec(function)
    types = tuple(spec.annotations[x] for x in spec.args)
    mm.register(types, function)
    return mm

และตัวอย่างการใช้งาน:

from mm import multimethod

@multimethod
def foo(a: int):
    return "an int"

@multimethod
def foo(a: int, b: str):
    return "an int and a string"

if __name__ == '__main__':
    print("foo(1,'a') = {}".format(foo(1,'a')))
    print("foo(7) = {}".format(foo(7)))

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

หมายเหตุ : ใน Python คุณสามารถเข้าถึงคำอธิบายประกอบได้function.__annotations__มากกว่าfunction.func_annotationsที่func_*จะลบสไตล์ใน Python 3


2
แอปพลิเคชั่นที่น่าสนใจแม้ว่าฉันกลัวว่าfunction = self.typemap.get(types)จะไม่ทำงานเมื่อมีคลาสย่อยเข้ามาเกี่ยวข้อง ในกรณีที่คุณอาจจะต้องห่วงผ่านการใช้typemap isinnstanceฉันสงสัยว่า@overloadจะจัดการกับสิ่งนี้ได้อย่างถูกต้องหรือไม่
Tobias Kienzler

ฉันคิดว่านี่จะใช้งานไม่ได้หากฟังก์ชันมีประเภทส่งคืน
zenna

1
คำสั่ง__annotations__ a คือdictไม่รับประกันการเรียงลำดับของข้อโต้แย้งดังนั้นบางครั้งข้อมูลโค้ดนี้จึงล้มเหลว ฉันจะแนะนำเปลี่ยนtypes = tuple(...)ไปแล้วspec = inspect.getfullargspec(function) types = tuple([spec.annotations[x] for x in spec.args])
xoolive

คุณค่อนข้างถูกต้อง @xoolive ทำไมคุณไม่แก้ไขคำตอบเพื่อเพิ่มการแก้ไขของคุณ?
มูฮัมหมัด Alkarouri

@ xoolive: ฉันสังเกตเห็น บางครั้งผู้แก้ไขใช้มือหนักในการจัดการการแก้ไข ฉันได้แก้ไขคำถามเพื่อรวมการแก้ไขของคุณ ที่จริงฉันมีการสนทนาเกี่ยวกับเรื่องนี้ แต่ไม่มีวิธีที่จะยกเลิกการแก้ไข ขอบคุณสำหรับความช่วยเหลือ
Muhammad Alkarouri

22

Uri ได้รับคำตอบที่ถูกต้องแล้วดังนั้นนี่เป็นคำตอบที่ไม่ร้ายแรง: ดังนั้นคุณสามารถทำให้เอกสารของคุณสั้นลงได้


2
รักมัน +1 อย่างไรก็ตามในท้ายที่สุดการเขียนเอกสารยังคงเป็นหมายเลขหนึ่งที่ฉันทำให้โค้ดของฉันสามารถอ่านได้อย่างไรก็ตามถ้าคุณต้องใช้การตรวจสอบแบบคงที่หรือแบบไดนามิกใด ๆ มันก็ดีที่มีสิ่งนี้ บางทีฉันอาจจะใช้มัน
Warren P

8
ฉันไม่แนะนำให้ใช้คำอธิบายประกอบเพื่อแทนที่ส่วน Args: หรือ @param หรือคล้ายกันในเอกสารของคุณ (ไม่ว่าคุณจะเลือกใช้รูปแบบใด) ในขณะที่คำอธิบายประกอบเอกสารสร้างขึ้นเพื่อเป็นตัวอย่างที่ดี แต่ก็ทำให้พลังของคำอธิบายประกอบลดลงเนื่องจากอาจทำให้การใช้งานอื่น ๆ มีประสิทธิภาพยิ่งขึ้น นอกจากนี้คุณไม่สามารถละเว้นคำอธิบายประกอบที่รันไทม์เพื่อลดปริมาณการใช้หน่วยความจำ (python -OO) อย่างที่คุณสามารถทำได้ด้วยคำสั่ง docstrings และ assert
gps

2
@gps: เหมือนที่ฉันพูดมันเป็นคำตอบที่จริงจังน้อยกว่า
JAB

2
ในทุกเรื่องที่ร้ายแรงมันเป็นวิธีที่ดีกว่ามากในการจัดทำเอกสารประเภทที่คุณคาดหวังในขณะที่ยังคงยึดมั่นกับ DuckTyping
Marc

1
@gps ฉันไม่แน่ใจว่าการใช้หน่วยความจำของ docstrings เป็นสิ่งที่ต้องกังวลในกรณี 99.999%
Tommy

13

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

ดังนั้นฉันจึงตัดสินใจเขียนมัณฑนากรฟังก์ชั่นง่ายๆเพื่อบังคับใช้พวกเขา :

def ensure_annotations(f):
    from functools import wraps
    from inspect import getcallargs
    @wraps(f)
    def wrapper(*args, **kwargs):
        for arg, val in getcallargs(f, *args, **kwargs).items():
            if arg in f.__annotations__:
                templ = f.__annotations__[arg]
                msg = "Argument {arg} to {f} does not match annotation type {t}"
                Check(val).is_a(templ).or_raise(EnsureError, msg.format(arg=arg, f=f, t=templ))
        return_val = f(*args, **kwargs)
        if 'return' in f.__annotations__:
            templ = f.__annotations__['return']
            msg = "Return value of {f} does not match annotation type {t}"
            Check(return_val).is_a(templ).or_raise(EnsureError, msg.format(f=f, t=templ))
        return return_val
    return wrapper

@ensure_annotations
def f(x: int, y: float) -> float:
    return x+y

print(f(1, y=2.2))

>>> 3.2

print(f(1, y=2))

>>> ensure.EnsureError: Argument y to <function f at 0x109b7c710> does not match annotation type <class 'float'>

ฉันเพิ่มลงในไลบรารีตรวจสอบ


ฉันมีความผิดหวังเหมือนกันหลังจากฉันออกจากการเชื่อว่า Python ในที่สุดก็มีการตรวจสอบประเภท ในที่สุดจะต้องดำเนินการตรวจสอบประเภทบ้าน
Hibou57

3

เป็นเวลานานตั้งแต่ถูกถาม แต่ตัวอย่างข้อมูลที่ให้ไว้ในคำถามคือ (ตามที่ระบุไว้เช่นกัน) จาก PEP 3107 และในตอนท้ายของตัวอย่าง PEP thas ตัวอย่างการใช้งานจะได้รับซึ่งอาจตอบคำถามจากจุด PEPs ของ ดู;)

ข้อมูลต่อไปนี้อ้างอิงจาก PEP3107

ใช้เคส

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

  • ให้ข้อมูลการพิมพ์
    • การตรวจสอบประเภท ([3], [4])
    • ให้ IDEs แสดงประเภทของฟังก์ชันที่คาดหวังและส่งคืน ([17])
    • ฟังก์ชันโอเวอร์โหลด / ฟังก์ชันทั่วไป ([22])
    • สะพานภาษาต่างประเทศ ([18], [19])
    • การปรับตัว ([21], [20])
    • ฟังก์ชันลอจิกเชิงกริยา
    • การแมปแบบสอบถามฐานข้อมูล
    • การจัดการพารามิเตอร์ RPC ([23])
  • ข้อมูลอื่น ๆ
    • เอกสารประกอบสำหรับพารามิเตอร์และค่าส่งคืน ([24])

ดูPEPสำหรับข้อมูลเพิ่มเติมเกี่ยวกับคะแนนเฉพาะ (รวมถึงการอ้างอิงของพวกเขา)


ฉันอยากจะชื่นชมถ้าผู้ลงคะแนนอย่างน้อยแสดงความคิดเห็นสั้น ๆ ว่าอะไรคือสาเหตุของการลงคะแนน สิ่งนี้จะช่วยได้มาก (อย่างน้อยฉัน) ในการปรับปรุง
klaas

2

งูหลาม 3.X (เท่านั้น) นอกจากนี้ยัง generalizes นิยามฟังก์ชันที่จะช่วยให้การขัดแย้งและกลับค่าที่จะมีคำอธิบายประกอบกับค่านิยมวัตถุ สำหรับการใช้งานในส่วนขยาย

มันเป็นข้อมูล META ที่จะอธิบายให้ชัดเจนมากขึ้นเกี่ยวกับค่าฟังก์ชั่น

คำอธิบายประกอบจะได้รับการกำหนดรหัสตาม:valueหลังชื่ออาร์กิวเมนต์และหน้าค่าเริ่มต้นและ->valueหลังรายการอาร์กิวเมนต์

พวกมันถูกรวบรวมไว้ใน__annotations__คุณสมบัติของฟังก์ชั่น แต่ไม่ได้รับการปฏิบัติเป็นอย่างอื่นโดยไพ ธ อนเอง:

>>> def f(a:99, b:'spam'=None) -> float:
... print(a, b)
...
>>> f(88)
88 None
>>> f.__annotations__
{'a': 99, 'b': 'spam', 'return': <class 'float'>}

ที่มา: Python Pocket Reference, Fifth Edition

ตัวอย่าง:

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

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

https://github.com/ceronman/typeannotations

วิธีการพิมพ์ช่วยในการเขียนรหัสที่ดีขึ้น

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

ทำความสะอาดหลาม: การเข้ารหัสที่หรูหราใน Python ISBN: ISBN-13 (pbk): 978-1-4842-4877-5

PEP 526 - ไวยากรณ์ของคำอธิบายประกอบแบบตัวแปร

https://www.python.org/dev/peps/pep-0526/

https://www.attrs.org/en/stable/types.html


@BackackJack "สำหรับใช้ในส่วนขยาย" ไม่ชัดเจนใช่ไหม
Demz

เป็นที่ชัดเจน แต่ไม่ตอบคำถาม IMHO มันเหมือนกับการตอบคำถาม„ การใช้ชั้นเรียนที่ดีมีอะไรบ้าง?“ กับ„ สำหรับใช้ในโปรแกรม“ ชัดเจนถูกต้อง แต่ผู้ถามไม่ได้ฉลาดเท่าการใช้งานที่เป็นรูปธรรม ของคุณคือคำตอบที่ไม่สามารถทั่วไปมากขึ้นโดยมีตัวอย่างที่หลักเช่นเดียวกับคนที่อยู่ในที่คำถาม
BlackJack

1

แม้จะมีการใช้งานทั้งหมดที่อธิบายไว้ที่นี่หนึ่งที่บังคับใช้และส่วนใหญ่มีแนวโน้มการบังคับใช้คำอธิบายประกอบจะให้คำแนะนำที่เป็นประเภทคำแนะนำที่เป็นประเภท

ขณะนี้ยังไม่มีการบังคับใช้ แต่อย่างใดหากพิจารณาจาก PEP 484 เวอร์ชันในอนาคตของ Python จะอนุญาตเฉพาะชนิดเป็นค่าสำหรับการเพิ่มความคิดเห็น

การพูดสิ่งที่เกี่ยวกับการใช้คำอธิบายประกอบที่มีอยู่แล้ว :

เราหวังว่าในที่สุดคำใบ้ประเภทนี้จะใช้เป็นคำอธิบายประกอบเพียงอย่างเดียว แต่จะต้องมีการสนทนาเพิ่มเติมและระยะเวลาคัดค้านหลังจากการเริ่มต้นโมดูลการพิมพ์ด้วย Python 3.5 PEP ปัจจุบันจะมีสถานะชั่วคราว (ดู PEP 411) จนกว่า Python 3.6 จะเปิดตัว รูปแบบที่เป็นไปได้ที่เร็วที่สุดจะแนะนำการลดทอนอย่างเงียบ ๆ ของคำอธิบายประกอบแบบไม่มีคำใบ้ใน 3.6 การคัดค้านแบบเต็มใน 3.7 และประกาศคำใบ้ประเภทเป็นการอนุญาตให้ใช้คำอธิบายประกอบใน Python 3.8 เท่านั้น

แม้ว่าฉันจะไม่ได้เห็นการลดลงของความเงียบใน 3.6 แต่มันสามารถชนกับ 3.7 ได้ดี

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


1

เป็นคำตอบที่ล่าช้าเล็กน้อยแพคเกจของฉัน (marrow.script, WebCore ฯลฯ ) ใช้คำอธิบายประกอบที่มีให้ประกาศ typecasting (เช่นการเปลี่ยนค่าที่เข้ามาจากเว็บ เพื่อดำเนินการมาร์กอัพเพิ่มเติมของอาร์กิวเมนต์

Marrow Script สร้างอินเทอร์เฟซบรรทัดคำสั่งที่สมบูรณ์เพื่อฟังก์ชั่นและคลาสโดยพลการ ไลบรารีทั้งหมดของฉันที่ใช้คำอธิบายประกอบสนับสนุนรูปแบบ:

any_string  # documentation
any_callable  # typecast / callback, not called if defaulting
(any_callable, any_string)  # combination
AnnotationClass()  # package-specific rich annotation object
[AnnotationClass(), AnnotationClass(), …]  # cooperative annotation

การสนับสนุน "Bare" สำหรับ docstrings หรือฟังก์ชั่น typecasting ช่วยให้ผสมกับไลบรารีอื่น ๆ ที่ทราบคำอธิบายประกอบได้ง่ายขึ้น (เช่นมีตัวควบคุมเว็บโดยใช้ typecasting ซึ่งจะปรากฏเป็นสคริปต์บรรทัดคำสั่งด้วย)

แก้ไขเพื่อเพิ่ม:ฉันเริ่มใช้แพ็คเกจTypeGuardโดยใช้การยืนยันเวลาพัฒนาเพื่อตรวจสอบความถูกต้อง ประโยชน์: เมื่อเปิดใช้งานด้วย "การเพิ่มประสิทธิภาพ" เปิดใช้งาน ( -O/ PYTHONOPTIMIZEenv var) การตรวจสอบซึ่งอาจมีราคาแพง (เช่นเรียกซ้ำ) จะถูกละเว้นด้วยความคิดที่ว่าคุณทดสอบแอปของคุณอย่างถูกต้องในการพัฒนาดังนั้นการตรวจสอบ


-2

คำอธิบายประกอบสามารถใช้สำหรับการทำให้เป็นโมดูลรหัส เช่นโมดูลสำหรับโปรแกรมที่ฉันดูแลอยู่สามารถกำหนดวิธีการเช่น:

def run(param1: int):
    """
    Does things.

    :param param1: Needed for counting.
    """
    pass

และเราสามารถถามผู้ใช้สำหรับสิ่งที่ชื่อว่า "param1" ซึ่งเป็น "Needed for Count" และควรเป็น "int" ในที่สุดเราสามารถแปลงสตริงที่ผู้ใช้กำหนดให้เป็นประเภทที่ต้องการเพื่อรับประสบการณ์ที่ไม่ยุ่งยากที่สุด

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


-2

ถ้าคุณดูที่รายการผลประโยชน์ของ Cython สิ่งสำคัญคือความสามารถในการบอกคอมไพเลอร์ที่พิมพ์วัตถุ Python

ฉันสามารถจินตนาการถึงอนาคตที่ Cython (หรือเครื่องมือที่คล้ายกันที่รวบรวมรหัส Python ของคุณ) จะใช้ไวยากรณ์คำอธิบายประกอบเพื่อทำเวทย์มนตร์ของพวกเขา


The RPython Annotatorเป็นตัวอย่างของวิธีการที่ให้ความรู้สึก Pythonic อย่างเหมาะสม; หลังจากสร้างกราฟของแอปพลิเคชันของคุณแล้วมันสามารถทำงานกับประเภทของตัวแปรทุกตัวและ (สำหรับ RPython) บังคับใช้ความปลอดภัยประเภทเดียว OTOH ต้องการ "Boxing" หรือโซลูชัน / การแก้ไขอื่น ๆ เพื่อให้สามารถใช้งานได้กับค่าที่หลากหลาย ฉันต้องบังคับให้multiplyฟังก์ชันของฉันทำงานกับจำนวนเต็มเท่านั้นเมื่อใดที่'na' * 8 + ' batman!'จะใช้ได้อย่างสมบูรณ์ ;)
รวบรวม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.