У меня есть три тесно связанные друг с другом переменные, и я не хочу передавать их по отдельности каждый раз, когда вызываю функцию. Как правильно их связать.
Контекст: назначение переменных — отслеживать некоторые свойства документа, пока я читаю его слово за словом.
Мой текущий подход состоит в том, чтобы связать их в класс:
class MarkdownIsOpen(object):
def __init__(self):
self.ChapterOpen = False
self.SectionOpen = False
self.ArticleOpen = False
Но мне это кажется немного неправильным, так как я не собираюсь добавлять какие-либо методы или другие функции.
Именованный кортеж был бы идеальным, если бы он был изменчивым.
Каким будет правильный (самый питонический) способ связать три переменные?
Словарь был бы простым.
Используйте namedtuples, это, вероятно, лучше всего подходит для этого.
Мне понравился этот: stackoverflow.com/a/18792190/6198978
Вы можете использовать простой именованный кортеж или простой словарь для этой цели, если вам действительно никогда не нужно определять какие-либо методы в классе.
Может взглянуть на этот вопрос: Существование изменяемого именованного кортежа в Python?
С двумя хорошими ответами: рекордкласс и список имен изменяемых альтернатив именованным кортежам
Вы можете использовать классы данных.
@dataclass
class MarkdownIsOpen:
ChapterOpen: bool = False
SectionOpen: bool = False
ArticleOpen: bool = False
Используйте класс данных:
@dataclass
class MarkdownIsOpen:
ChapterOpen: bool = False
SectionOpen: bool = False
ArticleOpen: bool = False
Или:
MarkdownIsOpen = make_dataclass('MarkdownIsOpen', ['ChapterOpen', 'SectionOpen', 'ArticleOpen'])
Обратите внимание, что для этого требуется Python 3.7.
Если вы используете Python <= 3.6, то подойдет и обычный класс. Классы стоят недорого, и они дают подсказку пользователю, что ваша функция ожидает не какой-то старый dict
-подобный, а контейнер особый со следующими атрибутами.
Сравните это, например, с C struct
или Scala case class
, которые в основном служат той же цели.
Кроме того, вы даже можете переопределить __slots__
и/или __getitem__
, чтобы разрешить dict
-подобный доступ и предотвратить добавление новых атрибутов:
class MarkdownIsOpen:
__slots__ = ('ChapterOpen', 'SectionOpen', 'ArticleOpen')
def __init__(self):
self.ChapterOpen = False
self.SectionOpen = False
self.ArticleOpen = False
def __getattr__(self, key):
return getattr(self, key)
def __setattr__(self, key, value):
setattr(self, key, value)
Пример:
m = MarkdownIsOpen()
m['ChapterOpen'] = True
print(m['SectionOpen'])
m['Nonexistent'] = False
Выход:
False
AttributeError: 'MarkdownIsOpen' object has no attribute 'Nonexistent'
Я не уверен, что понимаю преимущество этого над простым namedtuple, даже ПКП меня не убеждает (если только вам не нужна статическая проверка типа, что здесь, похоже, не так). Я бы все же предложил использовать namedtuple для этого.
Если вам нравится использовать подход с классами данных, то лучше написать: MarkdownIsOpen = make_dataclass('MarkdownIsOpen', ['ChapterOpen', 'SectionOpen', 'ArticleOpen']
).
@cglacet OP упомянул, что изменчивость необходима, что исключает namedtuple
. На самом деле я довольно большой поклонник namedtuple
, но у меня есть одна проблема с доступом с числовым индексом.
Можете ли вы привести пример вызова функции с этими переменными и что именно вы хотите сделать?