Trong python, làm cách nào để truyền một đối tượng lớp sang một dict


85

Giả sử tôi có một lớp đơn giản trong python

class Wharrgarbl(object):
    def __init__(self, a, b, c, sum, version='old'):
        self.a = a
        self.b = b
        self.c = c
        self.sum = 6
        self.version = version

    def __int__(self):
        return self.sum + 9000

    def __what_goes_here__(self):
        return {'a': self.a, 'b': self.b, 'c': self.c}

Tôi có thể truyền nó thành một số nguyên rất dễ dàng

>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> int(w)
9006

Đó là tuyệt vời! Nhưng, bây giờ tôi muốn chuyển nó thành một mệnh đề theo một kiểu tương tự

>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}

Tôi cần xác định điều gì để điều này hoạt động? Tôi đã thử thay thế cả hai __dict__dictcho __what_goes_here__, nhưng dict(w)kết quả là TypeError: Wharrgarbl object is not iterabletrong cả hai trường hợp. Tôi không nghĩ rằng chỉ cần làm cho lớp có thể lặp lại sẽ giải quyết được vấn đề. Tôi cũng đã thử sử dụng nhiều Google với nhiều từ ngữ khác nhau của "python cast object to dict" như tôi có thể nghĩ ra nhưng không thể tìm thấy bất kỳ điều gì có liên quan: {

Cũng thế! Lưu ý cách gọi w.__dict__sẽ không làm những gì tôi muốn vì nó sẽ chứa w.versionw.sum. Tôi muốn tùy chỉnh dàn diễn viên dictgiống như cách mà tôi có thể tùy chỉnh dàn diễn viên intbằng cách sử dụng def int(self).

Tôi biết rằng tôi có thể làm điều gì đó như thế này

>>> w.__what_goes_here__()
{'a': 'one', 'c': 'three', 'b': 'two'}

Nhưng tôi giả định rằng có một cách tuyệt vời để tạo ra dict(w)công việc vì nó cùng loại với int(w)hoặc str(w). Nếu không có cách nào khác đáng kinh ngạc hơn, điều đó cũng tốt thôi, chỉ cần tôi nghĩ là tôi sẽ hỏi. Oh! Tôi đoán vì nó quan trọng, đây là dành cho python 2.7, nhưng siêu điểm thưởng cho giải pháp 2.4 cũ và đã hỏng.

Có một câu hỏi khác là Nạp chồng __dict __ () trên lớp python tương tự như câu hỏi này nhưng có thể đủ khác để đảm bảo rằng đây không phải là một bản sao. Tôi tin rằng OP đang hỏi cách truyền tất cả dữ liệu trong các đối tượng lớp của anh ấy dưới dạng từ điển. Tôi đang tìm kiếm một cách tiếp cận tùy chỉnh hơn mà tôi không muốn mọi thứ __dict__có trong từ điển bị trả về dict(). Một cái gì đó như biến công khai và riêng tư có thể đủ để giải thích những gì tôi đang tìm kiếm. Các đối tượng sẽ lưu trữ một số giá trị được sử dụng trong tính toán và như vậy mà tôi không cần / muốn hiển thị trong từ điển kết quả.

CẬP NHẬT: Tôi đã chọn đi theo asdicttuyến đường được đề xuất nhưng đó là một lựa chọn khó khăn khi chọn những gì tôi muốn trở thành câu trả lời cho câu hỏi. Cả @RickTeachey và @ jpmc26 đều cung cấp câu trả lời mà tôi sẽ xem xét nhưng người trước đây có nhiều thông tin và tùy chọn hơn và cũng đạt được kết quả tương tự và được ủng hộ nhiều hơn nên tôi đã tiếp tục. Mặc dù vậy, ủng hộ tất cả xung quanh và cảm ơn vì sự giúp đỡ. Tôi đã ẩn nấp rất lâu và khó khăn trên dòng nước chảy tràn và tôi đang cố gắng đưa ngón chân vào nước nhiều hơn.


1
bạn đã thấy cái này chưa docs.python.org/3/reference/…
Garrett R

@GarrettR Nó hữu ích, nhưng nó không thực sự tiết lộ nhiều thông tin chi tiết về vấn đề cụ thể này.
Zizouz212


@RickTeachey nó chắc chắn tương tự như câu hỏi Overloading ..., mặc dù tôi đang tìm kiếm một biểu diễn chính tả có thể tùy chỉnh hơn. Ví dụ, đối tượng có thể đang lưu trữ những thứ mà tôi không muốn thấy trong dict.
xu hướng

Câu hỏi của bạn được diễn giải một cách sai lầm, bạn không muốn chuyển đổi hoặc chuyển đối tượng của mình thành biểu diễn chính tả (như vậy bạn có thể khôi phục hoàn toàn đối tượng nếu bạn chuyển đổi lại). Bạn chỉ muốn tạo một dạng xem biểu diễn chính tả cho (giả sử) các biến cá thể công khai.
smci

Câu trả lời:


117

Có ít nhất năm sáu cách. Cách ưa thích phụ thuộc vào trường hợp sử dụng của bạn là gì.

Tùy chọn 1: Chỉ cần thêm một asdict()phương thức.

Dựa trên mô tả vấn đề, tôi rất muốn xem xét asdictcách làm việc được đề xuất bởi các câu trả lời khác. Điều này là do có vẻ như đối tượng của bạn không thực sự là một bộ sưu tập:

class Wharrgarbl(object):

    ...

    def asdict(self):
        return {'a': self.a, 'b': self.b, 'c': self.c}

Việc sử dụng các tùy chọn khác bên dưới có thể gây nhầm lẫn cho những người khác trừ khi rất rõ ràng chính xác thành viên đối tượng nào sẽ và sẽ không được lặp lại hoặc được chỉ định dưới dạng cặp khóa-giá trị.

Tùy chọn 1a: Kế thừa lớp của bạn từ 'typing.NamedTuple'(hoặc phần lớn là tương đương 'collections.namedtuple') và sử dụng _asdictphương pháp được cung cấp cho bạn.

from typing import NamedTuple

class Wharrgarbl(NamedTuple):
    a: str
    b: str
    c: str
    sum: int = 6
    version: str = 'old'

Sử dụng một tuple được đặt tên là một cách rất tiện lợi để thêm nhiều chức năng vào lớp của bạn mà không tốn nhiều công sức, bao gồm cả một _asdictphương thức . Tuy nhiên, một hạn chế là, như đã trình bày ở trên, NT sẽ bao gồm tất cả các thành viên trong nó _asdict.

Nếu có những thành viên bạn không muốn đưa vào từ điển của mình, bạn sẽ cần sửa đổi _asdictkết quả:

from typing import NamedTuple

class Wharrgarbl(NamedTuple):
    a: str
    b: str
    c: str
    sum: int = 6
    version: str = 'old'

    def _asdict(self):
        d = super()._asdict()
        del d['sum']
        del d['version']
        return d

Một hạn chế khác là NT là chỉ đọc. Điều này có thể mong muốn hoặc không.

Phương án 2: Thực hiện __iter__.

Ví dụ như thế này:

def __iter__(self):
    yield 'a', self.a
    yield 'b', self.b
    yield 'c', self.c

Bây giờ bạn chỉ có thể làm:

dict(my_object)

Điều này hoạt động vì hàm dict()tạo chấp nhận một (key, value)cặp có thể lặp lại để tạo từ điển. Trước khi thực hiện việc này, hãy tự đặt câu hỏi liệu việc lặp lại đối tượng dưới dạng một chuỗi các cặp khóa, giá trị theo cách này - trong khi thuận tiện cho việc tạo dict- có thực sự là một hành vi đáng ngạc nhiên trong các ngữ cảnh khác hay không. Ví dụ, hãy tự đặt câu hỏi "hành vi list(my_object)nên là ...?"

Ngoài ra, hãy lưu ý rằng việc truy cập trực tiếp các giá trị bằng obj["a"]cú pháp get item sẽ không hoạt động và việc giải nén đối số từ khóa sẽ không hoạt động. Đối với những thứ đó, bạn cần triển khai giao thức ánh xạ.

Lựa chọn 3: Thực hiện các giao thức lập bản đồ . Điều này cho phép hành vi truy cập theo từng khóa, truyền đến một dictmà không cần sử dụng __iter__và cũng cung cấp hành vi giải nén ( {**my_obj}) và hành vi giải nén từ khóa nếu tất cả các khóa đều là chuỗi ( dict(**my_obj)).

Giao thức ánh xạ yêu cầu bạn cung cấp (tối thiểu) hai phương pháp cùng nhau: keys()__getitem__.

class MyKwargUnpackable:
    def keys(self):
        return list("abc")
    def __getitem__(self, key):
        return dict(zip("abc", "one two three".split()))[key]

Bây giờ bạn có thể làm những việc như:

>>> m=MyKwargUnpackable()
>>> m["a"]
'one'
>>> dict(m)  # cast to dict directly
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m)  # unpack as kwargs
{'a': 'one', 'b': 'two', 'c': 'three'}

