नामितों में डॉकस्ट्रिंग्स जोड़ना?


85

क्या एक आसान तरीके से किसी नेमटुपल में डॉक्यूमेंटेशन स्ट्रिंग जोड़ना संभव है?

मैंने कोशिश की

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
"""
A point in 2D space
"""

# Yet another test

"""
A(nother) point in 2D space
"""
Point2 = namedtuple("Point2", ["x", "y"])

print Point.__doc__ # -> "Point(x, y)"
print Point2.__doc__ # -> "Point2(x, y)"

लेकिन यह कटौती नहीं करता है। क्या किसी और तरीके से करना संभव है?

जवाबों:


53

आप लौटे हुए मूल्य के आसपास एक साधारण, खाली रैपर वर्ग बनाकर इसे प्राप्त कर सकते हैं namedtuple। मेरे द्वारा बनाई गई फ़ाइल की सामग्री ( nt.py):

from collections import namedtuple

Point_ = namedtuple("Point", ["x", "y"])

class Point(Point_):
    """ A point in 2d space """
    pass

फिर पायथन आरईपीएल में:

>>> print nt.Point.__doc__
 A point in 2d space 

या आप कर सकते हैं:

>>> help(nt.Point)  # which outputs...
मॉड्यूल एनटी में वर्ग बिंदु पर मदद:

कक्षा बिंदु (प्वाइंट)
 | 2 डी स्पेस में एक बिंदु
 |  
 | विधि संकल्प क्रम:
 | बिंदु
 | बिंदु
 | __builtin __। टपल
 | __अंतर्निहित वस्तु
 ...

अगर आपको हर बार ऐसा करना पसंद नहीं है, तो ऐसा करने के लिए एक प्रकार का कारखाना फ़ंक्शन लिखना तुच्छ है:

def NamedTupleWithDocstring(docstring, *ntargs):
    nt = namedtuple(*ntargs)
    class NT(nt):
        __doc__ = docstring
    return NT

Point3D = NamedTupleWithDocstring("A point in 3d space", "Point3d", ["x", "y", "z"])

p3 = Point3D(1,2,3)

print p3.__doc__

कौन से आउटपुट:

A point in 3d space

2
क्या उपवर्ग namedtupleएक पूर्ण "ऑब्जेक्ट" में परिवर्तित नहीं होगा ? जिससे नाम-टुपल्स से प्रदर्शन के कुछ लाभ खो रहे हैं?
पूर्वकाल

5
यदि आप __slots__ = ()व्युत्पन्न उपवर्ग में जोड़ते हैं, तो आप उपयोग करने की स्मृति और प्रदर्शन के लाभ को बनाए रख सकते हैंnamedtuple
एलियाम

यह अभी भी MRO में एक और स्तर जोड़ता है, जो कि डॉकस्ट्रिंग के लिए उचित नहीं है। हालाँकि, कोई भी __doc__मूल ऑब्जेक्ट में सहेजे गए कस्टमाइज़ किए गए डॉकस्ट्रिंग को केवल असाइन कर सकता है ।
बछसौ

70

पायथन 3 में, किसी भी आवरण की आवश्यकता नहीं है, क्योंकि __doc__प्रकारों की विशेषताएं लेखन योग्य हैं।

from collections import namedtuple

Point = namedtuple('Point', 'x y')
Point.__doc__ = '''\
A 2-dimensional coordinate

x - the abscissa
y - the ordinate'''

यह बारीकी से एक मानक वर्ग परिभाषा से मेल खाता है, जहां डॉकस्ट्रिंग हेडर का अनुसरण करता है।

class Point():
    '''A 2-dimensional coordinate

    x - the abscissa
    y - the ordinate'''
    <class code>

यह पायथन 2 में काम नहीं करता है।

AttributeError: attribute '__doc__' of 'type' objects is not writable


64

इसी बात पर आश्चर्य करते हुए Google के माध्यम से इस पुराने प्रश्न पर आया।

केवल यह बताना चाहते हैं कि आप वर्ग घोषणा से सही नामांकित () कॉल करके इसे और भी अधिक स्पष्ट कर सकते हैं:

from collections import namedtuple

class Point(namedtuple('Point', 'x y')):
    """Here is the docstring."""

