web-dev-qa-db-fra.com

Manière plus élégante de déclarer plusieurs variables en même temps

Pour déclarer plusieurs variables en même temps, je ferais:

a, b = True, False

Mais si je devais déclarer beaucoup plus de variables, cela deviendrait de moins en moins élégant:

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

Y a-t-il un meilleur moyen/élégant/pratique de le faire?

Merci d'avance!

Modifier:

Cela doit être très basique, mais si j’utilisais une liste ou un tuple pour stocker les variables, comment devrais-je me rapprocher pour que je puisse vous aider, puisque:

aList = [a,b]

N'est pas valide, je devrais faire:

a, b = True, True

Ou qu'est-ce qui me manque?

109
Trufa

Comme d'autres l'ont suggéré, il est peu probable que l'utilisation de 10 variables locales différentes avec des valeurs booléennes soit le meilleur moyen d'écrire votre routine (surtout s'ils ont vraiment un nom d'une lettre :)

Selon ce que vous faites, il peut être judicieux d'utiliser un dictionnaire à la place. Par exemple, si vous souhaitez définir des valeurs prédéfinies booléennes pour un ensemble d'indicateurs à une lettre, vous pouvez procéder comme suit:

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

Si vous préférez, vous pouvez également le faire avec une seule instruction de tâche:

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

Le second paramètre de dict n'est pas entièrement conçu pour cela: il est réellement destiné à vous permettre de remplacer des éléments individuels du dictionnaire à l'aide d'arguments de mots clés tels que d=False. Le code ci-dessus décompose le résultat de l'expression suivante ** en un ensemble d'arguments mot-clé qui sont transmis à la fonction appelée. C'est certainement un moyen fiable de créer des dictionnaires, et les gens semblent au moins accepter cet idiome, mais je soupçonne que certains pourraient le considérer comme non rythmique. </disclaimer>


Une autre approche, qui est probablement la plus intuitive si vous utilisez fréquemment ce modèle, consiste à définir vos données comme une liste de valeurs d'indicateur (True, False) mappées sur des noms d'indicateur (chaînes à un seul caractère). Vous transformez ensuite cette définition de données en un dictionnaire inversé qui mappe les noms des indicateurs sur les valeurs des indicateurs. Cela peut être fait assez succinctement avec une compréhension de liste imbriquée, mais voici une implémentation très lisible:

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

La fonction invert_dict est une fonction generator . Il génère ou donne - ce qui signifie qu'il renvoie à plusieurs reprises les valeurs de - paires clé-valeur. Ces paires clé-valeur sont l'inverse du contenu des deux éléments du dictionnaire flags initial. Ils sont introduits dans le constructeur dict. Dans ce cas, le constructeur dict fonctionne différemment de ci-dessus car il est alimenté par un iterator plutôt que par un dictionnaire comme argument.


S'inspirant du commentaire de @Chris Lutz: si vous voulez vraiment utiliser ceci pour les valeurs à un caractère, vous pouvez

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

Cela fonctionne car les chaînes Python sont iterable , ce qui signifie qu'elles peuvent être déplacées d'une valeur à l'autre. Dans le cas d'une chaîne, les valeurs sont les caractères individuels de la chaîne. Ainsi, quand ils sont interprétés comme des iterables, comme dans ce cas où ils sont utilisés dans une boucle for, ['a', 'b', 'c'] et 'abc' sont effectivement équivalents. Un autre exemple serait quand ils sont passés à une fonction qui prend un itératif, comme Tuple .

Personnellement, je ne le ferais pas parce qu'il ne lit pas intuitivement: quand je vois une chaîne, je m'attends à ce qu'elle soit utilisée comme une valeur unique plutôt que comme une liste. Alors, je regarde la première ligne et je me dis "D'accord, donc il y a un drapeau True et un drapeau False". Donc, bien que ce soit une possibilité, je ne pense pas que ce soit la voie à suivre. En revanche, il peut être utile d’expliquer plus clairement les concepts d’itérables et d’itérateurs.


Définir la fonction invert_dict telle qu'elle renvoie réellement un dictionnaire n'est pas une mauvaise idée non plus; La plupart du temps, je ne l'ai tout simplement pas fait, car cela n'aide pas vraiment à expliquer le fonctionnement de la routine.


Apparemment, Python 2.7 comprend des dictionnaires, ce qui constituerait un moyen extrêmement concis d’implémenter cette fonction. Ceci est laissé au lecteur comme un exercice, vu que Python 2.7 n’est pas installé :)

Vous pouvez également combiner certaines fonctions du module toujours polyvalent itertools . Comme on dit, Il y a plus d’une façon de le faire . Attendez, les gens de Python ne disent pas ça. En tout cas, c’est vrai dans certains cas. Je suppose que Guido nous a donné une compréhension du dictionnaire pour qu'il y ait une manière évidente de le faire.

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

