In my exercise, i have to use **kwargs to print the arguments entered in my function in alphabetical order.
Here is what I have for now:
def afficher(**kwargs):
if kwargs is not None:
for i in kwargs:
print (i)
afficher(helpme=7,plz=10)
returns:
plz
helpme
My concern is:
I'd like them returned in alphabetical order
I'd like them returned as:
helpme = 7
plz = 10
Thanks in advance !
Plain dictionaries are not sorted, as their keys are hashed and end up stored accordingly.
In your case you can scan the sorted keys of the kwargs dictionary
for i in sorted(kwargs):
So the code becomes
def afficher(**kwargs):
for i in sorted(kwargs):
print ('{}={}'.format(i,kwargs[i]))
afficher(helpme=7,plz=10)
which always produces
helpme=7
plz=10
Note: as you can see, I have removed the if, that I presume you inserted to check if any keyword arguments were passed to the function.
In such case kwargs will be an empty dictionary {}, not None, so there is no need to prevent the iteration.
When you have **something as a function argument, inside the function body something will be a dict that maps the keywords to their values.
To iterate over the sorted keys you would do:
def afficher(**kwargs):
for k,v in sorted(kwargs.items()):
print '{}={}'.format(k,v)
Note that when no keyword arguments are passed, kwargs={} and kwards.items()=[]. The for loop will exit immediately, so there is no reason to check it. Also, you wouldn't check it with if kwargs is None since {} is not None. You would check it with {}.
Related
I am reading the book Python Crash Course, and in the following I have a confusion why a dictionary is defined as user_info={k=v,k1=v1,...} and not user_info={k:v,k1:v1,...}. Here is the code from the book (slightly altered for name of person):
def build_profile(first, last, **user_info):
profile = {}
profile['first_name'] = first.title()
profile['last_name'] = last.title()
for key, value in user_info.items():
profile[key] = value
return profile
build_profile('freddie','mercury',location='uk',field='rock')
In the book, he says the following: The
double asterisks before the parameter **user_info cause Python to create
an empty dictionary called user_info and pack whatever name-value pairs it
receives into this dictionary.
Now, when I type in the values for the dictionary the ordinary way (ie key:value),
python gives me an error.
Could somebody explain why is this so?
Dictionaries are objects with key-value pairs. There's a special literal for creating dicts:
{'key': 'value'}
You could also use the dict constructor to do the same thing:
dict(key='value')
What's shown here are named function arguments. Taking a step back…
These are function definitions:
def foo(bar, baz): ...
This function defines two parameters. You can give these parameters default values:
def foo(bar, baz=42): ...
The parameter baz has the default value 42. When calling the function, you can supply the arguments positionally:
foo('a', 14)
Or, and here we go, you can supply the arguments by name:
foo(bar='a', baz=14)
foo(baz=14, bar='a') # exactly the same as above
This is in fact what the dict constructor does, it's a function call with named arguments.
Now, you can also accept arbitrary named arguments in your function:
def foo(**kwargs): ...
Any named argument you pass in will be accepted and land in the kwargs parameter, which happens to be a dict (because that's the natural data structure for a key-value mapping).
So, you're not constructing a dict with = there. You're calling a function that accepts arbitrary named arguments via **, and those end up being a dict. Function parameters or arguments always involve the = syntax. The only time : is used is in dict literals.
A good way to think of this might be that you are allowing the user to input in as many values as they would want. Say you have a function like this:
def Function(*arguments):
...
Here, the asterisks before the arguments means that the user is allowed to supply as many values as they want into the parameter. It it thus creating a list of values. Similarly, adding two asterisks before also means that the user is allowed to type in as many values as they want, but this time, the values will be organized as a dictionary.
so I have a function:
def Function(**arguments):
print(arguments)
then, if I call it like so:
Function("Key0", 0, "Key1", 1, ...)
The function takes the even values (value 0, 2, ...) as the keys and the odd values (1, 3, ...) as the values. So this code would print:
{"Key0": 0, "Key1": 1, ...}
Now note, this is not exactly how it functions at the lower lever, but it is a good way to think about it.
I have a method to validate input:
def validate_user_input(*args):
for item in args:
if not re.match('^[a-zA-Z0-9_-]+$', item):
And I'm calling it like this:
validate_user_input(var1, var2, ..., var7)
But those are generated from user input, and some of those can be missing. What would be the proper way to do that, without creating tons of if statements?
Variables are assigned from a json input like so, and json input might not have some of the needed properties:
var1 = request.json.get('var1')
I assume they are <class 'NoneType'>
Here's the error: TypeError: expected string or buffer
If your request.json object is a dict or dict-like you can just pass a default value as second argument to get
If I understand correctly you are generating var_ variables by request.json.get('var_') which will either return a string which you want to validate or None if the field was missing.
If this is the case then you can just add a special case to validate_user_input for a None value:
def validate_user_input(*args):
for item in args:
if item is None:
continue #this is acceptable, don't do anything with it
elif not re.match('^[a-zA-Z0-9_-]+$', item):
...
Or it may make more sense to store all of the values you are interested in in a dictionary:
wanted_keys = {'var1','var2','var3'}
## set intersection works in python3
present_keys = wanted_keys & response.json.keys()
## or for python 2 use a basic list comp
#present_keys = [key for key in response.json.keys() if key in wanted_keys]
actual_data = {key: response.json[key] for key in present_keys}
Then you would pass actual_data.values() as the argument list to validate_user_input.
If it really is possible that some var-variables are undefined when you call validate_user_input, why not just initialize them all (e.g. to the empty string '' so that your regex fails) before actually defining them?
In a few __init__ of different classes I have to use several times the construct
try:
self.member_name = kwargs['member_name']
except:
self.member_name = default_value
or as suggested by Moses Koledoye
self.member_name = kwargs.get('member_name', default_value)
I would like to have a method that inputs, say, the string 'member_name' and default_value and that the corresponding initialization gets produced. For example, if one inputs 'pi_approx' and 3.14 the resulting code is
self.pi_approx = kwargs.get('pi_approx', 3.14)
In this way I can replace a long sequence of these initializations by a loop along a list of all the required members and their default values.
This technique emulate a switch statement is not the same thing but kind of has a similar flavor.
I am not sure how to approach what I want to do.
Assuming that initializer(m_name, default_val) is the construction that gets replaced by
self.m_name = kwargs.get('m_name', default_val)
I would then used it by having a lists member_names = [m_name1, m_name2, m_name3] and default_values = [def_val1, def_val2, def_val3] and calling
for m_name, d_val in zip(member_names, default_values):
initializer(m_name, d_val)
This would replace long list of try's and also make the code a bit more readable.
If your try/except was meant to handle KeyError, then you can use the get method of the kwargs dict which allows you to supply a default value:
self.member_name = kwargs.get('member_name', default)
Which can be extended to your list of attribute names using setattr:
for m_name, d_val in zip(member_names, default_values):
setattr(self, m_name, kwargs.get(m_name, d_val))
class a(object):
data={'a':'aaa','b':'bbb','c':'ccc'}
def pop(self, key, *args):
return self.data.pop(key, *args)#what is this mean.
b=a()
print b.pop('a',{'b':'bbb'})
print b.data
self.data.pop(key, *args) ←------ why is there a second argument?
The pop method of dicts (like self.data, i.e. {'a':'aaa','b':'bbb','c':'ccc'}, here) takes two arguments -- see the docs
The second argument, default, is what pop returns if the first argument, key, is absent.
(If you call pop with just one argument, key, it raises an exception if that key's absent).
In your example, print b.pop('a',{'b':'bbb'}), this is irrelevant because 'a' is a key in b.data. But if you repeat that line...:
b=a()
print b.pop('a',{'b':'bbb'})
print b.pop('a',{'b':'bbb'})
print b.data
you'll see it makes a difference: the first pop removes the 'a' key, so in the second pop the default argument is actually returned (since 'a' is now absent from b.data).
So many questions here. I see at least two, maybe three:
What does pop(a,b) do?/Why are there a second argument?
What is *args being used for?
The first question is trivially answered in the Python Standard Library reference:
pop(key[, default])
If key is in the dictionary, remove it and return its value, else return default.
If default is not given and key is not in the dictionary, a KeyError is raised.
The second question is covered in the Python Language Reference:
If the form “*identifier” is present,
it is initialized to a tuple receiving
any excess positional parameters,
defaulting to the empty tuple. If the
form “**identifier” is present, it is
initialized to a new dictionary
receiving any excess keyword
arguments, defaulting to a new empty
dictionary.
In other words, the pop function takes at least two arguments. The first two get assigned the names self and key; and the rest are stuffed into a tuple called args.
What's happening on the next line when *args is passed along in the call to self.data.pop is the inverse of this - the tuple *args is expanded to of positional parameters which get passed along. This is explained in the Python Language Reference:
If the syntax *expression appears in
the function call, expression must
evaluate to a sequence. Elements from
this sequence are treated as if they
were additional positional arguments
In short, a.pop() wants to be flexible and accept any number of positional parameters, so that it can pass this unknown number of positional parameters on to self.data.pop().
This gives you flexibility; data happens to be a dict right now, and so self.data.pop() takes either one or two parameters; but if you changed data to be a type which took 19 parameters for a call to self.data.pop() you wouldn't have to change class a at all. You'd still have to change any code that called a.pop() to pass the required 19 parameters though.
def func(*args):
pass
When you define a function this way, *args will be array of arguments passed to the function. This allows your function to work without knowing ahead of time how many arguments are going to be passed to it.
You do this with keyword arguments too, using **kwargs:
def func2(**kwargs):
pass
See: Arbitrary argument lists
In your case, you've defined a class which is acting like a dictionary. The dict.pop method is defined as pop(key[, default]).
Your method doesn't use the default parameter. But, by defining your method with *args and passing *args to dict.pop(), you are allowing the caller to use the default parameter.
In other words, you should be able to use your class's pop method like dict.pop:
my_a = a()
value1 = my_a.pop('key1') # throw an exception if key1 isn't in the dict
value2 = my_a.pop('key2', None) # return None if key2 isn't in the dict
>>> def func(a, *args, **kwargs):
... print 'a %s, args %s, kwargs %s' % (a, args, kwargs)
...
>>> func('one', 'two', 'three', four='four', five='five')
a one, args ('two', 'three'), kwargs {'four': 'four', 'five': 'five'}
>>> def anotherfunct(beta, *args):
... print 'beta %s, args %s' % (beta, args)
...
>>> def func(a, *args, **kwargs):
... anotherfunct(a, *args)
...
>>> func('one', 'two', 'three', four='four', five='five')
beta one, args ('two', 'three')
>>>
I have python 3 code that is not working as expected:
def addFunc(x,y):
print (x+y)
def subABC(x,y,z):
print (x-y-z)
def doublePower(base,exp):
print(2*base**exp)
def RootFunc(inputDict):
for k,v in inputDict.items():
if v[0]==1:
d[k] = addFunc(*v[1:])
elif v[0] ==2:
d[k] = subABC(*v[1:])
elif v[0]==3:
d[k] = doublePower(*v[1:])
d={"s1_7":[1,5,2],"d1_6":[2,12,3,3],"e1_3200":[3,40,2],"s2_13":[1,6,7],"d2_30":[2,42,2,10]}
RootFunc(d)
#test to make sure key var assignment works
print(d)
I get:
{'d2_30': None, 's2_13': None, 's1_7': None, 'e1_3200': None, 'd1_6': None}
I expected:
{'d2_30': 30, 's2_13': 13, 's1_7': 7, 'e1_3200': 3200, 'd1_6': 6}
What's wrong?
Semi related: I know dictionaries are unordered but is there any reason why python picked this order? Does it run the keys through a randomizer?
print does not return a value. It returns None, so every time you call your functions, they're printing to standard output and returning None. Try changing all print statements to return like so:
def addFunc(x,y):
return x+y
This will give the value x+y back to whatever called the function.
Another problem with your code (unless you meant to do this) is that you define a dictionary d and then when you define your function, you are working on this dictionary d and not the dictionary that is 'input':
def RootFunc(inputDict):
for k,v in inputDict.items():
if v[0]==1:
d[k] = addFunc(*v[1:])
Are you planning to always change d and not the dictionary that you are iterating over, inputDict?
There may be other issues as well (accepting a variable number of arguments within your functions, for instance), but it's good to address one problem at a time.
Additional Notes on Functions:
Here's some sort-of pseudocode that attempts to convey how functions are often used:
def sample_function(some_data):
modified_data = []
for element in some_data:
do some processing
add processed crap to modified_data
return modified_data
Functions are considered 'black box', which means you structure them so that you can dump some data into them and they always do the same stuff and you can call them over and over again. They will either return values or yield values or update some value or attribute or something (the latter are called 'side effects'). For the moment, just pay attention to the return statement.
Another interesting thing is that functions have 'scope' which means that when I just defined it with a fake-name for the argument, I don't actually have to have a variable called "some_data". I can pass whatever I want to the function, but inside the function I can refer to the fake name and create other variables that really only matter within the context of the function.
Now, if we run my function above, it will go ahead and process the data:
sample_function(my_data_set)
But this is often kind of pointless because the function is supposed to return something and I didn't do anything with what it returned. What I should do is assign the value of the function and its arguments to some container so I can keep the processed information.
my_modified_data = sample_function(my_data_set)
This is a really common way to use functions and you'll probably see it again.
One Simple Way to Approach Your Problem:
Taking all this into consideration, here is one way to solve your problem that comes from a really common programming paradigm:
def RootFunc(inputDict):
temp_dict = {}
for k,v in inputDict.items():
if v[0]==1:
temp_dict[k] = addFunc(*v[1:])
elif v[0] ==2:
temp_dict[k] = subABC(*v[1:])
elif v[0]==3:
temp_dict[k] = doublePower(*v[1:])
return temp_dict
inputDict={"s1_7":[1,5,2],"d1_6":[2,12,3,3],"e1_3200":[3,40,2],"s2_13":[1,6,7],"d2_30"[2,42,2,10]}
final_dict = RootFunc(inputDict)
As erewok stated, you are using "print" and not "return" which may be the source of your error. And as far as the ordering is concerned, you already know that dictionaries are unordered, according to python doc at least, the ordering is not random, but rather implemented as hash tables.
Excerpt from the python doc: [...]A mapping object maps hashable values to arbitrary objects. Mappings are mutable objects. There is currently only one standard mapping type, the dictionary. [...]
Now key here is that the order of the element is not really random. I have often noticed that the order stays the same no matter how I construct a dictionary on some values... using lambda or just creating it outright, the order has always remained the same, so it can't be random, but it's definitely arbitrary.