Như đã đề cập ở trên, nếu bạn đang sử dụng phiên bản python đủ mới, bạn cũng có thể giải nén đối tượng giao thức ánh xạ của mình thành một dạng từ điển như vậy (và trong trường hợp này, khóa của bạn không bắt buộc phải là chuỗi):

>>> {**m}
{'a': 'one', 'b': 'two', 'c': 'three'}

Lưu ý rằng các giao thức lập bản đồ được ưu tiên hơn các __iter__phương pháp khi đúc một đối tượng đến một dictcách trực tiếp (mà không sử dụng kwarg giải nén, ví dụ dict(m)). Vì vậy, có thể- và đôi khi thuận tiện- khiến đối tượng có hành vi khác khi được sử dụng như một đối tượng có thể lặp lại (ví dụ list(m):) so với khi ép kiểu thành một dict( dict(m)).

NHÂN SỰ : Chỉ vì bạn CÓ THỂ sử dụng giao thức ánh xạ, KHÔNG có nghĩa là bạn NÊN làm như vậy . Liệu nó thực sự có ý nghĩa cho đối tượng của bạn để được thông qua xung quanh như một tập hợp các cặp khóa-giá trị, hoặc như các đối số và giá trị từ khóa? Việc truy cập nó bằng phím- giống như từ điển- có thực sự hợp lý không?

