Более элегантный способ объявления нескольких переменных одновременно
Чтобы объявить несколько переменных одновременно, я бы сделал:
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
Или чего мне не хватает?
Ответы
Ответ 1
Как и другие, маловероятно, что использование 10 разных локальных переменных с булевыми значениями - лучший способ написать вашу рутину (особенно, если у них действительно есть однобуквенные имена:)
В зависимости от того, что вы делаете, может быть смысл использовать словарь. Например, если вы хотите установить Boolean заданные значения для набора однобуквенных флагов, вы можете сделать это:
>>> 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
. Приведенный выше код выдувает результат выражения, следующего за **
, в набор аргументов ключевого слова, которые передаются вызываемой функции. Это, безусловно, надежный способ создания словарей, и люди, похоже, по крайней мере принимают эту идиому, но я подозреваю, что некоторые из них могут считать Unpythonic. </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
работает иначе, чем выше, потому что он кормит iterator, а не словарь как свой аргумент.
Рисунок на комментарии @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 iterable, что означает, что их можно перемещать по значению по значению. В случае строки значения представляют собой отдельные символы в строке. Поэтому, когда они интерпретируются как итеративные, так как в этом случае, когда они используются в цикле for, ['a', 'b', 'c']
и 'abc'
фактически эквивалентны. Другим примером может быть, когда они передаются функции, которая принимает итерируемый, например tuple
.
Я лично не сделал бы этого, потому что он не читал интуитивно: когда я вижу строку, я ожидаю, что она будет использоваться как одно значение, а не как список. Поэтому я смотрю на первую строчку и думаю: "Ладно, там есть флаг True и флаг False". Поэтому, хотя это возможно, я не думаю, что это путь. С другой стороны, это может помочь более четко объяснить концепции итераторов и итераторов.
Определение функции invert_dict
, так что она фактически возвращает словарь, тоже неплохая идея; Я в основном просто не делал этого, потому что это не очень помогает объяснить, как работает рутина.
По-видимому, Python 2.7 имеет понимание словаря, что позволило бы предельно сжатым образом реализовать эту функцию. Это остается как упражнение для читателя, так как у меня нет установленного Python 2.7:)
Вы также можете комбинировать некоторые функции из универсального itertools модуля. Как говорится, Там больше, чем один способ сделать это. Подождите, люди Python этого не говорят. В любом случае, это правда. Я бы предположил, что Гвидо дал нам понимание в словаре, чтобы One Очевидный способ сделать это.
Ответ 2
a, b, c, d, e, g, h, i, j = (True,)*9
f = False
Ответ 3
Используйте список/словарь или определите свой собственный класс, чтобы инкапсулировать материал, который вы определяете, но если вам нужны все эти переменные, которые вы можете сделать:
a = b = c = d = e = g = h = i = j = True
f = False
Ответ 4
Это разработка на @Jeff M и мои комментарии.
Когда вы это сделаете:
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 = _
Он даст вам тот же результат, что и первая строка (включая одно и то же исключение, если вы добавите значения или переменные в одну часть, но забудьте обновить другую).
Однако в этом конкретном случае yan answer является, пожалуй, лучшим.
Если у вас есть список значений, их можно распаковать. Вам просто нужно сначала преобразовать его в кортеж. Например, следующее присваивает значение от 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
Когда люди предлагают "использовать список или кортеж или другую структуру данных", то, что они говорят, это то, что, когда у вас много разных значений, о которых вы беспокоитесь, называя их все отдельно, поскольку локальные переменные могут не быть лучший способ сделать что-то.
Вместо этого вы можете собрать их вместе в более крупную структуру данных, которая может быть сохранена в одной локальной переменной.
intuited показал, как вы можете использовать словарь для этого, и Крис Лутц показал, как использовать кортеж для временного хранения перед распаковкой в отдельные переменные, но еще один вариант, который следует учитывать, - это использовать 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" и буквы алфавита, конечно.
Ответ 6
Какая проблема, на самом деле?
Если вам действительно нужно или нужно 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 идентификаторов? И если они меняются, зачем сначала определять идентификаторы?, они будут созданы, когда это необходимо, если не определены ранее
Ваш вопрос кажется мне странным
Ответ 7
Похоже, вы приближаетесь к своей проблеме неправильно.
Перепишите свой код, чтобы использовать кортеж, или напишите класс для хранения всех данных.
Ответ 8
Мне нравится главный проголосовавший ответ; однако он имеет проблемы со списком, как показано.
>> 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
Ответ 9
ну, вы могли бы сделать
а = Ь = с = d = False
Ответ 10
Как и в JavaScript, вы также можете использовать несколько операторов в одной строке в Python a = 1; b = "Hello World"; c += 3