8
महत्वपूर्ण है कि आप __slots__ = ()कक्षा में शामिल हैं । अन्यथा आप __dict__अपने अटार्स के लिए बनाते हैं , नेमटुपल के हल्के स्वभाव को खो देते हैं।
बोल्ट्जमैनब्रेन

34

क्या एक आसान तरीके से किसी नेमटुपल में डॉक्यूमेंटेशन स्ट्रिंग जोड़ना संभव है?

हाँ, कई मायनों में।

सबक्लास टाइपिंग ।NamedTuple - पायथन 3.6+

Python 3.6 के रूप में, हम एक classपरिभाषा का उपयोग typing.NamedTupleसीधे डॉकस्ट्रिंग (और एनोटेशन!) के साथ कर सकते हैं।

from typing import NamedTuple

class Card(NamedTuple):
    """This is a card type."""
    suit: str
    rank: str

अजगर 2 की तुलना में, खाली घोषित __slots__करना आवश्यक नहीं है। पायथन 3.8 में, उपवर्गों के लिए भी यह आवश्यक नहीं है।

ध्यान दें कि घोषित __slots__करना गैर-रिक्त नहीं हो सकता है!

पायथन 3 में, आप किसी नामांक पर आसानी से दस्तावेज़ को बदल सकते हैं:

NT = collections.namedtuple('NT', 'foo bar')

NT.__doc__ = """:param str foo: foo name
:param list bar: List of bars to bar"""

जब हम उन पर इरादे देखने की अनुमति देते हैं, जब हम उन पर सहायता कहते हैं:

Help on class NT in module __main__:

class NT(builtins.tuple)
 |  :param str foo: foo name
 |  :param list bar: List of bars to bar
...

यह उन कठिनाइयों की तुलना में वास्तव में सीधा है जहां हमने पायथन 2 में एक ही चीज को पूरा किया है।

अजगर २

पायथन 2 में, आपको इसकी आवश्यकता होगी

  • नेकटप्लस उपवर्ग, और
  • घोषित __slots__ == ()

घोषणा __slots__करना एक महत्वपूर्ण हिस्सा है कि अन्य उत्तर यहां याद आते हैं

यदि आप घोषित नहीं करते हैं __slots__- तो आप बगों को प्रस्तुत करते हुए, उदाहरणों के लिए परिवर्तनशील तदर्थ विशेषताओं को जोड़ सकते हैं।

class Foo(namedtuple('Foo', 'bar')):
    """no __slots__ = ()!!!"""

और अब:

>>> f = Foo('bar')
>>> f.bar
'bar'
>>> f.baz = 'what?'
>>> f.__dict__
{'baz': 'what?'}

एक्सेस किए जाने पर प्रत्येक उदाहरण अलग __dict__हो जाएगा __dict__(कमी __slots__अन्यथा कार्यक्षमता में बाधा नहीं लाएगी, लेकिन टपल की हल्कापन, अपरिवर्तनीयता, और घोषित विशेषताएँ नामांकित की सभी महत्वपूर्ण विशेषताएं हैं)।

आप भी एक चाहते हैं __repr__, यदि आप चाहते हैं कि कमांड लाइन पर आपको एक समान वस्तु देने के लिए क्या प्रतिध्वनित किया जाए:

NTBase = collections.namedtuple('NTBase', 'foo bar')

class NT(NTBase):
    """
    Individual foo bar, a namedtuple

    :param str foo: foo name
    :param list bar: List of bars to bar
    """
    __slots__ = ()

एक __repr__इस तरह की जरूरत है अगर आप एक अलग नाम के साथ आधार namedtuple बनाने (जैसे हम नाम स्ट्रिंग तर्क, साथ ऊपर किया 'NTBase'):

    def __repr__(self):
        return 'NT(foo={0}, bar={1})'.format(
                repr(self.foo), repr(self.bar))

रिप्र का परीक्षण करने के लिए, तुरंत, फिर पास होने की समानता के लिए परीक्षण करें eval(repr(instance))

nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt

प्रलेखन से उदाहरण

डॉक्स भी इस तरह के एक उदाहरण के बारे में देने के लिए, __slots__- मैं इसे करने के लिए अपने खुद के docstring जोड़ रहा:

class Point(namedtuple('Point', 'x y')):
    """Docstring added here, not in original"""
    __slots__ = ()
    @property
    def hypot(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5
    def __str__(self):
        return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

...

उपवर्ग __slots__को एक खाली टपल पर सेट दिखाया गया है । यह उदाहरण शब्दकोशों के निर्माण को रोककर स्मृति आवश्यकताओं को कम रखने में मदद करता है।

यह इन-प्लेस उपयोग को प्रदर्शित करता है (जैसा कि यहां एक अन्य उत्तर बताता है), लेकिन ध्यान दें कि जब आप डिबगिंग कर रहे हैं, तो इन-प्लेस का उपयोग भ्रमित हो सकता है, यदि आप विधि रिज़ॉल्यूशन ऑर्डर को देखते हैं, तो यही कारण है कि मैंने मूल Baseरूप से प्रत्यय के रूप में उपयोग करने का सुझाव दिया है आधार नामित के लिए:

>>> Point.mro()
[<class '__main__.Point'>, <class '__main__.Point'>, <type 'tuple'>, <type 'object'>]
                # ^^^^^---------------------^^^^^-- same names!        

इसका __dict__उपयोग करने वाले वर्ग से उप-क्लासिंग के निर्माण को रोकने के लिए , आपको इसे उप-वर्ग में भी घोषित करना होगा। उपयोग करने पर अधिक कैविट्स के लिए यह उत्तर__slots__ भी देखें ।


3
यद्यपि अन्य उत्तरों की तरह संक्षिप्त और स्पष्ट नहीं है, यह स्वीकृत उत्तर होना चाहिए क्योंकि यह इसके महत्व पर प्रकाश डालता है __slots__। इसके बिना, आप नामांकित के हल्के मूल्य को खो रहे हैं।
बोल्ट्जमैनब्रेन

7

पायथन 3.5 के बाद से, namedtupleवस्तुओं के लिए डॉकस्ट्रिंग को अद्यतन किया जा सकता है।

से whatsnew :

Point = namedtuple('Point', ['x', 'y'])
Point.__doc__ += ': Cartesian coodinate'
Point.x.__doc__ = 'abscissa'
Point.y.__doc__ = 'ordinate'


3

स्वीकार किए गए उत्तर द्वारा सुझाए गए आवरण वर्ग का उपयोग करने की आवश्यकता नहीं है। बस शाब्दिक रूप से एक डॉकस्ट्रिंग जोड़ें :

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
Point.__doc__="A point in 2D space"

इसमें यह परिणाम है: (उदाहरण का उपयोग करते हुए ipython3):

In [1]: Point?
Type:       type
String Form:<class '__main__.Point'>
Docstring:  A point in 2D space

In [2]: 

देखा!


1
नोट: यह केवल पायथन 3 के लिए मान्य है। पायथन 2 में AttributeError: attribute '__doc__' of 'type' objects is not writable:।
टेलर एड्मिस्टन

1

आप रेमंड हेटिंगर द्वारा अपने नामांकित कारखाने के कार्य के अपने संस्करण को व्यक्त कर सकते हैं और एक वैकल्पिक docstringतर्क जोड़ सकते हैं । हालांकि यह आसान होगा - और यकीनन बेहतर - नुस्खा में उसी मूल तकनीक का उपयोग करके अपने कारखाने के कार्य को परिभाषित करने के लिए। किसी भी तरह से, आप पुन: प्रयोज्य कुछ के साथ समाप्त होगा।

from collections import namedtuple

def my_namedtuple(typename, field_names, verbose=False,
                 rename=False, docstring=''):
    '''Returns a new subclass of namedtuple with the supplied
       docstring appended to the default one.

    >>> Point = my_namedtuple('Point', 'x, y', docstring='A point in 2D space')
    >>> print Point.__doc__
    Point(x, y):  A point in 2D space
    '''
    # create a base class and concatenate its docstring and the one passed
    _base = namedtuple(typename, field_names, verbose, rename)
    _docstring = ''.join([_base.__doc__, ':  ', docstring])

    # fill in template to create a no-op subclass with the combined docstring
    template = '''class subclass(_base):
        %(_docstring)r
        pass\n''' % locals()

    # execute code string in a temporary namespace
    namespace = dict(_base=_base, _docstring=_docstring)
    try:
        exec template in namespace
    except SyntaxError, e:
        raise SyntaxError(e.message + ':\n' + template)

    return namespace['subclass']  # subclass object created

0

मैंने इस फ़ंक्शन को एक नामित टपल बनाने के लिए बनाया और अपने प्रत्येक पैरामीटर के साथ टपल को दस्तावेज़ित किया:

from collections import namedtuple


def named_tuple(name, description='', **kwargs):
    """
    A named tuple with docstring documentation of each of its parameters
    :param str name: The named tuple's name
    :param str description: The named tuple's description
    :param kwargs: This named tuple's parameters' data with two different ways to describe said parameters. Format:
        <pre>{
            str: ( # The parameter's name
                str, # The parameter's type
                str # The parameter's description
            ),
            str: str, # The parameter's name: the parameter's description
            ... # Any other parameters
        }</pre>
    :return: collections.namedtuple
    """
    parameter_names = list(kwargs.keys())

    result = namedtuple(name, ' '.join(parameter_names))

    # If there are any parameters provided (such that this is not an empty named tuple)
    if len(parameter_names):
        # Add line spacing before describing this named tuple's parameters
        if description is not '':
            description += "\n"

        # Go through each parameter provided and add it to the named tuple's docstring description
        for parameter_name in parameter_names:
            parameter_data = kwargs[parameter_name]

            # Determine whether parameter type is included along with the description or
            # if only a description was provided
            parameter_type = ''
            if isinstance(parameter_data, str):
                parameter_description = parameter_data
            else:
                parameter_type, parameter_description = parameter_data

            description += "\n:param {type}{name}: {description}".format(
                type=parameter_type + ' ' if parameter_type else '',
                name=parameter_name,
                description=parameter_description
            )

            # Change the docstring specific to this parameter
            getattr(result, parameter_name).__doc__ = parameter_description

    # Set the docstring description for the resulting named tuple
    result.__doc__ = description

    return result

फिर आप एक नया नाम बना सकते हैं:

MyTuple = named_tuple(
    "MyTuple",
    "My named tuple for x,y coordinates",
    x="The x value",
    y="The y value"
)

फिर अपने खुद के डेटा, यानी के साथ वर्णित नाम tuple पल।

t = MyTuple(4, 8)
print(t) # prints: MyTuple(x=4, y=8)

जब help(MyTuple)python3 कमांड लाइन के माध्यम से निष्पादित किया जाता है, तो निम्न दिखाया जाता है:

Help on class MyTuple:

class MyTuple(builtins.tuple)
 |  MyTuple(x, y)
 |
 |  My named tuple for x,y coordinates
 |
 |  :param x: The x value
 |  :param y: The y value
 |
 |  Method resolution order:
 |      MyTuple
 |      builtins.tuple
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __getnewargs__(self)
 |      Return self as a plain tuple.  Used by copy and pickle.
 |
 |  __repr__(self)
 |      Return a nicely formatted representation string
 |
 |  _asdict(self)
 |      Return a new OrderedDict which maps field names to their values.
 |
 |  _replace(_self, **kwds)
 |      Return a new MyTuple object replacing specified fields with new values
 |
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |
 |  _make(iterable) from builtins.type
 |      Make a new MyTuple object from a sequence or iterable
 |
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |
 |  __new__(_cls, x, y)
 |      Create new instance of MyTuple(x, y)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  x
 |      The x value
 |
 |  y
 |      The y value
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  _fields = ('x', 'y')
 |  
 |  _fields_defaults = {}
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from builtins.tuple:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __getitem__(self, key, /)
 |      Return self[key].
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __hash__(self, /)
 |      Return hash(self).
 |  
 |  __iter__(self, /)
 |      Implement iter(self).
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __len__(self, /)
 |      Return len(self).
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __mul__(self, value, /)
 |      Return self*value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __rmul__(self, value, /)
 |      Return value*self.
 |  
 |  count(self, value, /)
 |      Return number of occurrences of value.
 |  
 |  index(self, value, start=0, stop=9223372036854775807, /)
 |      Return first index of value.
 |      
 |      Raises ValueError if the value is not present.

वैकल्पिक रूप से, आप पैरामीटर के प्रकार को इसके माध्यम से भी निर्दिष्ट कर सकते हैं:

MyTuple = named_tuple(
    "MyTuple",
    "My named tuple for x,y coordinates",
    x=("int", "The x value"),
    y=("int", "The y value")
)

-2

नहीं, आप केवल मॉड्यूल, क्लासेस और फ़ंक्शन में डॉक्टर के तार जोड़ सकते हैं (विधियों सहित)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.