Nếu câu trả lời cho những câu hỏi này là , có lẽ bạn nên xem xét lựa chọn tiếp theo.

Tùy chọn 4: Xem xét sử dụng 'collections.abcmô-đun ' .

Kế thừa lớp của bạn từ 'collections.abc.Mappinghoặc 'collections.abc.MutableMappingbáo hiệu cho những người dùng khác rằng, đối với mọi ý định và mục đích, lớp của bạn là một ánh xạ * và có thể được mong đợi sẽ hoạt động theo cách đó.

Bạn vẫn có thể truyền đối tượng của mình đến một đối tượng dictnhư bạn yêu cầu, nhưng có lẽ sẽ có rất ít lý do để làm như vậy. Do tính năng gõ phím , nên việc bận tâm truyền đối tượng ánh xạ của bạn sang a dictsẽ chỉ là một bước bổ sung không cần thiết trong phần lớn thời gian.

Câu trả lời này cũng có thể hữu ích.

Như đã lưu ý trong các nhận xét bên dưới: điều đáng nói là làm điều này theo cách abc về cơ bản biến lớp đối tượng của bạn thành dictlớp giống như (giả sử bạn sử dụng MutableMappingchứ không phải Mappinglớp cơ sở chỉ đọc ). Mọi thứ bạn có thể làm dict, bạn có thể làm với đối tượng lớp của riêng bạn. Điều này có thể được, hoặc có thể không, mong muốn.

