Є принаймні п’ять шість способів. Кращий спосіб залежить від того, який ви використовуєте.
Варіант 1: Просто додайте asdict()метод.
На основі опису проблеми я б дуже розглянув asdictспосіб здійснення речей, запропонований іншими відповідями. Це тому, що, здається, ваш об’єкт насправді не є колекцією:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
Використання інших варіантів, наведених нижче, може заплутати інших, за винятком випадків, коли дуже очевидно, які саме члени об'єкта будуть, а не будуть повторюватися або вказуватися як пари ключ-значення.
Варіант 1a: успадкуйте свій клас від 'typing.NamedTuple'(або переважно еквівалентного 'collections.namedtuple') та скористайтесь запропонованим для вас _asdictспособом .
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
Іменовані кортежі дуже зручний спосіб додати багато функціональних можливості для вашого класу з мінімальними зусиллями, в тому числі з _asdictметодом . Однак обмеження полягає в тому, що, як показано вище, НЗ включатиме у себе всіх членів _asdict.
Якщо є члени, яких ви не хочете включати у свій словник, вам доведеться змінити _asdictрезультат:
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
Іншим обмеженням є те, що NT доступний лише для читання. Це може бути або не бути бажаним.
Варіант 2: Впровадити __iter__.
Ось так, наприклад:
def __iter__(self):
yield 'a', self.a
yield 'b', self.b
yield 'c', self.c
Тепер ви можете просто зробити:
dict(my_object)
Це працює, оскільки dict()конструктор приймає ітерацію (key, value)пар для побудови словника. Перш ніж це зробити, задайте собі питання, чи повторення об’єкта як серії ключів, пар значень у такий спосіб - хоча це зручно для створення dict- може насправді дивувати поведінку в інших контекстах. Наприклад, задайте собі питання "якою повинна бути поведінка list(my_object)...?"
Крім того, зауважте, що безпосередній доступ до значень за допомогою obj["a"]синтаксису елемента get не працюватиме, а розпакування аргументів ключового слова не буде працювати. Для них вам потрібно буде застосувати протокол відображення.
Варіант 3: Впровадження в протокол відображення . Це дозволяє поведінку доступу за ключем, перекидання на a dictбез використання __iter__, а також забезпечує поведінку розпакування ( {**my_obj}) та поведінку розпакування ключового слова, якщо всі ключі є рядками ( dict(**my_obj)).
Протокол відображення вимагає, щоб ви надали (принаймні) два методи разом: keys()і __getitem__.
class MyKwargUnpackable:
def keys(self):
return list("abc")
def __getitem__(self, key):
return dict(zip("abc", "one two three".split()))[key]
Тепер ви можете робити такі речі:
>>> m=MyKwargUnpackable()
>>> m["a"]
'one'
>>> dict(m)
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m)
{'a': 'one', 'b': 'two', 'c': 'three'}
Як згадувалося вище, якщо ви використовуєте достатньо нову версію python, ви також можете розпакувати свій об'єкт протоколу відображення у розумінні словника так (і в цьому випадку не потрібно, щоб ваші ключі були рядками):
>>> {**m}
{'a': 'one', 'b': 'two', 'c': 'three'}
Зверніть увагу , що протокол відображення має пріоритет над по __iter__методі при заливці об'єкта до dictбезпосередньо (без використання kwarg розпакування, тобто dict(m)). Отже, можливо - а іноді і зручно - змусити об’єкт мати різну поведінку, коли він використовується як ітерабельний (наприклад, list(m)), ніж коли він передається в dict( dict(m)).
НАДКАЗАНО : Те, що ви МОЖЕТЕ використовувати протокол відображення, НЕ означає, що ви повинні це робити . Чи насправді має сенс передавати ваш об'єкт як набір пар ключ-значення або як аргументи та значення ключових слів? Чи справді доступ до нього за допомогою ключа - як і словника - справді має сенс?
Якщо відповідь на ці запитання так , можливо, варто розглянути наступний варіант.
Варіант 4: Подивіться на використання 'collections.abcмодуля ' .
Успадковуючи свій клас від 'collections.abc.Mappingабо 'collections.abc.MutableMappingповідомляючи іншим користувачам, що, незважаючи на всі наміри та цілі, ваш клас є відображенням * і можна очікувати, що він поводитиметься таким чином.
Ви все ще можете передати свій об’єкт так dictсамо, як вам потрібно, але для цього, мабуть, мало б причин. Через набрання качки , клопотання перекинути об’єкт відображення dictу більшість випадків буде просто додатковим непотрібним кроком.
Ця відповідь також може бути корисною.
Як зазначалося в коментарях нижче: варто згадати, що, роблячи це, метод abc по суті перетворює ваш клас об'єкта на dictподібний клас (за умови, що ви використовуєте, MutableMappingа не Mappingбазовий клас, призначений лише для читання ). Все, з чим ви могли б зробити dict, ви могли б зробити за допомогою власного об'єкта класу. Це може бути, а може і не бажано.
Також розгляньте числові abcs в numbersмодулі:
https://docs.python.org/3/library/numbers.html
Оскільки ви також перекидаєте свій об'єкт на int, можливо, має сенс перетворити свій клас на повноцінний, intтак що кастинг не потрібен.
Варіант 5: Ознайомтесь із використанням dataclassesмодуля (лише для Python 3.7), який включає зручний asdict()метод утиліти.
from dataclasses import dataclass, asdict, field, InitVar
@dataclass
class Wharrgarbl(object):
a: int
b: int
c: int
sum: InitVar[int]
version: InitVar[str] = "old"
def __post_init__(self, sum, version):
self.sum = 6
self.version = str(version)
Тепер ви можете зробити це:
>>> asdict(Wharrgarbl(1,2,3,4,"X"))
{'a': 1, 'b': 2, 'c': 3}
Варіант 6: Використання typing.TypedDict, яке було додано в python 3.8 .
ПРИМІТКА: варіант 6, швидше за все, НЕ те, що шукає ОР чи інші читачі, засновані на назві цього запитання. Дивіться додаткові коментарі нижче.
class Wharrgarbl(TypedDict):
a: str
b: str
c: str
Використовуючи цей параметр, результуючим об’єктом є adict (наголос: це не a Wharrgarbl). Немає жодної причини "кидати" його на дикт (якщо ви не робите копію).
А оскільки об’єктом є adict , підпис ініціалізації ідентичний підпису dictі як такий він приймає лише аргументи ключових слів або інший словник.
>>> w = Wharrgarbl(a=1,b=2,b=3)
>>> w
{'a': 1, 'b': 2, 'c': 3}
>>> type(w)
<class 'dict'>
Підкреслюється : наведений вище "клас" Wharrgarblнасправді зовсім не новий клас. Це просто синтаксичний цукор для створення набраних dictоб’єктів з полями різних типів для перевірки типу.
Як такий, цей параметр може бути досить зручним для сигналізації читачам вашого коду (а також для перевірки типу, такого як mypy), що такий dictоб'єкт повинен мати конкретні ключі з певними типами значень.
Але це означає, що ви не можете, наприклад, додавати інші методи, хоча ви можете спробувати:
class MyDict(TypedDict):
def my_fancy_method(self):
return "world changing result"
... але це не спрацює:
>>> MyDict().my_fancy_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'my_fancy_method'
* "Картування" стало стандартним "ім'ям" dictтипу качки