Более элегантный способ объявления нескольких переменных одновременно

Чтобы объявить несколько переменных одновременно, я бы сделал:

a, b = True, False

Но если бы мне пришлось объявлять гораздо больше переменных, это получается все менее и менее элегантно:

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True

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

Заранее спасибо!

Редактировать:

Это должно быть очень просто, но если бы я использовал список или кортеж для хранения переменных, как бы я подошел, чтобы быть полезным, так как:

aList = [a,b]

Не действует, я бы сделал:

a, b = True, True

Или чего мне не хватает?

8 ответов

Решение

Как и предполагали другие, маловероятно, что использование 10 различных локальных переменных с логическими значениями является лучшим способом написания вашей подпрограммы (особенно если они действительно имеют однобуквенные имена:)

В зависимости от того, что вы делаете, может иметь смысл использовать словарь. Например, если вы хотите установить логические предустановленные значения для набора однобуквенных флагов, вы можете сделать это:

>>> flags = dict.fromkeys(["a", "b", "c"], True)
>>> flags.update(dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Если вы предпочитаете, вы также можете сделать это с помощью одного оператора присваивания:

>>> flags = dict(dict.fromkeys(["a", "b", "c"], True),
...              **dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Второй параметр для dict не предназначен для этого полностью: он действительно позволяет вам переопределять отдельные элементы словаря, используя такие ключевые аргументы, как d=False, Код выше взрывает результат выражения, следующего за ** в набор ключевых аргументов, которые передаются вызываемой функции. Это, безусловно, надежный способ создания словарей, и люди, кажется, по крайней мере принимают эту идиому, но я подозреваю, что некоторые могут считать ее непифонической. </disclaimer>


Еще один подход, который, вероятно, является наиболее интуитивным, если вы будете часто использовать этот шаблон, заключается в определении ваших данных в виде списка значений флагов (True, False) сопоставляется с именами флагов (односимвольные строки). Затем вы преобразуете это определение данных в инвертированный словарь, который отображает имена флагов в значения флагов. Это может быть сделано довольно кратко с помощью понимания вложенного списка, но вот очень читаемая реализация:

>>> def invert_dict(inverted_dict):
...     elements = inverted_dict.iteritems()
...     for flag_value, flag_names in elements:
...         for flag_name in flag_names:
...             yield flag_name, flag_value
... 
>>> flags = {True: ["a", "b", "c"], False: ["d", "e"]}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Функция invert_dict является функцией генератора. Он генерирует или возвращает - это означает, что он многократно возвращает значения пар ключ-значение. Эти пары ключ-значение являются инверсией содержимого двух элементов исходного flags толковый словарь. Их кормят в dict конструктор. В этом случае dict Конструктор работает не так, как описано выше, потому что в качестве аргумента ему подают итератор, а не словарь.


Опираясь на комментарий @Chris Lutz: если вы действительно будете использовать это для односимвольных значений, вы можете сделать

>>> flags = {True: 'abc', False: 'de'}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Это работает, потому что строки Python являются итеративными, что означает, что их можно перемещать по значению по значению. В случае строки значения представляют собой отдельные символы в строке. Поэтому, когда они интерпретируются как итерируемые, как в этом случае, когда они используются в цикле for, ['a', 'b', 'c'] а также 'abc' эффективно эквивалентны. Другим примером может быть, когда они передаются в функцию, которая принимает итеративный, как tuple,

Лично я бы не стал этого делать, потому что он не читается интуитивно: когда я вижу строку, я ожидаю, что она будет использоваться как одно значение, а не как список. Поэтому я смотрю на первую строку и думаю: "Хорошо, значит, есть флаг True и флаг False". Так что, хотя это возможно, я не думаю, что это путь. С другой стороны, это может помочь объяснить понятия итераторов и итераторов более четко.


Определение функции invert_dict такой, что он на самом деле возвращает словарь - тоже неплохая идея; Я в основном просто не делал этого, потому что это действительно не помогает объяснить, как работает рутина.


По-видимому, в Python 2.7 есть словарные представления, которые позволили бы реализовать чрезвычайно лаконичный способ реализации этой функции. Это оставлено в качестве упражнения для читателя, так как у меня не установлен Python 2.7:)

Вы также можете комбинировать некоторые функции из универсального модуля itertools. Как говорится, есть больше, чем один способ сделать это. Подожди, люди Python не говорят этого. Ну, в любом случае это правда. Я предполагаю, что Гвидо дал нам словарное понимание, чтобы был один очевидный способ сделать это.

a, b, c, d, e, g, h, i, j = (True,)*9
f = False

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

a = b = c = d = e = g = h = i = j = True
f = False

Это разработка @ Jeff Mercado и моих комментариев.

Когда вы делаете это:

a, b = c, d

Работает с упаковкой и распаковкой кортежей. Вы можете разделить этапы упаковки и распаковки:

_ = c, d
a, b = _

Первая строка создает кортеж с именем _ который имеет два элемента, первый со значением c а второй со значением d, Вторая строка распаковывает _ кортеж в переменные a а также b, Это ломает вашу огромную строку:

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True, True, True, True

На две меньшие строки:

_ = True, True, True, True, True, False, True, True, True, True
a, b, c, d, e, f, g, h, i, j = _

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

Если у вас есть список значений, вы можете распаковать их. Вы просто должны сначала преобразовать его в кортеж. Например, следующее назначит значение от 0 до 9 каждому из a через jсоответственно:

a, b, c, d, e, f, g, h, i, j = tuple(range(10))

РЕДАКТИРОВАТЬ: аккуратный трюк, чтобы назначить все из них как истина, кроме элемента 5 (переменная f):

a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))

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

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

