วิธีจัดทำเอกสารแอตทริบิวต์คลาสใน Python [ปิด]


115

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

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
    """

    flight_speed = 691
    __doc__ += """
        flight_speed (691)
          The maximum speed that such a bird can attain.
    """

    nesting_grounds = "Raymond Luxury-Yacht"
    __doc__ += """
        nesting_grounds ("Raymond Luxury-Yacht")
          The locale where these birds congregate to reproduce.
    """

    def __init__(self, **keyargs):
        """Initialize the Albatross from the keyword arguments."""
        self.__dict__.update(keyargs)

ซึ่งจะส่งผลใน docstring ชั้นที่มีการเริ่มต้นส่วน docstring __doc__มาตรฐานเช่นเดียวกับเส้นเพิ่มสำหรับแต่ละแอตทริบิวต์ผ่านที่ได้รับมอบหมายในการเติม

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

นี่ถือเป็นการฝ่าฝืนอนุสัญญาชุมชนเฉพาะกิจอย่างชั่วร้ายหรือไม่ จะเป็นไรไหม? มีวิธีที่ดีกว่า? ตัวอย่างเช่นเป็นไปได้ที่จะสร้างพจนานุกรมที่มีค่าและ docstrings สำหรับแอตทริบิวต์จากนั้นเพิ่มเนื้อหาลงในคลาส__dict__และ docstring ในตอนท้ายของการประกาศคลาส สิ่งนี้จะช่วยบรรเทาความจำเป็นในการพิมพ์ชื่อและค่าแอตทริบิวต์สองครั้ง แก้ไข : ความคิดสุดท้ายนี้คือฉันคิดว่าเป็นไปไม่ได้จริงอย่างน้อยก็ไม่ได้หากไม่มีการสร้างคลาสทั้งหมดจากข้อมูลแบบไดนามิกซึ่งดูเหมือนจะเป็นความคิดที่ไม่ดีจริงๆเว้นแต่จะมีเหตุผลอื่นให้ทำเช่นนั้น

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


หากคุณกำลังมองหาวิธีจัดทำเอกสารแอตทริบิวต์โมเดล Django สิ่งนี้อาจเป็นประโยชน์: djangosnippets.org/snippets/2533
Michael Scheper

3
สำเนาของHow to document fields และ properties ใน Python? ซึ่งถือเป็นทางออกที่แตกต่างกัน
bufh

1
ฉันไม่เข้าใจว่าทำไมจึงเป็นไปตามความคิดเห็น Python โดยเฉพาะเอกสารเป็นอนุสัญญาที่ยอมรับได้ใน PEP มีเครื่องมือซอร์ส Python ที่แตกต่างกันที่ดึงเอกสารที่จัดรูปแบบอย่างถูกต้อง ในความเป็นจริง Python มีการattribute doc stringกล่าวถึงในPEP 257ซึ่งไม่เป็นที่รู้จักกันดีและดูเหมือนจะหายากซึ่งอาจตอบคำถาม OPs และได้รับการสนับสนุนโดยเครื่องมือต้นทางบางอย่าง นี่ไม่ใช่ความเห็น มันเป็นความจริงและเป็นส่วนหนึ่งของภาษาและค่อนข้างตรงกับสิ่งที่ OP ต้องการ
NeilG

คำตอบ:


83

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

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
        flight_speed     The maximum speed that such a bird can attain.
        nesting_grounds  The locale where these birds congregate to reproduce.
    """
    flight_speed = 691
    nesting_grounds = "Throatwarbler Man Grove"

ฉันคิดว่ามันง่ายกว่าวิธีการในตัวอย่างของคุณมาก ถ้าฉันต้องการให้สำเนาของค่าแอตทริบิวต์ปรากฏในสตริง doc จริงๆฉันจะวางไว้ข้างหรือด้านล่างคำอธิบายของแต่ละแอตทริบิวต์

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


ฉันเดาว่าในกรณีส่วนใหญ่นี่เป็นเรื่องปกติเนื่องจากแอตทริบิวต์ - ขอบคุณสำหรับการแก้ไขคำศัพท์ - มีการประกาศอย่างรวบรัดเพียงพอว่าสามารถจัดกลุ่มที่จุดเริ่มต้นของการประกาศชั้นเรียนได้โดยไม่ต้องพลิกกลับไปกลับมาเพื่อ {read both เอกสารประกอบและค่าเริ่มต้น} หรือ {อัปเดตทั้งสองอินสแตนซ์ของเอกสารประกอบและ / หรือค่าเริ่มต้น}
ปรีชา

1
โปรดทราบว่าตัวอย่างของฉันจะทำให้เอกสารสำหรับแอตทริบิวต์ปรากฏใน docstring ของคลาส จริงๆแล้วฉันต้องการใส่เอกสารใน docstrings ของแอตทริบิวต์ แต่มันใช้ไม่ได้กับประเภท builtin ส่วนใหญ่
สังหรณ์ใจ

