This question already has answers here:
Destructuring-bind dictionary contents
(17 answers)
Closed 4 years ago.
I'm trying to write a function spread in Python 3.6 (I cannot use any newer release), and, so far, I've got something that looks like this:
d = {"a": 1, "b": 2, "c": 3}
a, b, c = spread(d, ['a', 'b', 'c'])
a
>> 1
b
>> 2
c
>> 3
The problem is: there is kind of duplication since the position of the left side must match the keys list on the function's 2nd argument for it to make sense. So, change the order of the keys list, and variable a will hold a different value than d['a']. I need to keep consistency by either
a, b, c = spread(d) # how?
Or spread(d, ???). I'm not considering initializing a, b, c with None and then pass them as a list.
Any thoughts or leads on how to approach this? Is it even possible?
Thanks!
No this isn't really possible. You can't have
a, b, c = spread(d)
and
a, c, b = spread(d)
give the same value to b. This is because the right side of an assignment statement is evaluated first. So spread executes and returns its values before your code knows which order you put them in on the left.
Some googling leads be to believe that by "spread-like syntax for dicts", you're looking for the **dict syntax. See What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
not very pretty, but you can sort of get there doing:
def f1(a, b, c, **_):
print(a)
print(b)
print(c)
d = {"a": 1, "b": 2, "c": 3}
f1(**d)
very different semantics, but posted in the hope it'll inspire something!
as per #phhu's comment, ** in the definition of f1 is a catch-all keyword argument specifier telling Python that all unmatched parameters should be put into a dictionary of the given name, _ in my case. calling as f1(**d) says to unpack the specified dictionary into the function's parameters.
hence if it was used like:
e = {"a": 1, "b": 2, "c": 3, "extra": 42}
f1(**e)
then inside f1 the _ variable would be set to {"extra": 42}. I'm using _ because this identifier is used across a few languages to indicate a throwaway/placeholder variable name, i.e. something that is not expected to be used later.
globals().update(d) does what you ask, but...
It works in the global scope only, locals() is not guaranteed to return a writable dictionary.
It impairs debuggability of your code. If one of the variables set this way ends up with an unexpected value, no search will show you that this is the place the variable is being set.
You could assign the variables to the result of a values() call:
>>> d = {"a": 1, "b": 2, "c": 3}
>>> a,b,c = d.values()
>>> a
1
>>> b
2
>>> c
3
I don't recommend doing this for versions of Python where dict ordering is not guaranteed, but luckily this should work in 3.6 and above.
Related
I have function with default values. Based on a condition I would like to either use a specified value or the default value. Example:
def f(a=1,b=2,c=3):
print(a, b, c)
I would like to have the following logic:
if condition:
f(a=4, b=5, c=6)
else:
f(a=4, c=6)
But I would like to understand if it's possible to do this using a ternary operator e.g. something like:
f(a=4, b=5 if condition else <default value>, c=6)
Is there a way?
Edit for clarification:
I would like to tell the function to take the default value in case the condition is false without providing the default value in the if-else statement. So in the example above the output should be 4 5 6 if true and 4 2 6 if false.
The only way I can think of would be:
func("arg", "arg2", *(("default",) if condition == True else ()))
As far as I know it's not possible as one liner. Named arguments are simply dict and default value is used when key is not present in dict.
So you can also write it as
if condition:
f(**{"a": 4, "b": 5, "c": 6})
else:
f(**{"a": 4, "c": 6})
kwargs approach is commonly used to add dynamic arguments
kwargs = {"a": 4, "c": 6}
if condition:
kwargs["b"] = 5
f(**kwargs)
But I am afraid there is no single expression which put conditionally key into dict.
This question already has answers here:
How do I call a function twice or more times consecutively?
(9 answers)
Closed 3 years ago.
My aim is to have many inputs from a user stored in a disordered manner. So, I decided to use a set. The code I have so far is:
a = input()
b = input()
c = input()
d = input()
all = a, b, c, d
print(set(all))
However, I do not want to repeat input() several times like above. Is there a way to achieve this?
If all you want is a set you do not need a, b, c, d.
all = set() #or all = {*(),}
for _ in range(4):
all.add(input())
print(all)
Or,
all = {input() for _ in range(4)}
This is considering you take the inputs in new line. Otherwise, if the input are comma-separated for example:
all = set(input().split(','))
print(all)
or
all = {*input().split(',')}
print(all)
In case you need both a, b, c, d and all the inputs, you could do:
>>> all = a, b, c, d = {*input().split(',')}
# example
>>> all = a, b, c, d = {1, 2, 3, 4}
>>> all
{1, 2, 3, 4}
>>> a
1
>>> b
2
As pointed out by #Tomerikoo all(iterable) is a built-in function avoid naming your variables same as python builints or keywords.
Another point, if in case you have already done so, in order to get the default behavior of all, you could do:
>>> import builtins
>>> all = builtins.all
# Or, more conveniently, as pointed out by #Martijn Pieters
>>> del all
* is used for iterable unpacking
_ is used for don't care or throwaway or anonymous variable,
as we do not need the variable in the loop. More on this
here.
{*()} is just a fancy way of creating empty sets as python does not have empty set literals. It is recommended to use set()
You could put your calls to input() in a comprehension:
set(input() for i in range(4))
You could use a for loop:
all = set()
for _ in range(4):
all.add(int(input())
print(all)
Don't forget that input gives you a string, so you should convert it to int or any type if needed excplicitly.
"_" in the for loop means that this variable is not important. But you can put whatever name you like.
Can anyone explain the difference when unpacking the dictionary using single or double asterisk? You can mention their difference when used in function parameters, only if it is relevant here, which I don't think so.
However, there may be some relevance, because they share the same asterisk syntax.
def foo(a,b)
return a+b
tmp = {1:2,3:4}
foo(*tmp) #you get 4
foo(**tmp) #typeError: keyword should be string. Why it bothers to check the type of keyword?
Besides, why the key of dictionary is not allowed to be non-string when passed as function arguments in THIS situation? Are there any exceptions? Why they design Python in this way, is it because the compiler can't deduce the types in here or something?
When dictionaries are iterated as lists the iteration takes the keys of it, for example
for key in tmp:
print(key)
is the same as
for key in tmp.keys():
print(key)
in this case, unpacking as *tmp is equivalent to *tmp.keys(), ignoring the values. If you want to use the values you can use *tmp.values().
Double asterisk is used for when you define a function with keyword parameters such as
def foo(a, b):
or
def foo(**kwargs):
here you can store the parameters in a dictionary and pass it as **tmp. In the first case keys must be strings with the names of the parameter defined in the function firm. And in the second case you can work with kwargs as a dictionary inside the function.
def foo(a,b)
return a+b
tmp = {1:2,3:4}
foo(*tmp) #you get 4
foo(**tmp)
In this case:
foo(*tmp) mean foo(1, 3)
foo(**tmp) mean foo(1=2, 3=4), which will raise an error since 1 can't be an argument. Arg must be strings and (thanks # Alexander Reynolds for pointing this out) must start with underscore or alphabetical character. An argument must be a valid Python identifier. This mean you can't even do something like this:
def foo(1=2, 3=4):
<your code>
or
def foo('1'=2, '3'=4):
<your code>
See python_basic_syntax for more details.
It is a Extended Iterable Unpacking.
>>> def add(a=0, b=0):
... return a + b
...
>>> d = {'a': 2, 'b': 3}
>>> add(**d)#corresponding to add(a=2,b=3)
5
For single *,
def add(a=0, b=0):
... return a + b
...
>>> d = {'a': 2, 'b': 3}
>>> add(*d)#corresponding to add(a='a',b='b')
ab
Learn more here.
I think the ** double asterisk in function parameter and unpacking dictionary means intuitively in this way:
#suppose you have this function
def foo(a,**b):
print(a)
for x in b:
print(x,"...",b[x])
#suppose you call this function in the following form
foo(whatever,m=1,n=2)
#the m=1 syntax actually means assign parameter by name, like foo(a = whatever, m = 1, n = 2)
#so you can also do foo(whatever,**{"m":1,"n":2})
#the reason for this syntax is you actually do
**b is m=1,n=2 #something like pattern matching mechanism
so b is {"m":1,"n":2}, note "m" and "n" are now in string form
#the function is actually this:
def foo(a,**b): # b = {"m":1,"n":2}
print(a)
for x in b: #for x in b.keys(), thanks to #vlizana answer
print(x,"...",b[x])
All the syntax make sense now. And it is the same for single asterisk. It is only worth noting that if you use single asterisk to unpack dictionary, you are actually trying to unpack it in a list way, and only key of dictionary are unpacked.
[https://docs.python.org/3/reference/expressions.html#calls]
A consequence of this is that although the *expression syntax may appear after explicit keyword arguments, it is processed before the keyword arguments (and any **expression arguments – see below). So:
def f(a, b):
print(a, b)
f(b=1, *(2,))
f(a=1, *(2,))
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#TypeError: f() got multiple values for keyword argument 'a'
f(1, *(2,))
I have found some Python behavior that confuses me.
>>> A = {1:1}
>>> B = A
>>> A[2] = 2
>>> A
{1: 1, 2: 2}
>>> B
{1: 1, 2: 2}
So far, everything is behaving as expected. A and B both reference the same, mutable, dictionary and altering one alters the other.
>>> A = {}
>>> A
{} # As expected
>>> B
{1: 1, 2: 2} # Why is this not an empty dict?
Why do A and B no longer reference the same object?
I have seen this question: Python empty dict not being passed by reference? and it verifies this behavior, but the answers explain how to fix the provided script not why this behavior occurs.
Here is a pictorial representation *:
A = {1: 1}
# A -> {1: 1}
B = A
# A -> {1: 1} <- B
A[2] = 2
# A -> {1: 1, 2: 2} <- B
A = {}
# {1: 1, 2: 2} <- B
# A -> {}
A = {} creates a completely new object and reassigns the identifier A to it, but does not affect B or the dictionary A previously referenced. You should read this article, it covers this sort of thing pretty well.
Note that, as an alternative, you can use the dict.clear method to empty the dictionary in-place:
>>> A = {1: 1}
>>> B = A
>>> A[2] = 2
>>> A.clear()
>>> B
{}
As A and B are still references to the same object, both now "see" the empty version.
* To a first approximation - similar referencing behaviour is going on within the dictionary too, but as the values are immutable it's less relevant.
Remember, variables in python act like labels. So, in the first example, you have a dictionary {1: 1, 2: 2}. That dictionary stays in memory. In the first example, A points to that dictionary, and you say B points to what A is pointing to (It won't point to the label A, but rather what the label A is pointing to).
In the second example, A and B are both pointing to this dictionary, but you point A to a new dictionary ({}). B stays pointing to the old dictionary in memory from the first example.
you are changing the dictionary A points to when you say A={} not destroying the old dictionary ... this sample should demonstrate for you
A={1:1}
print id(A)
B = A
print id(B)
B[2] = 5
print id(B)
print A
print id(A)
A = {}
print id(A)
It's about the difference between creating a new dictionary and changing an existing dictionary.
A[2] = 2
Is modifying the dictionary by adding a new key, the existing stuff is still part of that dictionary.
A = {}
This creates a totally new empty dictionary.
Think about it like this: A is the name of one object, then you make B a different name for that object. That's the first part, but then in the second code you make a new object and say ok that old object isn't called A anymore now this new object is called A.
B isn't pointing at A. B and A are both names for the same object, then names for two different objects.
I want to have a a reference that reads as "whatever variable of name 'x' is pointing to" with ints so that it behaves as:
>>> a = 1
>>> b = 2
>>> c = (a, b)
>>> c
(1, 2)
>>> a = 3
>>> c
(3, 2)
I know I could do something similar with lists by doing:
>>> a = [1]
>>> b = [2]
>>> c = (a, b)
>>> c
([1], [2])
>>> a[0] = 3
>>> c
([3], [2])
but this can be easily lost if one assigns a or b to something instead of their elements.
Is there a simple way to do this?
No, there isn't a direct way to do this in Python. The reason is that both scalar values (numbers) and tuples are immutable. Once you have established a binding from a name to an immutable value (such as the name c with the tuple (1, 2)), nothing you do except reassigning c can change the value it's bound to.
Note that in your second example, although the tuple is itself immutable, it contains references to mutable values. So it appears as though the tuple changes, but the identity of the tuple remains constant and only the mutable parts are changing.
Whatever possible solution you come up with the second last line will always destroy it:
a = 3
This will assign a completely new content to the variable. Unless a stands for a property of an object or something (or a key in a list, as you did in your own example), you won't be able to have a relation between the first and last a.
If you just need the current values to be placed in a tuple on the fly you could use a lambda. You'll have to call c, not just return it or use it, but that may be acceptable in your situation. Something like this:
>>> a = 1
>>> b = 2
>>> c = lambda: (a, b)
>>> c()
(1, 2)
>>> a = 3
>>> c()
(3, 2)
There isn't a way in Python, not only because numbers are immutable, but also because you don't have pointers. Wrapping the value in a list simulates that you have pointers, so that's the best you can do.
class ByRefValue(object):
def __init__(self, value):
self.value = value
Pass it around wherever you like, remembering that you need to access the value member rather than the entire object.
Alternatively, globals().get('a', 0) will return the value of a if it is in the global namespace (or zero if it isn't).
Finally:
import threading
tls = threading.local()
tls.a = 1
If you import tls into every module where you need it, you will access the same value for a on each thread. Depending on how your program is set up, this may be acceptable, ideal or useless.
You can try creating your own pointer class and your own pointer storage object to emulate the system's internal stack.