簡単な方法で名前付きタプルにドキュメント文字列を追加することは可能ですか?
私は試した
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)"
しかし、それはそれをカットしません。他の方法で行うことは可能ですか?
これは、namedtuple
からの戻り値の周りに単純な空のラッパークラスを作成することで実現できます。作成したファイルの内容(nt.py
):
from collections import namedtuple
Point_ = namedtuple("Point", ["x", "y"])
class Point(Point_):
""" A point in 2d space """
pass
次に、Python REPL:
>>> print nt.Point.__doc__
A point in 2d space
または、次のことができます。
>>> help(nt.Point) # which outputs...
モジュールntのクラスPointに関するヘルプ: classPoint(Point) | 2次元空間の点 | |メソッド解決の順序: |ポイント |ポイント | __builtin __。Tuple | __builtin __。object ...
毎回手作業で行うのが気に入らない場合は、これを行うための一種のファクトリ関数を作成するのは簡単です。
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
同じことを疑問に思いながら、Google経由でこの古い質問に出くわしました。
クラス宣言から直接namedtuple()を呼び出すことで、さらに整理できることを指摘したいと思います。
from collections import namedtuple
class Point(namedtuple('Point', 'x y')):
"""Here is the docstring."""
Python 3)では、型の__doc__
属性が書き込み可能であるため、ラッパーは必要ありません。
from collections import namedtuple
Point = namedtuple('Point', 'x y')
Point.__doc__ = '''\
A 2-dimensional coordinate
x - the abscissa
y - the ordinate'''
これは、docstringがヘッダーの後に続く標準のクラス定義に密接に対応しています。
class Point():
'''A 2-dimensional coordinate
x - the abscissa
y - the ordinate'''
<class code>
これはPython 2では機能しません。
AttributeError: attribute '__doc__' of 'type' objects is not writable
。
簡単な方法で名前付きタプルにドキュメント文字列を追加することは可能ですか?
Python 3では、namedtupleのドキュメントを簡単に変更できます。
_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
...
_
これは、Python 2で同じことを達成するのが難しいことと比較して本当に簡単です。
Python 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__ = ()
_
別の名前でベースnamedtupleを作成する場合は、このような___repr__
_が必要です(上記の名前文字列引数_'NTBase'
_で行ったように):
_ def __repr__(self):
return 'NT(foo={0}, bar={1})'.format(
repr(self.foo), repr(self.bar))
_
Reprをテストするには、インスタンス化してから、eval(repr(instance))
へのパスが等しいかどうかをテストします。
_nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt
_
docsも ___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
は、ベースnamedtupleの接尾辞として:
_>>> Point.mro()
[<class '__main__.Point'>, <class '__main__.Point'>, <type 'Tuple'>, <type 'object'>]
# ^^^^^---------------------^^^^^-- same names!
_
___dict__
_を使用するクラスからサブクラス化するときに、それが作成されないようにするには、サブクラスでそれを宣言する必要もあります。 ___slots__
_ の使用に関するその他の注意事項については、この回答も参照してください。
Python 3.5なので、namedtuple
オブジェクトのdocstringを更新できます。
whatsnew から:
Point = namedtuple('Point', ['x', 'y']) Point.__doc__ += ': Cartesian coodinate' Point.x.__doc__ = 'abscissa' Point.y.__doc__ = 'ordinate'
Python 3.6+では次を使用できます:
class Point(NamedTuple):
"""
A point in 2D space
"""
x: float
y: float
受け入れられた回答で提案されているように、ラッパークラスを使用する必要はありません。単に文字通りadd docstring:
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]:
Voilà!
Raymond Hettingerによる namedtupleファクトリ関数 の独自のバージョンを作成し、オプションの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
この関数を作成して、名前付きタプルをすばやく作成し、タプルとその各パラメーターを文書化しました。
_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
_
次に、Tupleという名前の新しい名前を作成できます。
_MyTuple = named_Tuple(
"MyTuple",
"My named Tuple for x,y coordinates",
x="The x value",
y="The y value"
)
_
次に、記述された名前付きタプルを独自のデータでインスタンス化します。
_t = MyTuple(4, 8)
print(t) # prints: MyTuple(x=4, y=8)
_
Python3コマンドラインからhelp(MyTuple)
を実行すると、次のように表示されます。
_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")
)
_