Dataclass – это совершенно новая структура данных, которые отображаются в Python 3.7. Недавно @Btaskaya написать об этом отличной статьей. Если вы еще не прочитали, вы можете прочитать здесь.
Dataclass имеет перспективные функции для создания многоразовых, самоуверенных и автоматических объектов метаданных. До этого я использовал для использования Дикт
Формат для создания объектов метаданных, но копирование и вставка одного и того же объекта все время скучно и конфликт с сухим (не повторять себя) правило.
Это было так:
Metadata = {} Metadata["id"] = id Metadata["url"] = url if something: Metadata["some_field"] = some_data Metadata["media"] = {} Metadata["media"]["id"] = media_id ...
Я могу использовать NamedTuple
или что-то вместо обдумывать
Но у них есть некоторые ограничения И у меня на самом деле не было достаточно времени, чтобы реализовать что-то фантастику в первые дни проекта. Когда I Refactor Code я понимаю, что Dataclass более функционален для моих потребностей.
В этой статье я покажу вам, как реализовать полностью автоматизированные объекты метаданных с помощью Dataclasses Step за шагом.
Часть 1: Внедрить поля метаданных, которые не нуждаются в расчете
На этом шаге нет проблем. Это просто стандартная реализация.
from dataclasses import * @dataclass class Metadata: title: str url: str created_at: str = None # Fields may have default value
Часть 2: Добавьте некоторые поля, которые нуждаются в расчете, и давайте вычисляем его автоматически.
Эти поля получит значения только после расчетов. В нашем случае post_id
следует равнить случайное число плюс URL.
import random from dataclasses import * @dataclass class Metadata: # Normal fields title: str url: str created_at: str = None # Calculated fields post_id: str = field(init=False) def __post_init__(self): random_number = random.randint(100000, 999999) self.post_id = f"{random_number}_{self.url}"
__post_init__
Функция рассчитает наше поле post_id
после инициации.
Давайте назовем это:
>>> Metadata( ... title="Some Article", ... url="https://example.com/article.html", ... created_at="2018-09-23" ... ) Metadata(title='Some Article', url='https://example.com/article.html', created_at='2018-09-23', post_id='696953_https://example.com/article.html')
Попался!
Часть 3: сделать наши руки грязнее; Добавить __Post_init__ только Pseudo полей
Мы можем захотеть построить автономные комплексные структуры. Например, если одно поле аннотировано, Dataclass может построить всю подструктуру для нас. В нашем случае мы используем дополнительные поля автор_names.
и author_ids
построить Авторы
поле как Список
обдумывать
. Если информация о авторе не предусмотрена для статьи, стоимость Авторы
поле должно быть Нет
Отказ
import random from dataclasses import * @dataclass class Metadata: # Normal fields title: str url: str created_at: str = None authors: list = None # Calculated fields post_id: str = field(init=False) # Non-nullable Pseudo fields author_names: InitVar[list] author_ids: InitVar[list] def __post_init__(self, author_names, author_ids): # You have to pass pseudo fields as the parameter. random_number = random.randint(100000, 999999) self.post_id = f"{random_number}_{self.url}" self.authors = [] for i in range(0, len(author_names)): self.authors.append({"id": author_ids[i], "name": author_names[i]})
Давайте назовем это:
>>> Metadata( ... title="Some Article", ... url="https://example.com/article.html", ... created_at="2018-09-23" ... ) TypeError: non-default argument 'author' follows default argument.
Это не сработало:(
Важное примечание: Вы должны группировать по умолчанию и не по умолчанию.
Попробуйте снова:
import random, json from dataclasses import * @dataclass class Metadata: # Non-nullable Pseudo fields author_names: InitVar[list] author_ids: InitVar[list] # Normal fields title: str url: str created_at: str = None authors: list = None # Calculated fields post_id: str = field(init=False) def __post_init__(self, author_names, author_ids): # You have to pass pseudo fields as the parameter. random_number = random.randint(100000, 999999) self.post_id = f"{random_number}_{self.url}" self.authors = [] for i in range(0, len(author_names)): self.authors.append({"id": author_ids[i], "name": author_names[i]}) def to_json(self): json.dumps(asdict(self))
Давайте назовем это снова:
>>> Metadata( ... title="Some Article", ... url="https://example.com/article.html", ... created_at="2018-09-23", ... author_names=["Furkan Kalkan", "John Doe"], ... author_ids=["1", "2"] ... ) Metadata(title='Some Article', url='https://example.com/article.html', created_at='2018-09-23', authors=[{'id': '1', 'name': 'Furkan Kalkan'}, {'id': '2', 'name': 'John Doe'}], post_id='692728_https://example.com/article.html')
Ага!
Но ждать… Где автор_names.
и author_ids
пропали?
Примечание: Псевдо поля, которые Initvar.
экземпляр, используемый только в __post_init __ ()
В качестве параметров они не являются частью объекта.
>> Metadata.author_names Traceback (most recent call last): File "", line 1, in AttributeError: type object 'Metadata' has no attribute 'author_names'
Часть 4: Нам не нужно определять author_names.
Мы можем сделать псевдоэлектрические поля тоже по желанию.
import random, json from dataclasses import * @dataclass class Metadata: # Non-nullable Pseudo fields author_ids: InitVar[list] # Normal fields title: str url: str created_at: str = None authors: list = None # Nullable Pseudo fields author_names: InitVar[list] = field(default=None) # Calculated fields post_id: str = field(init=False) def __post_init__(self, author_names, author_ids): # You have to pass pseudo fields as the parameter. random_number = random.randint(100000, 999999) self.post_id = f"{random_number}_{self.url}" if author_names: self.authors = [] for i in range(0, len(author_names)): self.authors.append({"id": author_ids[i], "name": author_names[i]}) def to_json(self): json.dumps(asdict(self))
Назови это:
>>> Metadata( ... title="Some Article", ... url="https://example.com/article.html", ... created_at="2018-09-23", ... author_ids=["1", "2"] ... ) Metadata(title='Some Article', url='https://example.com/article.html', created_at='2018-09-23',authors=None,post_id='692728_https://example.com/article.html')
Часть 5: нам нужно JSON.
Объекты Python хороши, но нам нужно бросить его как JSON, чтобы опубликовать его на веб-сервисы, MQS и т. Д. Библиотека Dataclass встроен в функцию наркоман ()
который может бросить ваш объект на обдумывать
.
Давайте напишем обертку для нашего объекта.
import random, json from dataclasses import * @dataclass class Metadata: # Non-nullable Pseudo fields author_names: InitVar[list] author_ids: InitVar[list] # Normal fields title: str url: str created_at: str = None authors: list = None # Calculated fields post_id: str = field(init=False) def __post_init__(self, author_names, author_ids): # You have to pass pseudo fields as the parameter. random_number = random.randint(100000, 999999) self.post_id = f"{random_number}_{self.url}" if author_names: self.authors = [] for i in range(0, len(author_names)): self.authors.append({"id": author_ids[i], "name": author_names[i]}) def to_json(self): return json.dumps(asdict(self))
Проверь это:
>>> m = Metadata( ... title="Some Article", ... url="https://example.com/article.html", ... created_at="2018-09-23", ... author_names=["Furkan Kalkan", "John Doe"], ... author_ids=["1", "2"] ... ) >>> m.to_json() {"title": "Some Article", "url": "https://example.com/article.html", "created_at": "2018-09-23", "authors": [{"id": "1", "name": "Furkan Kalkan"}, {"id": "2", "name": "John Doe"}], "post_id": "466969_https://example.com/article.html"}
Часть 6: Удалите ненужные поля с JSON.
Мы хотим удалить Нет
Ценные поля от JSON, кроме поля URL. Это возможно с небольшим количеством изменений:
def to_json(self): metadata = asdict(self) for key in list(metadata): if key != "url" and metadata[key] == None: del metadata[key] return json.dumps(metadata)
Оригинал: “https://dev.to/furkan_kalkan1/a-fully-automated-metadata-objects-with-python-37s-brand-new-dataclass-library-492i”