Python keyword output interpretation - python

I'm going through the Python 2.7 tutorial, and I was looking at the output of the following statement:
def cheeseshop(kind, *arguments, **keywords):
print "-- Do you have any", kind, "?"
print "-- I'm sorry, we're all out of", kind
for arg in arguments:
print arg
print "-" * 40
keys = sorted(keywords.keys())
for kw in keys:
print kw, ":", keywords[kw]
So, if I call the program as such:
cheeseshop("Cheddar", "No.", "Seriously?",
Shopkeeper="Michael Palin",
Client="John Cleese")
It outputs:
Do you have any Cheddar?
I'm sorry, we're all out of Cheddar
No.
Seriously?
--------------------------------------
Client: John Cleese
Shopkeeper: Michael Palin
This is correct.
If I change that print statement to print keywords, I get the following representation:
{'Shopkeeper': 'Ryan Lambert', 'Client': 'John Cleese'}
I'm a bit confused on how printing keywords[kw] just comes back with a name, and keywords does not.

In Python, you can pass optional keyword parameters by putting a ** in front of the function parameter's list.
So the keywords variable is actually a dictionary type. Thus, if you do:
print keywords
you get back (reformatted to make the mapping more obvious)
{
'Shopkeeper': 'Ryan Lambert',
'Client': 'John Cleese'
}
which is a dictionary. And if you do:
print keywords[kw]
you get back the value of the dictionary associated with the key kw. So if kw was 'Shopkeeper', then keywords[kw] becomes 'Ryan Lambert', and if kw was 'Client', then keywords[kw] becomes 'John Cleese'

keywords is stored as a dictionary. ( See this for more)
If you print the dictionary itself it is going to output the complete set of pairs it contains (key,value).
On your program:
keys are: 'Shopkeeper' and 'Client'
values are respectively: 'Ryan Lambert' and 'John Cleese'
One way to access the values is to "search" for it with its key: dict[key]
So when you wrote: "keywords[kw]" you are actually passing a key and python is going to give you the corresponding value.
You can think it as similar as accessing an array value:
a = ['a', 'b', 'c']
if you:
print a #output: ['a', 'b', 'c']
print a[0] # outputs: 'a'
just unlike arrays the data is not stored "neatly" together in memory, but using hashing
Hope it helped, Cheers

When you call the function with
cheeseshop("Cheddar", "No.", "Seriously?",
Shopkeeper="Michael Palin", Client="John Cleese")
the keywords parameter takes on the value {'Shopkeeper': 'Ryan Lambert', 'Client': 'John Cleese'}, i.e., it's a dictionary.
This is equivalent to (and much easier to read than) calling the function as
cheeseshop("Cheddar", *["No.", "Seriously?"],
**{"Shopkeeper":"Michael Palin", "Client":"John Cleese"})
That is, the values in the first function call are automatically wrapped inside the *arguments and **keywords parameters -- that's what those * and ** are for.
Now, when you do this:
keys = sorted(keywords.keys())
for kw in keys:
print kw, ":", keywords[kw]
keyword.keys() is ['Shopkeeper', 'Client'], i.e. the "keys" in the dictionary. Next, you sort those keys and for each key, you print the respective entry in the dictionary, e.g., "John Cleese" for "Client".

Related

Comparing items through a tuple in Python

