Đây là một trường hợp khác của pylint
các quy tắc mù quáng.
"Các lớp không dùng để lưu trữ dữ liệu" - đây là một tuyên bố sai. Từ điển không tốt cho mọi thứ. Thành viên dữ liệu của một lớp là một cái gì đó có ý nghĩa, một mục từ điển là một cái gì đó tùy chọn. Bằng chứng: bạn có thể làm dictionary.get('key', DEFAULT_VALUE)
để ngăn chặn a KeyError
, nhưng không đơn giản __getattr__
với mặc định.
EDIT - các cách được đề xuất để sử dụng cấu trúc
Tôi cần cập nhật câu trả lời của mình. Ngay bây giờ - nếu bạn cần struct
, bạn có hai lựa chọn tuyệt vời:
a) Chỉ cần sử dụng attrs
Đây là một thư viện cho điều đó:
https://www.attrs.org/en/stable/
import attr
@attr.s
class MyClass(object): # or just MyClass: for Python 3
foo = attr.ib()
bar = attr.ib()
Những gì bạn nhận được thêm: không phải viết hàm tạo, giá trị mặc định, xác thực, __repr__
đối tượng chỉ đọc (để thay thế namedtuples
, ngay cả trong Python 2) và hơn thế nữa.
b) Sử dụng dataclasses
(Py 3.7+)
Sau nhận xét của hwjp, tôi cũng khuyên bạn nên dataclasses
:
https://docs.python.org/3/library/dataclasses.html
Điều này gần như tốt attrs
và là một cơ chế thư viện tiêu chuẩn ("bao gồm pin"), không có phụ thuộc bổ sung, ngoại trừ Python 3.7+.
Phần còn lại của câu trả lời trước
NamedTuple
không phải là tuyệt vời - đặc biệt là trước python 3's typing.NamedTuple
:
https://docs.python.org/3/library/typing.html#typing.NamedTuple
- bạn chắc chắn nên xem mẫu "lớp bắt nguồn từ NamedTuple
". Python 2 - namedtuples
được tạo ra từ các mô tả chuỗi - xấu, tệ và "lập trình bên trong chuỗi ký tự" ngu ngốc.
Tôi đồng ý với hai câu trả lời hiện tại ("cân nhắc sử dụng thứ khác, nhưng pylint không phải lúc nào cũng đúng" - câu được chấp nhận và "sử dụng bình luận ngăn chặn pylint"), nhưng tôi có đề xuất của riêng mình.
Hãy để tôi chỉ ra điều này một lần nữa: Một số lớp chỉ dùng để lưu trữ dữ liệu.
Bây giờ tùy chọn cũng cần xem xét - sử dụng property
-ies.
class MyClass(object):
def __init__(self, foo, bar):
self._foo = foo
self._bar = bar
@property
def foo(self):
return self._foo
@property
def bar(self):
return self._bar
Ở trên, bạn có các thuộc tính chỉ đọc, điều này được chấp nhận cho Đối tượng giá trị (ví dụ như các thuộc tính trong Thiết kế theo hướng miền), nhưng bạn cũng có thể cung cấp các bộ định vị - bằng cách này, lớp của bạn sẽ có thể chịu trách nhiệm cho các trường mà bạn có - ví dụ: để thực hiện một số xác thực, v.v. (nếu bạn có các bộ thiết lập, bạn có thể chỉ định bằng cách sử dụng chúng trong phương thức khởi tạo, tức là self.foo = foo
thay vì trực tiếp self._foo = foo
, nhưng cẩn thận, các bộ thiết lập có thể giả định các trường khác đã được khởi tạo và sau đó bạn cần xác thực tùy chỉnh trong phương thức khởi tạo) .