flight_speed = 691; flight_speed.__doc__ = "blah blah"ใช่ความคิดแรกของฉันเป็นเพียงแค่การประกาศเช่น ผมคิดว่านี่คือสิ่งที่คุณกำลังกล่าวขวัญของคุณในการแก้ไข น่าเสียดายที่สิ่งนี้ใช้ไม่ได้กับการสร้างอินสแตนซ์ของประเภทบิวท์อิน (ส่วนใหญ่?) (เช่นintในตัวอย่างนั้น) มันใช้ได้กับการสร้างอินสแตนซ์ของประเภทที่ผู้ใช้กำหนดเอง =========== มี PEP (ขออภัยลืมหมายเลข) ซึ่งเสนอให้เพิ่ม docstrings สำหรับแอตทริบิวต์คลาส / โมดูล แต่ถูกปฏิเสธเนื่องจากไม่สามารถหาวิธีทำให้ชัดเจนได้ ไม่ว่า docstrings เป็นของแอตทริบิวต์ก่อนหน้าหรือต่อไปนี้
ปรีชา

2
แล้วถ้าเป็นแอตทริบิวต์อินสแตนซ์ล่ะ? ยังคงจัดทำเอกสารในคลาส docstring หรืออะไร
n611x007

1
@intuited มันเป็น PEP นี้หรือไม่? legacy.python.org/dev/peps/pep-0224
taz

30

คุณอ้างถึง PEP257: Docstring Conventions ในส่วนdocstringคืออะไรระบุไว้:

ตัวอักษรสตริงที่เกิดขึ้นที่อื่นในโค้ด Python อาจทำหน้าที่เป็นเอกสารประกอบ คอมไพเลอร์ Python bytecode ไม่รู้จักและไม่สามารถเข้าถึงได้ในฐานะแอ็ตทริบิวต์อ็อบเจ็กต์รันไทม์ (กล่าวคือไม่ได้กำหนดให้กับ __doc__) แต่เครื่องมือซอฟต์แวร์สองประเภทอาจแตกสตริง docstrings เพิ่มเติม:

ตัวอักษรสตริงที่เกิดขึ้นทันทีหลังจากการกำหนดอย่างง่ายที่ระดับบนสุดของโมดูลคลาสหรือเมธอด __init__ เรียกว่า "attribute docstrings"

และนี่คือรายละเอียดเพิ่มเติมใน PEP 258: Attribute docstrings ตามที่อธิบายไว้ข้างต้นʇsәɹoɈ แอตทริบิวต์ไม่ใช่วัตถุที่สามารถเป็นเจ้าของ __doc__ ได้ดังนั้นจึงไม่ปรากฏในhelp()หรือ pydoc docstrings เหล่านี้สามารถใช้สำหรับเอกสารที่สร้างขึ้นเท่านั้น

พวกเขาใช้ใน Sphinx กับ คำสั่ง autoattribute

สฟิงซ์สามารถใช้ความคิดเห็นในบรรทัดก่อนการมอบหมายงานหรือความคิดเห็นพิเศษหลังจากงานมอบหมายหรือ docstring หลังจากคำจำกัดความซึ่งจะถูกจัดทำเป็นเอกสารอัตโนมัติ


1
ปลั๊กอิน jedi-vim ยังจดจำแอตทริบิวต์ docstrings
Long Vu

1
ฉันไม่รู้ว่าสิ่งนี้ถูกนำมาใช้เมื่อใด แต่ Sphinx 1.2.2 ดูเหมือนจะรวม docstrings แอตทริบิวต์ไว้ในเอกสารที่สร้างขึ้น
jochen

1
ขอบคุณ @jochen ฉันอัปเดตคำตอบของฉัน
marcz

3
โปรดทราบว่า PEP 258 ถูกปฏิเสธ ข้อความแจ้งการปฏิเสธระบุว่า: "แม้ว่าสิ่งนี้อาจใช้เป็นเอกสารการออกแบบที่น่าสนใจสำหรับเอกสารที่เป็นอิสระในขณะนี้ แต่ก็ไม่มีกำหนดให้รวมไว้ในไลบรารีมาตรฐานอีกต่อไป"
MichałŁazowik

13

คุณสามารถละเมิดคุณสมบัติเพื่อเอฟเฟกต์นี้ คุณสมบัติมี getter เป็นหมา, Deleter ที่และ docstring อย่างไร้เดียงสาสิ่งนี้จะได้รับอย่างละเอียดมาก:

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """Docstring goes here."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

จากนั้นคุณจะมี docstring ของ Cx:

In [24]: print(C.x.__doc__)
Docstring goes here.

ในการทำเช่นนี้สำหรับคุณสมบัติหลายอย่างนั้นยุ่งยาก แต่คุณสามารถจินตนาการถึงฟังก์ชันตัวช่วย myprop:

def myprop(x, doc):
    def getx(self):
        return getattr(self, '_' + x)

    def setx(self, val):
        setattr(self, '_' + x, val)

    def delx(self):
        delattr(self, '_' + x)

    return property(getx, setx, delx, doc)

class C:
    a = myprop("a", "Hi, I'm A!")
    b = myprop("b", "Hi, I'm B!")

In [44]: c = C()

In [46]: c.b = 42

In [47]: c.b
Out[47]: 42

In [49]: print(C.b.__doc__)
Hi, I'm B!

จากนั้นการเรียก Pythons แบบโต้ตอบhelpจะให้:

Help on class C in module __main__:

class C
 |  Data descriptors defined here:
 |  
 |  a
 |      Hi, I'm A!
 |  
 |  b
 |      Hi, I'm B!

ซึ่งฉันคิดว่าน่าจะเป็นสิ่งที่คุณต้องการ

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

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