Инициализация объекта с несколькими аргументами

Есть лучший способ сделать это?

class MyClass:
    def __init__(self, my_var_1, my_var_2, my_var_3, my_var_4, my_var_5, my_var_6, my_var_7, my_var_8, my_var_9):
        self.my_var_1 = my_var_1
        self.my_var_2 = my_var_2
        self.my_var_3 = my_var_3
        self.my_var_4 = my_var_4
        self.my_var_5 = my_var_5
        self.my_var_6 = my_var_6
        self.my_var_7 = my_var_7
        self.my_var_8 = my_var_8
        self.my_var_9 = my_var_9

Предположим, что имена переменных не следуют шаблону.

«Предположим, что имена переменных не следуют шаблону». - тогда имело бы смысл не вкладывать в имена большой очевидный шаблон.

user2357112 20.12.2020 20:06

Другой вариант — получить аргументы ключевого слова с помощью **kwargs и прокрутить dict для установки атрибутов экземпляра. Вы должны указать аргументы ключевого слова, так как вам нужны ключевые слова для установки имени атрибута.

progmatico 20.12.2020 20:11

«Другой» на самом деле следует читать как «Другой». В Python почти всегда есть какие-то другие продвинутые способы что-то сделать. Вы можете получить dict и обновить с его помощью self.__dict__ вместо того, чтобы итерировать его для установки атрибутов, как очень простой пример.

progmatico 20.12.2020 20:23

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

progmatico 20.12.2020 21:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python.
Некоторые методы, о которых вы не знали, что они существуют в Python.
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если целью класса является просто хранение набора связанных данных («Обычный старый класс данных»), я бы использовал либо NamedTuple (неизменяемый), либо класс данных (изменяемый):

from typing import NamedTuple

class MyClass(NamedTuple):
    my_var_1: the_type
    my_var_2: the_type
    my_var_3: the_type
    my_var_4: the_type
    my_var_5: the_type
    my_var_6: the_type
    my_var_7: the_type
    my_var_8: the_type
    my_var_9: the_type
    

Или

from dataclasses import dataclass

@dataclass
class MyClass:
    my_var_1: the_type
    my_var_2: the_type
    # Ignoring other fields for brevity, but they'd be written the same as above

Где the_type — тип каждого поля. К сожалению, в этом случае синтаксис Python требует указания типа. Типовые подсказки в любом случае являются хорошей практикой, поскольку они помогают уменьшить количество ошибок, которые могут быть обнаружены до запуска кода. Если вам действительно не нужны типы, вы можете использовать старый синтаксис namedtuple:

from collections import namedtuple

MyClass = namedtuple("MyClass", ["my_var_1", "my_var_2", "my_var_3"])
obj = MyClass(1, 2, 3)
print(obj)
# Prints MyClass(my_var_1=1, my_var_2=2, my_var_3=3)

Все эти параметры сгенерируют для вас этот инициализатор вместе с другими функциями, такими как приятные методы __str__/__repr__. Например:

class MyClass(NamedTuple):
    my_var_1: int
    my_var_2: int
    my_var_3: int
    my_var_4: int
    my_var_5: int
    my_var_6: int
    my_var_7: int
    my_var_8: int
    my_var_9: int

obj = MyClass(1, 2, 3, 4, 5, 6, 7, 8, 9)
print(obj)
# Prints MyClass(my_var_1=1, my_var_2=2, my_var_3=3, my_var_4=4, my_var_5=5, my_var_6=6, my_var_7=7, my_var_8=8, my_var_9=9)

Не требуется ручное определение инициализатора.


Основное различие между этими двумя типами заключается в том, что dataclass можно изменять, а NamedTuple нельзя (как обычные кортежи):

# obj from above
print(obj.my_var_6)  # Prints 6

obj.my_var_6 = 5

Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: can't set attribute

Я бы посоветовал вам показать пример инициализации каждого из этих классов, поскольку это основное внимание в вопросе. Как выглядят сгенерированные инициализаторы? В вашем ответе сейчас я не демонстрирую, что какая-либо альтернатива является лучшим способом инициализации объектов, о чем и был задан вопрос. Типы не были частью исходного вопроса, поэтому ваш ответ кажется немного «яблоки против апельсинов» мне.

CryptoFool 20.12.2020 20:40

@ Стив Да. К сожалению, я написал этот ответ на клавиатуре Swype на моем телефоне в приложении, когда я выходил из автобуса. Я постараюсь улучшить его, когда у меня будет доступ к надлежащему компьютеру.

Carcigenicate 20.12.2020 20:44

@Carcigenicate, пожалуйста, не рискуйте своей безопасностью, отвечая на SO-вопросы (думаю, я никогда не говорил ничего подобного на SO). Ответ на самом деле точен и по делу, но он не объясняет почему, и для тех, кто не знает классы данных, может выглядеть так, как говорит Стив, из-за аннотаций типов.

progmatico 20.12.2020 20:54

Если вы хотите иметь возможность хранить произвольные пары ключ/значение, как если бы они были атрибутами хранящего их объекта, без необходимости определять их явно, вы можете определить класс, который действует как dict, но разрешает доступ к своим ключам/значениям. через ссылки на атрибуты, например:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

class MyClass(AttrDict):

    def __init__(self, *args, **kwargs):
        super(MyClass, self).__init__(*args, **kwargs)

        # Attributes built into your class
        self.predef = 'predefind'

    pass

# Define attributes at class creation time
mc = MyClass((('abc', '123'), ('foo', 'bar')))
print(mc.abc)
print(mc.foo)

# See that the class defined attribute is there
print(mc.predef)

# Change the value of an existing attribute
mc.abc = 'blah'
print(mc.abc)

# Create a new attribute
mc.xxx = 1111
print(mc.xxx)

from typing import NamedTuple

class MyClass(NamedTuple):
    my_var_1: int
    my_var_2: str

Результат:

123
bar
predefined
blah
1111

Если вы хотите применить определенный набор аргументов/атрибутов, вам понадобится что-то более сложное, чем это, или вы захотите использовать одну из других альтернатив. Но если вы хотите иметь возможность использовать произвольные атрибуты объекта с минимальным количеством установочного кода (никакого), это ваш ответ.

Другие вопросы по теме