Интуитивно показал, как вы можете использовать словарь для этого, и Крис Латс показал, как использовать кортеж для временного хранения перед распаковкой в ​​отдельные переменные, но другой вариант, который следует рассмотреть, это использовать collections.namedtuple связывать значения более постоянно.

Так что вы можете сделать что-то вроде:

# Define the attributes of our named tuple
from collections import namedtuple
DataHolder = namedtuple("DataHolder", "a b c d e f g")

# Store our data
data = DataHolder(True, True, True, True, True, False, True)

# Retrieve our data
print(data)
print(data.a, data.f)

Надеемся, что настоящий код будет использовать более значимые имена, чем "DataHolder" и буквы алфавита, конечно.

В чем проблема, на самом деле?

Если вам действительно нужно или вы хотите 10 a, b, c, d, e, f, g, h, i, j, не будет никакой другой возможности, в тот или иной момент, написать a и написать b и написать c.....

Если значения все разные, вы будете обязаны написать для примера

a = 12
b= 'sun'
c = A() #(where A is a class)
d = range(1,102,5)
e = (line in filehandler if line.rstrip())
f = 0,12358
g = True
h = random.choice
i = re.compile('^(!=  ab).+?<span>')
j = [78,89,90,0]

то есть определение "переменных" индивидуально.

Или, используя другое письмо, не нужно использовать _:

a,b,c,d,e,f,g,h,i,j =\
12,'sun',A(),range(1,102,5),\
(line for line in filehandler if line.rstrip()),\
0.12358,True,random.choice,\
re.compile('^(!=  ab).+?<span>'),[78,89,90,0]

или же

a,b,c,d,e,f,g,h,i,j =\
(12,'sun',A(),range(1,102,5),
 (line for line in filehandler if line.rstrip()),
 0.12358,True,random.choice,
 re.compile('^(!=  ab).+?<span>'),[78,89,90,0])

,

Если некоторые из них должны иметь одинаковое значение, проблема в том, что это слишком долго писать

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True 

?

Тогда вы можете написать:

a=b=c=d=e=g=h=i=k=j=True
f = False

,

Я не понимаю, в чем именно твоя проблема. Если вы хотите написать код, вы обязаны использовать символы, необходимые для написания инструкций и определений. Что-то еще?

Интересно, не является ли ваш вопрос признаком того, что вы что-то неправильно поняли.

Когда кто-то пишет a = 10 нельзя создавать переменную в смысле "порция памяти, значение которой может измениться". Эта инструкция:

  • либо вызывает создание объекта типа integer и значение 10 и связывание имени "а" с этим объектом в текущем пространстве имен

  • или переназначить имя "а" в пространстве имен для объекта 10 (потому что "а" был предварительно связан с другим объектом)

Я говорю это потому, что не вижу утилиты для определения 10 идентификаторов a, b, c..., указывающих на False или True. Если эти значения не меняются во время выполнения, почему 10 идентификаторов? И если они меняются, зачем сначала определять идентификаторы?, Они будут создаваться при необходимости, если не определены ранее

Ваш вопрос кажется мне странным

Похоже, вы подходите ко мне со своей проблемой.

Перепишите свой код, чтобы использовать кортеж или написать класс для хранения всех данных.

Как и JavaScript, вы также можете использовать несколько операторов в одной строке в Pythona = 1; b = "Hello World"; c += 3

Мне нравится топ-проголосовавший ответ; однако, у него есть проблемы со списком, как показано.

  >> a, b = ([0]*5,)*2
  >> print b
  [0, 0, 0, 0, 0]
  >> a[0] = 1
  >> print b
  [1, 0, 0, 0, 0]

Это обсуждается очень подробно (здесь), но суть в том, что a а также b один и тот же объект с a is b возврате True (то же самое для id(a) == id(b)). Поэтому, если вы меняете индекс, вы меняете индекс обоих a а также b, поскольку они связаны между собой. Для решения этой проблемы вы можете сделать (источник)

>> a, b = ([0]*5 for i in range(2))
>> print b
[0, 0, 0, 0, 0]
>> a[0] = 1
>> print b
[0, 0, 0, 0, 0]

Затем это можно использовать как вариант верхнего ответа, который имеет "желаемые" интуитивные результаты

>> a, b, c, d, e, g, h, i = (True for i in range(9))
>> f = (False for i in range(1)) #to be pedantic

В вашем случае я бы использовал YAML .

Это элегантный и профессиональный стандарт для работы с несколькими параметрами. Значения загружаются из отдельного файла. Вы можете увидеть некоторую информацию по этой ссылке:

https://keleshev.com/yaml-quick-introduction

Но его проще погуглить, так как это стандарт, о нем сотни информации, вы можете найти то, что лучше всего подходит для вашего понимания.;)

С наилучшими пожеланиями.

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