Ngoài ra, hãy xem xét abcs số trong numbersmô-đun:

https://docs.python.org/3/library/numbers.html

Vì bạn cũng đang truyền đối tượng của mình tới một int, có thể có ý nghĩa hơn khi chuyển về cơ bản lớp của bạn thành một lớp hoàn chỉnh intđể việc truyền không cần thiết.

Tùy chọn 5: Xem xét việc sử dụng dataclassesmô-đun (chỉ Python 3.7), bao gồm một asdict()phương thức tiện ích thuận tiện.

from dataclasses import dataclass, asdict, field, InitVar

@dataclass
class Wharrgarbl(object):
    a: int
    b: int
    c: int
    sum: InitVar[int]  # note: InitVar will exclude this from the dict
    version: InitVar[str] = "old"

    def __post_init__(self, sum, version):
        self.sum = 6  # this looks like an OP mistake?
        self.version = str(version)

Bây giờ bạn có thể làm điều này:

    >>> asdict(Wharrgarbl(1,2,3,4,"X"))
    {'a': 1, 'b': 2, 'c': 3}

Tùy chọn 6: Sử dụng typing.TypedDict, đã được thêm vào python 3.8 .

LƯU Ý: lựa chọn 6 có thể KHÔNG phải là điều mà OP, hoặc những độc giả khác dựa trên tiêu đề của câu hỏi này, đang tìm kiếm. Xem thêm bình luận bên dưới.

class Wharrgarbl(TypedDict):
    a: str
    b: str
    c: str

Sử dụng tùy chọn này, đối tượng kết quả là adict (nhấn mạnh: nó không phải là a Wharrgarbl). Không có lý do gì để "truyền" nó thành một chính tả (trừ khi bạn đang tạo một bản sao).

Và vì đối tượng là adict , chữ ký khởi tạo giống với chữ ký của dictvà như vậy nó chỉ chấp nhận các đối số từ khóa hoặc một từ điển khác.

    >>> w = Wharrgarbl(a=1,b=2,b=3)
    >>> w
    {'a': 1, 'b': 2, 'c': 3}
    >>> type(w)
    <class 'dict'>

Nhấn mạnh : "lớp" ở trên Wharrgarblthực ra không phải là một lớp mới. Nó chỉ đơn giản là đường cú pháp để tạo các dictđối tượng được định kiểu với các trường thuộc các kiểu khác nhau cho trình kiểm tra kiểu.

Do đó, tùy chọn này có thể khá thuận tiện để báo hiệu cho người đọc mã của bạn (và cả cho một trình kiểm tra kiểu như mypy) rằng một dictđối tượng như vậy được mong đợi có các khóa cụ thể với các kiểu giá trị cụ thể.

Nhưng điều này có nghĩa là bạn không thể, ví dụ, thêm các phương pháp khác, mặc dù bạn có thể thử:

class MyDict(TypedDict):
    def my_fancy_method(self):
        return "world changing result"

... nhưng nó sẽ không hoạt động:

>>> MyDict().my_fancy_method()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'my_fancy_method'

* "Lập bản đồ" đã trở thành "tên" tiêu chuẩn của dictloại vịt giống


1
Đây một cách để có được hiệu ứng OP muốn, nhưng bạn có thể nên làm rõ rằng nó có các hiệu ứng khác, ví dụ như for k, v in my_objectcũng sẽ được bật.
zwol

@RickTeachey Tôi thấy bạn đang lái xe ở điểm nào với quan điểm. Tôi chắc chắn không cần các đối tượng có thể lặp lại.
xu hướng