I am given an assignment when I am supposed to define a function that returns the second element of a tuple if the first element of a tuple matches with the argument of a function.
Specifically, let's say that I have a list of student registration numbers that goes by:
particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))
And I have defined a function that is supposed to take in the argument of reg_num, such as "S12345", and return the name of the student in this case, "John". If the number does not match at all, I need to print "Not found" as a message. In essence, I understand that I need to sort through the larger tuple, and compare the first element [0] of each smaller tuple, then return the [1] entry of each smaller tuple. Here's what I have in mind:
def get_student_name(reg_num, particulars):
for i in records:
if reg_num == particulars[::1][0]:
return particulars[i][1]
else:
print("Not found")
I know I'm wrong, but I can't tell why. I'm not well acquainted with how to sort through a tuple. Can anyone offer some advice, especially in syntax? Thank you very much!
When you write for i in particulars, in each iteration i is an item of the collection and not an index. As such you cannot do particulars[i] (and there is no need - as you already have the item). In addition, remove the else statement so to not print for every item that doesn't match condition:
def get_student_name(reg_num, particulars):
for i in particulars:
if reg_num == i[0]:
return i[1]
print("Not found")
If you would want to iterate using indices you could do (but less nice):
for i in range(len(particulars)):
if reg_num == particulars[i][0]:
return particulars[i][1]
Another approach, provided to help learn new tricks for manipulating python data structures:
You can turn you tuple of tuples:
particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))
into a dictionary:
>>> pdict = dict(particulars)
>>> pdict
{'S12345': 'John', 'S23456': 'Max', 'S34567': 'Mary'}
You can look up the value by supplying the key:
>>> r = 'S23456'
>>> dict(pdict)[r]
'Max'
The function:
def get_student_name(reg, s_data):
try:
return dict(s_data)[reg]
except:
return "Not Found"
The use of try ... except will catch errors and just return Not Found in the case where the reg is not in the tuple in the first place. It will also catch of the supplied tuple is not a series of PAIRS, and thus cannot be converted the way you expect.
You can read more about exceptions: the basics and the docs to learn how to respond differently to different types of error.
for loops in python
Gilad Green already answered your question with a way to fix your code and a quick explanation on for loops.
Here are five loops that do more or less the same thing; I invite you to try them out.
particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))
for t in particulars:
print("{} {}".format(t[0], t[1]))
for i in range(len(particulars)):
print("{}: {} {}".format(i, particulars[i][0], particulars[i][1]))
for i, t in enumerate(particulars):
print("{}: {} {}".format(i, t[0], t[1]))
for reg_value, student_name in particulars:
print("{} {}".format(reg_value, student_name))
for i, (reg_value, student_name) in enumerate(particulars):
print("{}: {} {}".format(i, reg_value, student_name))
Using dictionaries instead of lists
Most importantly, I would like to add that using an unsorted list to store your student records is not the most efficient way.
If you sort the list and maintain it in sorted order, then you can use binary search to search for reg_num much faster than browsing the list one item at a time. Think of this: when you need to look up a word in a dictionary, do you read all words one by one, starting by "aah", "aback", "abaft", "abandon", etc.? No; first, you open the dictionary somewhere in the middle; you compare the words on that page with your word; then you open it again to another page; compare again; every time you do that, the number of candidate pages diminishes greatly, and so you can find your word among 300,000 other words in a very small time.
Instead of using a sorted list with binary search, you could use another data structure, for instance a binary search tree or a hash table.
But, wait! Python already does that very easily!
There is a data structure in python called a dictionary. See the documentation on dictionaries. This structure is perfectly adapted to most situations where you have keys associated to values. Here the key is the reg_number, and the value is the student name.
You can define a dictionary directly:
particulars = {'S12345': 'John', 'S23456': 'Max', 'S34567': 'Mary'}
Or you can convert your list of tuples to a dictionary:
particulars = (("S12345", "John"), ("S23456", "Max"), ("S34567", "Mary"))
particulars_as_dict = dict(particulars)
Then you can check if an reg_number is in the dictionary, with they keyword in; you can return the student name using square brackets or with the method get:
>>> particulars = {'S12345': 'John', 'S23456': 'Max', 'S34567': 'Mary'}
>>> 'S23456' in particulars
True
>>> 'S98765' in particulars
False
>>>
>>> particulars['S23456']
'Max'
>>> particulars.get('S23456')
'Max'
>>> particulars.get('S23456', 'not found')
'Max'
>>>
>>> particulars['S98765']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'S98765'
>>> particulars.get('S98765')
None
>>> particulars.get('S98765', 'not found')
'not found'

Update value of a nested key by reference in python 3

I have the following dictionary:
watch_list= {'videos': [{'systemId': 'qre', 'duration': 19}, {'systemId': 'abc', 'duration': 19}]}
now I wanted to check if the systemId already exists in the dictionary and if yes then update duration by systemId.
hence I am trying the following code:
def update_duration(watch_list,system_id,duration):
watch_history= next((a for a in watch_list if a['systemId'] == system_id), None)
if watch_history:
watch_history['duration'] =duration
return watch_history
but this gives me an error:
*** TypeError: string indices must be integers
I am new to python, I have read stack overflow other solutions but couldnt made it work. can anyone help me a little here, on how to update the value by the systemId?
I am using python 3 and flask
When you iterate through a dictionary with something like
my_dictionary = { 'hello' : ['I', 'am', 'a', 'dictionary'] }
for entry in my_dictionary:
print entry
The output will be hello, as it iterates through its keys by default. As it appears you're actually wanting to iterate through the dictionary's values, you'll want to call the values() function, or itervalues() in Python2.
Beyond that, you're then running into an issue with your generator comprehension's if statement. At that point, your a variable is holding a list of dictionaries---what used to be the value found by watch_list['videos'].

How to print the key of a dictionary but not it's value? [python]

I know this is probably extremely simple and I'm forgetting something, but I cannot remember how to print the key of a dictionary. The specific problem is I have a dictionary of parts of an animal that can attack, and the value is the verb used to attack, e.g: {'teeth': 'bites'}
It looks like this:
attack_part = random.choice(list(self.attacking_parts))
print('The', self.name, self.attacking_parts[attack_part], 'you with their', self.attacking_parts.keys() + '!')
But when I use this what happens is:
The bear scratches you with their scrathes!
attack_part variable in you code is the key of your dict. When you are doing the self.attacking_parts[attack_part], you are fetching the value corresponding to attack_part key in you self.attacking_parts dict. Whereas doing self.attacking_parts.keys() returns the list of all the keys present in the dict.
Hence, instead you should be using your print statement like:
print('The', self.name, self.attacking_parts[attack_part], 'you with their', attack_part + '!')

