Есть как минимум пять- шесть способов. Предпочтительный способ зависит от вашего варианта использования.
Вариант 1. Просто добавьте asdict()метод.
Основываясь на описании проблемы, я бы очень внимательно рассмотрел asdictспособ выполнения вещей, предложенный другими ответами. Это потому, что не похоже, что ваш объект действительно является большой коллекцией:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
Использование других опций, приведенных ниже, может сбить с толку других, если только не очень очевидно, какие именно члены объекта будут и не будут повторяться или указаны как пары ключ-значение.
Вариант 1а: унаследовать свой класс от '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методом . Однако есть ограничение в том, что, как показано выше, NT будет включать в себя всех членов _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"]синтаксиса получения элемента не будет работать, и распаковка аргументов ключевого слова не будет работать. Для них вам потребуется реализовать протокол сопоставления.
Вариант 3: Внедрение в протокол отображения . Это позволяет осуществлять доступ по ключу, преобразовывать в 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в большинстве случаев приведение объекта сопоставления в a было бы просто дополнительным ненужным шагом.
Этот ответ тоже может быть полезен.
Как отмечено в комментариях ниже: стоит упомянуть, что выполнение этого способа 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, скорее всего, НЕ то, что ищут OP или другие читатели, исходя из названия этого вопроса. См. Дополнительные комментарии ниже.
class Wharrgarbl(TypedDict):
a: str
b: str
c: str
Используя эту опцию, результирующий объект будетdict (курсив: это не 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утки -подобного типа.