Có thể thêm một chuỗi tài liệu vào một tệp tin có tên một cách dễ dàng không?
Có, theo một số cách.
Nhập lớp con.NamedTuple - Python 3.6+
Kể từ Python 3.6, chúng ta có thể sử dụng một class
định nghĩa typing.NamedTuple
trực tiếp, với một chuỗi doc (và các chú thích!):
from typing import NamedTuple
class Card(NamedTuple):
"""This is a card type."""
suit: str
rank: str
So với Python 2, việc khai báo rỗng __slots__
là không cần thiết. Trong Python 3.8, nó không cần thiết ngay cả đối với các lớp con.
Lưu ý rằng khai báo __slots__
không được để trống!
Trong Python 3, bạn cũng có thể dễ dàng thay đổi tài liệu trên một tệp tin có tên:
NT = collections.namedtuple('NT', 'foo bar')
NT.__doc__ = """:param str foo: foo name
:param list bar: List of bars to bar"""
Điều này cho phép chúng tôi xem mục đích dành cho họ khi chúng tôi kêu gọi họ trợ giúp:
Help on class NT in module __main__:
class NT(builtins.tuple)
| :param str foo: foo name
| :param list bar: List of bars to bar
...
Điều này thực sự dễ hiểu so với những khó khăn mà chúng tôi đã gặp phải khi hoàn thành điều tương tự trong Python 2.
Python 2
Trong Python 2, bạn sẽ cần
- phân lớp con được đặt tên, và
- khai báo
__slots__ == ()
Khai báo __slots__
là một phần quan trọng mà các câu trả lời khác ở đây bỏ lỡ .
Nếu bạn không khai báo __slots__
- bạn có thể thêm các thuộc tính đặc biệt có thể thay đổi vào các phiên bản, đưa ra các lỗi.
class Foo(namedtuple('Foo', 'bar')):
"""no __slots__ = ()!!!"""
Và bây giờ:
>>> f = Foo('bar')
>>> f.bar
'bar'
>>> f.baz = 'what?'
>>> f.__dict__
{'baz': 'what?'}
Mỗi trường hợp sẽ tạo ra một riêng biệt __dict__
khi __dict__
được truy cập (thiếu __slots__
sẽ không khác cản trở các chức năng, nhưng lightweightness của tuple, không thay đổi, và tuyên bố thuộc tính này là tất cả các tính năng quan trọng của namedtuples).
Bạn cũng sẽ muốn một __repr__
, nếu bạn muốn những gì được lặp lại trên dòng lệnh cung cấp cho bạn một đối tượng tương đương:
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__ = ()
cần một cái __repr__
như thế này nếu bạn tạo base nametuple với một tên khác (giống như chúng ta đã làm ở trên với đối số chuỗi tên, 'NTBase'
):
def __repr__(self):
return 'NT(foo={0}, bar={1})'.format(
repr(self.foo), repr(self.bar))
Để kiểm tra repr, hãy khởi tạo, sau đó kiểm tra xem có bằng nhau về lượt vượt qua eval(repr(instance))
nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt
Ví dụ từ tài liệu
Tài liệu cũng đưa ra một ví dụ như vậy, liên quan đến __slots__
- Tôi đang thêm chuỗi tài liệu của riêng mình vào đó:
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)
...
Lớp con được hiển thị ở trên đặt __slots__
thành một bộ trống. Điều này giúp giữ cho yêu cầu bộ nhớ thấp bằng cách ngăn chặn việc tạo các từ điển phiên bản.
Điều này thể hiện cách sử dụng tại chỗ (giống như một câu trả lời khác ở đây gợi ý), nhưng lưu ý rằng việc sử dụng tại chỗ có thể trở nên khó hiểu khi bạn nhìn vào thứ tự giải quyết phương pháp, nếu bạn đang gỡ lỗi, đó là lý do tại sao ban đầu tôi đề xuất sử dụng Base
làm hậu tố cho base có têntuple:
>>> Point.mro()
[<class '__main__.Point'>, <class '__main__.Point'>, <type 'tuple'>, <type 'object'>]
# ^^^^^---------------------^^^^^-- same names!
Để ngăn việc tạo __dict__
lớp con khi từ một lớp sử dụng nó, bạn cũng phải khai báo nó trong lớp con. Xem thêm câu trả lời này để biết thêm những lưu ý khi sử dụng__slots__
.
namedtuple
thành một "đối tượng" chính thức? Do đó làm mất một số lợi ích về hiệu suất từ các bộ giá trị được đặt tên?