Python 2.7.8: Printing a sub-dictionary value?

I'm using ConfigParser which returns a dictionary of configuration data as such:
{'general': {'UserKey': 'thisisatestkey'}}
If I want to simply print the value of the UserKey key (in this case thisisatestkey), then I generally just do a print "Your key is: {0}".format(mydictvar.get('UserKey')).
If I just print out the raw dict to a string I get the above. If I use the print statement above I get result of None since there is no key in the root of the dict called UserKey. If I .get('general') I just get: {'UserKey': 'thisisatestkey'}
Obviously I could do a fore loop like so:
keydic = cp.get_config_data()
for m, k in keydic.iteritems():
for s, v in k.iteritems():
userkey = v
and then print userkey which works fine. But I want to know how I can just avoid having to do the entire for loop first and just print the darned value right inline? Thanks!
You can use
mydictvar['general']['UserKey']
Or, if keys might be missing
mydictvar.get('general', {}).get('UserKey')
mydictvar['general'] returns a dictionary object; you can then just apply [...] to that value to retrieve the next key.
This works in string formatting too:
>>> mydictvar = {'general': {'UserKey': 'thisisatestkey'}}
>>> print "Your key is: {0[general][UserKey]}".format(mydictvar)
Your key is: thisisatestkey
simply without loop:
>>> my_dict = {'general': {'UserKey': 'thisisatestkey'}}
>>> my_dict['general']['UserKey']
'thisisatestkey'

Dictionary Operations... Index / Iterate / Validate

I'd like to:
Check a key / value at position i
Check to see if key / value contains a string
delete / store in another variable either the key / value
The equivelant of this Java code:
//Some list...
ArrayList<String> example;
...
//Index into data structure
example.get(i);
//Check for some string...
if (example.get(i).contains("someText")){
somestuff;
}
//Store in some other variable
exam = example.get(i)
That's what I'm effectively trying to in Java, however I'd like to be able to do that with Python dictionarties however I'm not sure if this is possible, as I find the Python documentation rather hard to read.
Python dictionaries are implemented as hash tables, so there is no intrinsic ordering; therefore, "position i" is a totally nonsensical concept for a dict -- it's like asking for the dict entry that's most yellow, or that least resembles a llama... those concepts just don't apply to dict entries, and "position i" is just as totally inapplicable.
Where does that i come from, i.e., what's the real issue you're trying to solve? If your requirement is to iterate over the dictionary, you do that directly, without the crutch of a "numeric index". Or, if you do need to keep some specific order or other, then you don't use a dict, but rather some different data structure. If you explain exactly the purpose you're trying to address, I'm sure we can help you.
Direct translation (for an ArrayList<String>, you do not want a dictionary, you want a list):
example = ["foo", "bar", "baz"]
str = example[i]
if "someText" in str:
somestuff()
Get used to the for keyword, though, it's awesome in Python:
for str in example:
if "someText" in str:
someStuff()
Here's an example using dictionaries:
fruits = {
"apple": "red",
"orange": "orange",
"banana": "yellow",
"pear": "green"
}
for key in fruits:
if fruits[key] == "apple":
print "An apple is my favorite fruit, and it is", fruits[key]
else:
print "A", key, "is not my favorite fruit, and it is", fruits[key]
Iteration using for on a dictionary results in the keys, it's still up to you to index the item itself. As Alex pointed out, we're really off-base answering you with so little information, and it sounds like you're not well-rooted in data structures (dictionaries will probably yield a different order every time you iterate it).
Yo can do that to reproduce the same behavior that your example in Java.
# Some list
example = {} # or example = dict()
...
# Index into data estructure.
example[example.keys(i)]
# Check for some string...
if example[example.keys(i)] == 'someText' :
pass
# Store in some other variable...
exam = example[example.keys(i)]
del example[example.keys(i)]
# ...or
exam = example.pop(example.keys(i))
What's nice about Python is that you can try code interactively.
So we create a list which is like a Java List:
>>> mylist = ["python","java","ruby"]
>>> mylist
['python', 'java', 'ruby']
We can get an entry in the list via its index:
>>> mylist[0]
'python'
And use the find function to search for substrings:
>>> mylist[1].find("av")
1
>>> mylist[1].find("ub")
-1
It returns -1 if the string isn't found.
Copying an entry to a new variable is done just how you'd expect:
>>> newvalue = mylist[2]
>>> newvalue
'ruby'
Or we can create a dict which is like a Java Map, storing by key rather than index, but these work very similarly to lists in Python:
>>> mydict = { 'python':'Guido', 'java':'James', 'ruby':'Yukihiro' }
>>> mydict['java']
'James'
>>> othervalue = mydict['ruby']
>>> othervalue
'Yukihiro'
>>> mydict['python'].find('uid')
1
>>> mydict['python'].find('hiro')
-1
>>> mydict['ruby'].find('hiro')
4

Categories