Utilisez une liste/dictionnaire ou définissez votre propre classe pour encapsuler les éléments que vous définissez, mais si vous avez besoin de toutes ces variables, vous pouvez le faire:

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

Ceci est une élaboration sur @ Jeff M et mes commentaires.

Quand tu fais ça:

a, b = c, d

Il fonctionne avec l’emballage et le déballage des tuples. Vous pouvez séparer les étapes d'emballage et de déballage:

_ = c, d
a, b = _

La première ligne crée un tuple appelé _ qui comporte deux éléments, le premier avec la valeur c et le second avec la valeur d. La deuxième ligne décompresse le _ Tuple dans les variables a et b. Cela décompose votre ligne énorme:

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

En deux lignes plus petites:

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

Il vous donnera exactement le même résultat que la première ligne (y compris la même exception si vous ajoutez des valeurs ou des variables à une partie mais oubliez de mettre à jour l’autre). Cependant, dans ce cas particulier, la réponse de yan est peut-être la meilleure.

Si vous avez une liste de valeurs, vous pouvez toujours les décompresser. Vous devez d'abord le convertir en tuple. Par exemple, les éléments suivants attribueront une valeur comprise entre 0 et 9 à chacun des a à j, respectivement:

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

EDIT: astuce pour les affecter tous à la valeur true sauf l'élément 5 (variable f):

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

Lorsque les gens suggèrent d'utiliser "une liste, un tuple ou une autre structure de données", ils prétendent que, lorsque vous vous préoccupez de nombreuses valeurs différentes, les nommer séparément en tant que variables locales peut ne pas être la meilleure solution. faire des choses.

Au lieu de cela, vous souhaiterez peut-être les rassembler dans une structure de données plus grande pouvant être stockée dans une seule variable locale.

intuited a montré comment utiliser un dictionnaire pour cela, et Chris Lutz a montré comment utiliser un Tuple pour le stockage temporaire avant la décompression dans des variables séparées, mais une autre option à envisager est d'utiliser collections.namedtuple pour regrouper les valeurs de manière plus permanente.

Donc, vous pourriez faire quelque chose comme:

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

Espérons que le code réel utilise des noms plus significatifs que "DataHolder" et les lettres de l'alphabet, bien sûr.

5
ncoghlan

Quel est le problème, en fait? 

Si vous avez vraiment besoin ou voulez 10 a , b , c , d , e , f , g , h , i , j , il n’y aura pas d’autre possibilité, à un moment ou à un autre, d’écrire a et d’écrire b et d’écrire c .....

Si les valeurs sont toutes différentes, vous serez obligé d'écrire par exemple

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]

c'est-à-dire définir les "variables" individuellement.

Ou, en utilisant un autre écrit, pas besoin d'utiliser _:

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]

ou

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

.

Si certains d’entre eux doivent avoir la même valeur, le problème est-il trop long à écrire? 

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

?

Ensuite, vous pouvez écrire:

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

.

Je ne comprends pas quel est exactement votre problème. Si vous voulez écrire un code, vous devez utiliser les caractères nécessaires à la rédaction des instructions et des définitions. Quoi d'autre ? 

Je me demande si votre question n'est pas le signe que vous comprenez mal quelque chose.

Quand on écrit a = 10, on ne crée pas de variable dans le sens de "morceau de mémoire dont la valeur peut changer". Cette instruction:

  • soit déclenche la création d'un objet de type integer et de valeur 10 et la liaison d'un nom 'a' avec cet objet dans l'espace de noms actuel 

  • ou réaffecter le nom 'a' dans l'espace de noms à l'objet 10 / (car 'a' a déjà été lié à un autre objet)

Je dis cela parce que je ne vois pas l'utilitaire permettant de définir 10 identificateurs a, b, c ... pointant vers False ou True. Si ces valeurs ne changent pas pendant l'exécution, pourquoi 10 identifiants? Et s’ils changent, pourquoi définir les identifiants d’abord? Ils seront créés en cas de besoin sinon définis au préalable.

Votre question me parait bizarre

4
eyquem

On dirait que vous abordez votre problème de la mauvaise façon pour moi.

Réécrivez votre code pour utiliser un tuple ou écrivez une classe pour stocker toutes les données.

2
richo

J'aime la réponse la plus votée; Cependant, il a des problèmes avec la liste comme indiqué.

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

Ceci est discuté en détail (ici) , mais le Gist est que a et b sont le même objet avec a is b retournant True (identique pour id(a) == id(b)). Par conséquent, si vous modifiez un index, vous modifiez les index de a et b, car ils sont liés. Pour résoudre cela, vous pouvez faire (source)

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

Ceci peut alors être utilisé comme une variante de la réponse principale, qui a les résultats intuitifs "souhaités"

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