Страницы

Поиск по вопросам

вторник, 10 декабря 2019 г.

Есть ли нативный способ присвоить список значений полям объекта в Python?

#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)

Комментариев нет:

Отправить комментарий