Автоматически сгенерированный конструктор Python - PullRequest
1 голос
/ 09 мая 2011

У меня есть бесчисленные классы Python из различных проектов из SQLAlchemy (и пара из Pygame), и я недавно заметил шаблон во многих из них: их конструкторы всегда работали примерно так:

class Foo(Base):
    def __init__(self, first, last, email, mi=""):
        self.first = first
        self.last = last
        self.email = email
        self.mi = mi

... при этом единственное, что сделал конструктор, - это перенес набор позиционных аргументов в точно идентично названный набор элементов данных, не выполняя никаких вычислений или других вызовов функций вообще.

Мне кажется, что это повторение не нужно и подвержено человеческим ошибкам при изменении.

Это подводит меня к вопросу: можно ли автоматически сгенерировать такую ​​функцию __init__(self, ...), желательно без использования байт-кода CPython или с помощью шаблонов / макросов для изменения самого исходного файла?

Ответы [ 3 ]

3 голосов
/ 09 мая 2011

Вы, вероятно, можете сделать это с метаклассами.Вот пример метакласса, который переопределяет __init__(): Python Class Decorator

Конечно, вам нужно будет как-то указать имена полей / аргументов - или использовать именованные аргументы, если вы предпочитаете,Вот один из способов сделать это:

# This is the mataclass-defined __init__
def auto_init(self, *args, **kwargs):
    for arg_val, arg_name in zip(args, self.init_args):
        setattr(self, arg_name, arg_val)

    # This would allow the user to explicitly specify field values with named arguments
    self.__dict__.update(kwargs)

class MetaBase(type):
    def __new__(cls, name, bases, attrs):
        attrs['__init__'] = auto_init
        return super(MetaBase, cls).__new__(cls, name, bases, attrs)

class Base(object):
    __metaclass__ = MetaBase

# No need to define __init__
class Foo(Base):
    init_args = ['first', 'last', 'email', 'mi']
1 голос
/ 09 мая 2011

Проверьте namedtle:

>>> from collections import namedtuple
>>> Foo = namedtuple("Foo", "first last email mi")
>>> f = Foo("Alfred", "Neumann", "aen@madmagazine.com", "E")
>>> f
Foo(first='Alfred', last='Neumann', email='aen@madmagazinecom', mi='E')
0 голосов
/ 09 мая 2011

Вы можете сделать что-то вроде этого:

class Foo(Base):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

Одна проблема с этим заключается в том, что нет гарантии, что все экземпляры будут иметь одинаковых членов. Другая проблема заключается в том, что все конструкторы должны вызываться с аргументами ключевых слов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...