Tại sao chúng ta có thể đơn giản sử dụng hàm vars như đã đề cập trong liên kết khác: //stackoverflow.com/questions/61517/python-dictionary-from-an-objects-fields. Tôi có thiếu một số điều trong câu hỏi này?
người dùng

@user Câu hỏi của OP muốn chỉ các thành viên a, bctrong dict. Các varschức năng sẽ trở lại một cuốn từ điển với TẤT CẢ các thành viên đối tượng trong đó có những cái mà không được muốn: sumversion. Trong một số trường hợp, varsnó sẽ hoạt động nhưng theo kinh nghiệm của tôi thì nó không thực sự thành ngữ. Thông thường mọi người nói rõ ràng hơn, nói rằng "Tôi hiện đang truyền đối tượng của mình vào từ điển" bằng cách làm ví dụ obj.asdict(). Với vars, nó thường là một cái gì đó giống như obj_kwargs = vars(obj)theo sau MyObject(**obj_kwargs). Nói cách khác: varschủ yếu được sử dụng để sao chép các đối tượng.
Rick ủng hộ Monica

làm thế nào về việc thêm một phương thức trả về self.__dict__?
user32882

17

Không có phương pháp kỳ diệu nào sẽ làm được điều bạn muốn. Câu trả lời chỉ đơn giản là đặt tên cho nó một cách thích hợp. asdictlà một lựa chọn hợp lý cho một chuyển đổi đơn giản dict, lấy cảm hứng chủ yếu từ namedtuple. Tuy nhiên, phương thức của bạn rõ ràng sẽ chứa logic đặc biệt mà có thể không rõ ràng ngay từ tên đó; bạn chỉ trả về một tập hợp con của trạng thái lớp. Nếu bạn có thể nghĩ ra một cái tên dài dòng hơn một chút để truyền đạt các khái niệm một cách rõ ràng thì càng tốt.

Các câu trả lời khác đề xuất sử dụng __iter__, nhưng trừ khi đối tượng của bạn thực sự có thể lặp lại (đại diện cho một loạt các phần tử), điều này thực sự không có ý nghĩa gì và tạo thành một sự lạm dụng phương thức một cách khó xử. Thực tế là bạn muốn lọc ra một số trạng thái của lớp làm cho cách tiếp cận này càng trở nên khó hiểu.


vâng, trả về một tập hợp con của toàn bộ trạng thái của lớp, các giá trị liên quan, là điều tôi đang cố gắng đạt được. Tôi đã lưu trữ một số giá trị "ẩn" để làm cho mọi thứ nhanh hơn để tính toán / so sánh, v.v., nhưng chúng không phải là thứ mà con người muốn nhìn thấy hoặc chơi cùng và chúng cũng không thực sự đại diện cho chính đối tượng.
xu hướng

@ tr3buchet Trong mã ví dụ của bạn, các giá trị đó được chuyển vào trình khởi tạo . Đó có phải là cách nó có trong mã thực của bạn không? Có vẻ kỳ lạ khi các phép tính được lưu trong bộ nhớ cache sẽ được chuyển vào dưới dạng đối số.
jpmc26

không phải ở tất cả, tôi chỉ làm việc đó để cung cấp một ví dụ
thiên hướng

Chỉ muốn lưu ý rằng các tài liệu dường như không sử dụng __iter__như các câu trả lời khác đã đề xuất: "Đối với ánh xạ, nó nên lặp qua các khóa của vùng chứa và cũng nên được cung cấp dưới dạng phương thức iterkeys ()."
dbenton

@dbenton Đó không phải là những gì OP đang làm hoặc những gì các câu trả lời khác đang khuyến nghị. Đối tượng của OP không phải là "container", trong ngữ cảnh này về cơ bản được sử dụng như một từ đồng nghĩa của collection. Đối tượng của OP cũng không phải là thứ thường có nghĩa là ánh xạ. Một ánh xạ sẽ là một cái gì đó có số lượng khóa và giá trị tùy ý và nên mở rộng Mappinglớp cơ sở. Đối tượng có các thuộc tính được đặt tên cụ thể không thuộc loại này.
jpmc 26

