Я вижу такие шаблоны, как
def __init__(self, x, y, z):
...
self.x = x
self.y = y
self.z = z
...
довольно часто, часто с гораздо большим количеством параметров. Есть ли хороший способ избежать такого утомительного повторения? Должен ли класс наследовать от namedtuple
?
__slots__
для этой цели, хотя ; это слегка не пифонично (более многословно, чтобы сэкономить память), но мне нравится это во многом, чтобы избежать риска самовосстановления целого нового атрибута, если я опишу имя.ini <shortcut> x, y, z): <shortcut>
и вы сделали.Ответы:
Изменить: Если у вас есть Python 3.7+ просто используйте классы данных
Решение для декоратора, которое сохраняет подпись:
источник
signature
Отказ от ответственности: Кажется, что несколько человек обеспокоены представлением этого решения, поэтому я предоставлю очень четкую оговорку. Вы не должны использовать это решение. Я предоставляю это только в качестве информации, чтобы вы знали, что язык способен на это. Остальная часть ответа просто показывает языковые возможности, а не одобряет их использование таким образом.
Нет ничего плохого в том, чтобы явно копировать параметры в атрибуты. Если в ctor слишком много параметров, это иногда считается запахом кода, и, возможно, вам следует сгруппировать эти параметры в меньшее количество объектов. В других случаях это необходимо, и в этом нет ничего плохого. В любом случае, делать это явно - путь.
Однако, поскольку вы спрашиваете, КАК это можно сделать (а не нужно ли это делать), то одно из решений заключается в следующем:
источник
self.__dict__.update(kwargs)
может быть немного более питоническимA.__init__
самом деле ожидают аргументы , и нет проверки ошибок для имен аргументов с ошибками.kwargs
оставляя вас открытым для эквивалента атаки SQL-инъекцией. Если у вашего объекта есть метод с именемmy_method
и вы передаете аргумент с именемmy_method
в конструктор, тоupdate()
в словаре вы просто переписали метод.Как уже упоминалось, повторение неплохое, но в некоторых случаях именованный кортеж отлично подходит для такого типа проблем. Это позволяет избежать использования locals () или kwargs, что обычно является плохой идеей.
Я нашел ограниченное использование для него, но вы можете наследовать именованный кортеж, как и любой другой объект (пример продолжается):
источник
properties
метод может быть записан как разreturn tuple(self)
, что становится более сопровождаемым , если в будущем больше полей добавляются к определению namedtuple.XYZ = namedtuple("XYZ", "x y z")
работает так же хорошо.namedtuple
s для этой конкретной цели, особенно в математическом коде, где функция может быть сильно параметризована и иметь кучу коэффициентов, которые имеют смысл только вместе.namedtuple
том, что они доступны только для чтения. Вы не можете сделатьabc.x += 1
или что-нибудь в этом роде.явный лучше, чем неявный ... так что вы можете сделать его более кратким:
Лучший вопрос, вы должны?
... при этом если вы хотите именованный кортеж, я бы порекомендовал использовать именованный кортеж (помните, что у кортежей есть определенные условия): возможно, вы хотите упорядоченный приговор или даже просто диктовку ...
источник
if k != "self":
можно было бы заменитьif v is not self:
дешевый тест на идентичность, а не сравнение строк. Я полагаю, что технически__init__
можно было бы вызвать второй раз после строительства и передатьself
в качестве последующего аргумента, но я действительно не хочу думать, какой монстр это сделает. :-)locals
:set_fields_from_locals(locals())
. Тогда это не более, чем более волшебные решения на основе декораторов.Чтобы расширить
gruszczy
ответ, я использовал такой шаблон:Мне нравится этот метод, потому что он:
super().__init(...)
)X.__init__
До Python 3.6 это не давало контроля над порядком, в котором установлены атрибуты, что может быть проблемой, если некоторые атрибуты являются свойствами с сеттерами, которые обращаются к другим атрибутам.
Возможно, это можно немного улучшить, но я единственный пользователь своего собственного кода, поэтому я не беспокоюсь о какой-либо форме очистки входных данных. Возможно,
AttributeError
было бы более уместным.источник
Вы также можете сделать:
Конечно, вам придется импортировать
inspect
модуль.источник
Это решение без какого-либо дополнительного импорта.
Вспомогательная функция
Небольшая вспомогательная функция делает ее более удобной и многократно используемой:
заявка
Вам нужно позвонить с помощью
locals()
:Тест
Вывод:
Без изменения
locals()
Если вы не любите менять,
locals()
используйте эту версию:источник
locals()
не следует изменять (в вашем случае это может повлиять на удаление интерпретатораself
из области видимости вызывающей функции)self
все еще доступен в__init__
.Интересная библиотека, которая обрабатывает это (и избегает многих других шаблонов), является attrs . Ваш пример, например, может быть сведен к этому (предположим, что класс вызывается
MyClass
):Вам даже не нужен
__init__
метод больше, если он не делает другие вещи, а также. Вот хорошее введение от Глифа Лефковица .источник
attr
становится избыточнойdataclasses
?Мой 0,02 $. Это очень близко к ответу Джорана Бизли, но более элегантно:
Кроме того, ответ Майка Мюллера (лучший на мой вкус) можно уменьшить с помощью этой техники:
И просто звонок
auto_init(locals())
от вашего__init__
источник
locals()
не следует изменять (неопределенное поведение)Это естественный способ делать вещи в Python. Не пытайтесь изобретать что-то более умное, это приведет к чрезмерно умному коду, который никто в вашей команде не поймет. Если вы хотите быть командным игроком, а затем продолжайте писать это так.
источник
Python 3.7 года
В Python 3.7 вы можете (ab) использовать
dataclass
декоратор, доступный изdataclasses
модуля. Из документации:Если ваш класс большой и сложный, использовать его может быть неуместно
dataclass
. Я пишу это в день выпуска Python 3.7.0, поэтому шаблоны использования еще не установлены.источник