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

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

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 ]

207 голосов
/ 30 июля 2012
a, b, c, d, e, g, h, i, j = (True,)*9
f = False
48 голосов
/ 31 марта 2011

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

a = b = c = d = e = g = h = i = j = True
f = False
47 голосов
/ 31 марта 2011

Как и предполагали другие, маловероятно, что использование 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 не говорят этого.Ну, в любом случае это правда.Я бы предположил, что Гвидо дал нам толкование по словарю, чтобы для этого был Один очевидный способ .

9 голосов
/ 31 марта 2011

Это разработка @ Джеффа М и моих комментариев.

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

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))

EDIT: аккуратный трюк, чтобы назначить все из них как true, кроме элемента 5 (переменная f):

a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))
5 голосов
/ 31 марта 2011

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

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

Интуитивно

показал, как вы можете использовать для этого словарь, а Крис Латс показал, как использовать кортеж для временного хранения перед распаковкой в ​​отдельные переменные, но другой вариант, который следует рассмотреть, - это использовать 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» и буквы алфавита, конечно.

4 голосов
/ 31 марта 2011

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

Если вам действительно нужно или хотите 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 и связывание имени 'a' с этим объектом в текущем пространстве имен

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

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

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

2 голосов
/ 31 марта 2011

Звучит так, как будто вы подошли ко мне со своей проблемой.

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

0 голосов
/ 21 сентября 2016

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

  >> 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
...