11

một cái gì đó như thế này có thể sẽ hoạt động

class MyClass:
    def __init__(self,x,y,z):
       self.x = x
       self.y = y
       self.z = z
    def __iter__(self): #overridding this to return tuples of (key,value)
       return iter([('x',self.x),('y',self.y),('z',self.z)])

dict(MyClass(5,6,7)) # because dict knows how to deal with tuples of (key,value)

Ồ! thật thú vị! một bộ giá trị có thể lặp lại, tôi đã không xem xét điều này. Tôi sẽ làm một bài kiểm tra nhanh
xu hướng

Ngoài ra, trả về một iter của danh sách các bộ giá trị chụp nhanh tất cả các giá trị của x, y và z vào danh sách dựa trên nó. Trong trường hợp nếu 3 câu lệnh lợi nhuận, có thể (một cửa sổ nhỏ, nhưng vẫn có) việc chạy điều này trong môi trường luồng có thể dẫn đến một luồng khác sửa đổi thuộc tính y hoặc thuộc tính z sao cho x, y và và z không nhất quán.
PaulMcG

@PaulMcGuire: CPython có đảm bảo rằng tất cả chúng sẽ nhất quán ngay cả với mã của Joran không? Tôi đã nghĩ rằng một luồng khác có thể được lên lịch, ví dụ, sau khi bộ đầu tiên với xđược tạo, nhưng trước bộ thứ hai với y. Tôi có nhầm không, và thực sự khả năng hiểu danh sách là nguyên tử đối với lập lịch luồng?
Steve Jessop,

Bây giờ bạn hỏi, tôi nhận ra rằng ngay cả khả năng hiểu danh sách cũng không được đảm bảo nguyên tử, vì trình chuyển đổi luồng của Python làm như vậy ở cấp bytecode, không phải cấp nguồn. Nhưng hiển thị của bạn chỉ trong khoảng thời gian tạo danh sách - khi danh sách đã được tạo, thì mọi cập nhật đối với thuộc tính sẽ không quan trọng (trừ khi giá trị thuộc tính là đối tượng có thể thay đổi). Tốt nhất nên sử dụng dismô-đun để xem các mã byte thực tế.
PaulMcG

11

Tôi nghĩ rằng điều này sẽ làm việc cho bạn.

class A(object):
    def __init__(self, a, b, c, sum, version='old'):
        self.a = a
        self.b = b
        self.c = c
        self.sum = 6
        self.version = version

    def __int__(self):
        return self.sum + 9000

    def __iter__(self):
        return self.__dict__.iteritems()

a = A(1,2,3,4,5)
print dict(a)

Đầu ra

{'a': 1, 'c': 3, 'b': 2, 'sum': 6, 'version': 5}


điều gì đã xảy ra với tổng và phiên bản? Điều này có gì khác so với việc chỉ truy cập __dict__như câu trả lời khác được đề xuất?
Joran Beasley

nó không phải là mệnh lệnh. lệnh gọi tới iteritems trả về một trình lặp
Garrett R

1
Tôi giống như câu trả lời ... nhưng nó cần một công việc ít hơn trước khi nó đáp ứng yêu cầu của OP ...
Joran Beasley

câu trả lời này thực sự không khác gì @JoranBeasley. Sự khác biệt là của anh ta có chọn lọc trong khi của bạn lấy toàn bộ self.__dict__chứa các mục mà tôi không muốn có trong phiên bản từ điển của đối tượng.
thiên hướng

6

Giống như nhiều người khác, tôi khuyên bạn nên triển khai một hàm to_dict () hơn là (hoặc thêm vào) cho phép truyền vào từ điển. Tôi nghĩ rằng nó làm rõ ràng hơn rằng lớp hỗ trợ loại chức năng đó. Bạn có thể dễ dàng triển khai một phương pháp như thế này:

