How to assign values to an undefined amount of python variables?

Asked

Viewed 1,580 times

0

To assign values to multiple variables just follow this structure: a, b, c = 1, 2, 3; This I know, but what if for example I want to store several values that came from an input without knowing the amount of values? How do I do that?

2 answers

4


In general, if you don’t have exactly one value for each variable, that is, if the variables will have the same functionality and save elements of a sequence, then the best thing is to do this: save the values directly in a sequence - in general, a list.

So, let’s assume that you input, go with a split, and then having a sequence with no known size at the time of programming you want to assign this to a variable: you don’t have to do anything else, because the content is already a list - and the list is already the value returned by the split value.

I will follow with examples in the interactive prompt (the prompt has In[XX] instead of the traditional >>> why is it an ipython shell - the language used is exactly the same Python as the normal shell):

In [83]: entrada = input("Entre com valores separados por espaço: ").split()                             
Entre com valores separados por espaço: teste de entrada de várias palavras

In [84]: print(entrada)                                                                                  
['teste', 'de', 'entrada', 'de', 'várias', 'palavras']

So, as I said, if each input value is going to be used the same way, then the simplest is for me to keep the entrada. A for will process word for word from that list, much simpler than if every word were in a different variable - just do for palavra in entrada:.

Now, let’s assume that the entries are not all the same, and that the first and second words have a specific function, and, I don’t mind the others - in this case, yes, the Python assignment distribution allows you to use a * as prefix to indicate that in that variable goes a list with "everything left". Continuing the previous example:

In [91]: a, b, *c = entrada                                                                              

In [92]: print (f"a: {a}, b: {b}, c: {c}")                                                               
a: teste, b: de, c: ['entrada', 'de', 'várias', 'palavras']

Note that the * does not need to be used in the last variable - if the ones I want to separate are the first and last words, for example, and I want to keep all the others in a list, I can do:

In [93]: a, *b, c = entrada                                                                              

In [94]: print (f"a: {a}, b: {b}, c: {c}")                                                               
a: teste, b: ['de', 'entrada', 'de', 'várias'], c: palavras

If there is a number maximum of items in your entry, but it can optionally be smaller, there is a way: we create an iterator that fills the missing items with a value "blank" as None. There are several ways to do this - and we can use a list comprehension with a if ternary for our purposes. Important to understand here, is that the caveats to create dynamic variables already begin to apply, and the code begins to become complex, mainly for those who do not know the language well:

In [101]: a, b, c, d, e, f, g, h = [entrada[i] if i < len(entrada) else None for i in range(8)]          

In [102]: print(a, b, c, d, e, f, g, h)                                                                  
teste de entrada de várias palavras None None

Okay, but I want create a variable for each entry item without knowing the size

So far it is part of the normal Python syntax, only a more advanced aspect of it. Specifically what you want can be done differently - using the Python capabilities of introspection and dynamism, which allow the dynamic change of variables by the program itself that is running.

It’s not hard to do that - but for the reason I mentioned first in that answer, it doesn’t make sense - since if you’re going to create a variable dynamically, you won’t be able to write any code that use this variable by name later, since you do not know if it will exist. So it makes more sense to keep the sequence as a list, or even to put the sequence in a dictionary if it’s appropriate.

But for example, what you can use in this case is the fact that the call to function globals() Python return a dictionary with the global variables of the current module. If we use it as a common dictionary, the entries created in this dictionary are created "for real" as global variables. This is possible because when manipulating the dictionary, variable names are strings - and strings are data that we can manipulate with the various Python functions. It’s just that - I insist - it would have no use in a normal program.

The section below creates the variables, starting at a0 and incrementing the digit for each word in the sequence:

In [97]: for i, palavra in enumerate(entrada): 
    ...:     globals()['a' + str(i)] = palavra 
    ...:      
    ...:                                                                                                 

In [98]: print(a0, a1, a2, a3, a4)                                                                       
teste de entrada de várias

In [99]: print(a5)                                                                                       
palavras

In [100]: print(a6)                                                                                      
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-100-ff75f4805c17> in <module>
----> 1 print(a6)

NameError: name 'a6' is not defined

I let the error crash on purpose - if it was a program, and not an example in interactive mode, the code down from the creation of the variables would have no way of knowing which of these variables aN would have been created - the only way to use any would be to place its use within a try...except NameError: ... - which overrides any utility it could have. And even if it were simple to use these names in the program, realize that the program gets bigger and you have to type a lot more than you would need if each element were within a list. This example still allows to see at the same time the practical use for the entrada as a list: it is used directly in for. (in this case I used along with the function enumerate to create a numeric index for each word)

Note, however, that this solution does not work for local variables - only global. That’s why changes made to the dictionary returned by locals() do not change local variables: access to them is optimized internally, and does not pass through this dictionary - it is useful for reading only.

  • PS. the answer from @Niero would be good size - you should not do this in a program. I added this more answer to show syntax with * than to put the example "than not to do". But this example helps to better understand the language, so it is there.

  • All right, thank you. You helped a lot.

1

Directly is not possible. You can create a sophisticated algorithm that manages this. And then it depends on what you call a variable. Although it is possible to create variables at runtime, almost always this is bad and wrong code.

Unless you’re referring to variables each element of a list, which is something that is actually correct, then it becomes simpler, and probably correct. If you do not know how many elements need the list solves well because it has the same undefined amount, the execution will determine its size.

I would advise using the list as a array, so the elements are referenced by a sequential numerical index without intervals. But using a specific key in a dictionary can be a solution as well.

Of course in any case your code should handle this properly to identify how many values are and put in each variable, but the solution is the array. A form of array is always the solution to these things. It’s a indirect that solves the problem of nondeterminism.

  • What if I put a limit? For example I know that the input will have between 1 and 1000 elements. How can I do this? For example, an average calculator can be given two numbers, 3, 4, 10, 20, etc., to make the arithmetic mean between them. I want to know only the part that takes the input values and stores them in variables: num1, num2, num3...

  • 3

    No, I just said you can’t do that, it’s unfeasible, make the list and solve your problem.

  • Okay, now I get it. Thank you.

  • 1

    You can’t even calculate the average by creating a new variable for each data, why won’t you know how much data has been created - so you add up all the values, and divide by how much?? Already, if in a name list valores the average is simply: media = sum(valores) / len(valores)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.