#python #парсер #python_35
Есть класс:
class MyClass:
__slots__ = ('foo', 'bar')
Есть объект:
obj = MyClass()
И есть желание присвоить полям объекта значения разом:
obj.__something__ = ('foovalue', 202) # Распаковка из кортежа прямиком в поля объекта
Можно просто явно указать имена полей:
obj.foo, obj.bar = ('foovalue', 202)
Но если бы был способ распаковки значении без явного указания имён полей это бы сильно
сократило количество кода.
На данный момент приходится писать так:
class XBGHeader:
__slots__ = (
'id',
'_0',
'block_size',
'data_size',
'has_block_inside',
)
@staticmethod
def parse(stream):
obj = XBGHeader()
fmt = '=4s4I'
fmt_size = calcsize(fmt)
# Это место меня огорчает =(
(
obj.id,
obj._0,
obj.block_size,
obj.data_size,
obj.has_block_inside,
) = unpack(fmt, stream.read(fmt_size))
Можно и функцию написать:
def setattrs(attrs, obj, values):
# Присваивает список значении списку полей указанного объекта
for attr, value in zip(attrs, values):
setattr(obj, attr, value)
И приходилось бы писать так:
setattrs(obj.__slots__, obj, unpack(fmt, stream.read(fmt_size)))
Но хотелось бы pythonic решения этой задачи =)
Спасибо!!!
Ответы
Ответ 1
В таких случаях удобно использовать namedtuple: from collections import namedtuple XBGHeader = namedtuple('XBGHeader', ('id', 'us_0', 'block_size', 'data_size', 'has_block_inside') ) obj = XBGHeader(*unpack(fmt, stream.read(fmt_size)) # распаковка в вашем случае test_obj = XBGHeader(*(42, 0, 1024, 8192, 'foo')) print(test_obj) # XBGHeader(id=42, us_0=0, block_size=1024, data_size=8192, has_block_inside='foo') P.S. поля в namedtuple не могут начинаться с нижнего подчеркивания. Для версий Python 3.7 и старше можно использовать dataclass, который является почти альтернативой namedtuple с допольнительными возможностями. from dataclasses import dataclass from typing import Any @dataclass class XBGHeader: _id: int _0: Any block_size: int data_size: int has_block_inside: bool print(XBGHeader(42, 'bar', 1024, 8192, False)) # XBGHeader(_id=42, _0='bar', block_size=1024, data_size=8192, has_block_inside=0)Ответ 2
Руководство по магическим методам в Питоне class XBGHeader: def __init__(self, slots, *args): self.slots = slots self.__dict__.update(zip(slots, args)) return def __getattr__(self, attr): if attr in self.slots: return None else: raise AttributeError(attr) slots = ( 'id', '_0', 'block_size', 'data_size', 'has_block_inside', ) ob = XBGHeader(slots, 1, 2) print(ob.id) print(ob._0)
Комментариев нет:
Отправить комментарий