def to_dict(self):
    class_vars = vars(MyClass)  # get any "default" attrs defined at the class level
    inst_vars = vars(self)  # get any attrs defined on the instance (self)
    all_vars = dict(class_vars)
    all_vars.update(inst_vars)
    # filter out private attributes
    public_vars = {k: v for k, v in all_vars.items() if not k.startswith('_')}
    return public_vars

1

Thật khó để nói nếu không biết toàn bộ bối cảnh của vấn đề, nhưng tôi sẽ không viết quá __iter__.

Tôi sẽ thực hiện __what_goes_here__trên lớp.

as_dict(self:
    d = {...whatever you need...}
    return d

Không, đó là những gì các biến được lưu trữ trong.
Zizouz212

3
Tôi đặc biệt chỉ ra rằng điều w.__dict__đó không làm những gì tôi cần.
xu hướng

Nhưng __dict__có thể bị ghi đè, có thể không?
noisewaterphd

@noisewaterphd không, nó là một phương pháp ma thuật (có thể bạn có thể ghi đè nó nhưng ít nhất phải nói là có hàm ý đáng sợ)
Joran Beasley

1
Tại sao không kế thừa từ dict, hoặc có lẽ tốt hơn, chỉ cần tạo một phương thức trên lớp để trả về nó dưới dạng dict.
noisewaterphd

0

Tôi đang cố gắng viết một lớp là "cả hai" a listhoặc a dict. Tôi muốn lập trình viên có thể "truyền" đối tượng này thành a list(thả các phím) hoặc dict(với các phím).

Nhìn vào cách Python hiện thực hiện dict()ép kiểu: Nó gọi Mapping.update()với đối tượng được truyền. Đây là mã từ repo Python :

def update(self, other=(), /, **kwds):
    ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
        If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
        If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
        In either case, this is followed by: for k, v in F.items(): D[k] = v
    '''
    if isinstance(other, Mapping):
        for key in other:
            self[key] = other[key]
    elif hasattr(other, "keys"):
        for key in other.keys():
            self[key] = other[key]
    else:
        for key, value in other:
            self[key] = value
    for key, value in kwds.items():
        self[key] = value

Chữ hoa con cuối cùng của câu lệnh if, nơi nó đang lặp lại otherlà câu mà hầu hết mọi người đều nghĩ đến. Tuy nhiên, như bạn thấy, nó cũng có thể có một keys()tài sản. Điều đó, kết hợp với a __getitem__()sẽ giúp dễ dàng chuyển một lớp con vào từ điển một cách chính xác:

class Wharrgarbl(object):
    def __init__(self, a, b, c, sum, version='old'):
        self.a = a
        self.b = b
        self.c = c
        self.sum = 6
        self.version = version

    def __int__(self):
        return self.sum + 9000

    def __keys__(self):
        return ["a", "b", "c"]

    def __getitem__(self, key):
        # have obj["a"] -> obj.a
        return self.__getattribute__(key)

Sau đó, điều này sẽ hoạt động:

>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}

Bạn đã triển khai giao thức ánh xạ. Xem Tùy chọn 3 trong câu trả lời của tôi ở trên. Nếu bạn cũng muốn listgiảm các khóa, bạn có thể thêm một __iter__phương thức lặp qua các giá trị và quá trình truyền tới dictsẽ vẫn tiếp tục hoạt động. Lưu ý rằng thông thường với từ điển, nếu bạn truyền đến một danh sách, nó sẽ trả lại KEYS chứ không phải các giá trị như bạn yêu cầu. Điều này có thể gây ngạc nhiên cho những người khác sử dụng mã của bạn trừ khi rõ ràng tại sao điều này lại xảy ra.
Rick ủng hộ Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.