Accessing specific values of a loop-created dictionary in a Python function - python

I am very new to Python and as an exercise I tried solving a basic finance exercise using code. My objective is to get a dictionary of spot rates and then a dictionary of discount rates calculated from those. I had thought to something like this:
discountrates={}
def discountrates(n):
spotrates={}
for x in range(1,n+1):
spotrates['s'+str(x)]=float(input('What is s'+str(x)+'? (not in percentage)'))
for y in range(1,n+1):
discountrates['d(0,'+str(y)+')']= 1/((1+float(spotrates['s'+str(y)]))**y)
for key, value in discountrates.items():
print (key, value)
Now the problem is that dictionary items cannot be accessed in a function. When I looked in your forum, I found solutions for unpacking the dictionary but that does not work in my case because I need to access a specific element of the dictionary, whose name cannot be fully specified (as I have seen in the Python manual) because it's part of a loop, in order for the formula to work without having to manually insert anything else. I used a dictionary in the first place to create names that were automatically generated but now I can't seem to get the information out of it.
What is the best solution?
Thanks in advance for the help. It's been driving me crazy.

It's because you called your global variable discountratesdict not discountrates (which is the name of your function).

I suggest you don"t name your dictionary like your function since the later will overwrite the former. In line 1 you say discountrates is an empty dict, in line 2 you say discountrates is a function object. You need to give them different names in python if they are on the same scope.
Furthermore why do you need discountrates to be global? would you like to keep old rates if n is smaller than a previous n? For performance I suggest you combine the two loops. Besides that there is no reason why the second loop can't read for x ... as well since zou don't use x anymore anyway. As a further hint, if you come to the conclusion, that a global is the only way it might help to add global discountratesdict, so it is easier to spot that a global is intended here, even though this is not necessary in your particular case since the []-operator needs an object and thus it already refers to your global.
Putting all this together yields:
discountratedict={}
def discountrates(n):
global discountratedict
spotrates={}
for x in range(1,n+1):
spotrates['s'+str(x)]=float(input('What is s'+str(x)+'? (not in percentage)'))
discountratedict['d(0,'+str(x)+')']= 1/((1+float(spotrates['s'+str(x)]))**x)
for key, value in discountratedict.items():
print (key, value)

Related

Access dictionary several times or store in temporary variable

Say, I need to use some value from Python dictionary several times in one piece of code. What are the best practices?
Access dictionary once, store value in some temporary variable and use this variable:
value = d['my_key']
do_some_work(value)
do_some_other_work(value)
and_again(value)
or access dictionary everytime a need this value:
do_some_work(d['my_key'])
do_some_other_work(d['my_key'])
and_again(d['my_key'])
The first approach leads to more readable functions when called, in particular when the key of the dictionary is long or not self explanatory. However, the reader will always have to check the origin of the variable if he's not willing to blindly trust the name of the variable. So why not calling the dictionary directly then?
Personally, I use both approaches according to the use case. If the key or dictionary names are long or not sufficiently self-explanatory, I create a temporary variable. Otherwise, I access the dictionary directly when calling the functions.
For a dict, the average time complexity of accessing an item is constant O(1), see
Python Time Complexity.
So, I wouldn't expect much difference in performance.

local variable value is not used - python

I am writing some python code (to work in conjuction with ArcGIS), and I have a simple statement that runs fine and does exactly what I am asking it to do, I just get a 'warning' from my scripting software (PyCharm) telling me:
Local variable 'row' value is not used
This inspection highlights local variables, parameters or local functions unused in scope.
I understand it is not used, because it is not needed. This is the only way (that I know of personally) to work out how many rows exist in a table.
Can someone tell me if there is a better (more correct) way of writing this??
cursor = arcpy.SearchCursor(my_table)
for row in cursor:
count += 1
print count
Cheers
By convention if you're looping and don't intend to use the value you store the iterator in a variable named _. This is still a normal variable that gets each value in turn, but is taken to mean "I don't plan to use this value." To use this convention you'd rewrite your code as:
cursor = arcpy.SearchCursor(my_table)
for _ in cursor:
count += 1
print count
See What is the purpose of the single underscore "_" variable in Python? to learn more about the single underscore variable.
But as Markus Meskanen pointed out there is a better way to solve this specific problem.

Alternatives to storing variables globally

I am starting out with Python now, working on the Learn Python The Hard Way, on exercise 36. I want to create a good game, and learn some more techniques before moving on with the next exercise. I haven't approached the subject of Classes and Object yet, yet I want to see if I can do something that would be a bit more complex than a standard first 'choose-your-own-adventure' game.
I want to collect four different keys in 'Ganon's Lair', and then use those four keys to open a door in the 'main-hall'. I already have quite some of it worked out (not elegantly), but I still need to figure out how to store keys without them getting erased. An unelegant way is to assign them as global variables, such as I do here.
def grass_room():
global key1
grass_instructions = """As you enter the lair of the grass room, you see
a spider hanging on the ceiling, with his
big eye focused on you. You could grab your 1.slingshot,
or perhaps 2.make a run for the green-coloured key under his
tail?"""
print grass_instructions
gohma_boss = raw_input("> ")
if gohma_boss == "1":
print "You shoot him in the eye, he falls down and dies. You grab the key, and return."
key1 = True
main_hall("not_empty")
else:
print die("You die.")
main_hall("not_empty")
Any suggestions for different ways to 'save' this key across functions, besides making them global?
If you want some variable or variables to be shared between functions, there are a few ways to do it:*
Pass each variable's value into every function as an argument, and return it from every function as part of a return tuple.
Wrap all of the values up in some structure, like a dict that you can look each thing up in by name, so you only have one value to pass and return.
Make the values attributes of an object, and turn the functions into methods of that object's type.
Use a closure, which I won't bother to explain because I'm sure you haven't learned about closures yet.
Use globals.
The Pythonic way to do this is definitely #3, but you haven't learned about classes yet. In that case, I'd just use #5, as you're already doing.
And when you learn about classes, coming back and modifying this script to use a class instead will be a great exercise.
* In fact, under the covers, options 3-5 are all pretty much syntactic sugar for option 2… but don't worry about that.
You could make your key datatype a list or a dict and pass the key list/dict into each key-changing function. Since lists and dicts are mutable, changes made to the key list/dict in one function will be seen in the calling scope and in any subsequent functions that key is passed to.

how recursion works in Python

I am trying to solve a interview question: how to convert a BST to a double linked list.
Below is my code. I am really confused about how python recursion works. Why after the convert2DoubleLst_recursive , the prev and head remain to be None, I have assigned a new value to these two variables, why after this method call, I cannot save the change. I remembered that python pass arguments by reference, but why here I cannot save the changes. Many thanks in advance.
def convert2_recursive(node):
prev,head=None,None
convert2DoubleLst_recursive(node,prev,head)
end=head.lChild
printList(head,end)
def convert2DoubleLst_recursive(node,prev,head):
if node:
convert2DoubleLst_recursive(node.lChild,prev,head)
node.lChild=prev
if prev:
prev.rChild=node
else:
head=node
nextNode=node.rChild
head.lChild=node
node.rChild=head
prev=node
convert2DoubleLst_recursive(nextNode,prev,head)
Naively put, because there is no pass-by-reference in Python. Recursion is not your problem.
It may become a little clearer, when you think "There are no variables in Python, only names and values".
When the statement convert2DoubleLst_recursive(node.lChild, prev, head) is executed, actually the function convert2DoubleLst_recursive is called with the values that node.lChild, prev and head point to at that time.
Then, within convert2DoubleLst_recursive, those values are given the (local) names node, etc. (which are different names from those before!).
Later you assign new values to those names, recurse (which is not actually relevant in your code) and essentially Python forgets the names and their values when exiting the function.
Basically, between line 8 and 10 prev does not change it's value (as you experienced), because the name used in the caller is never seen inside of the callee. The value assigned to that name is not changed in line 3 and it is not relevant what happens inside the callee.
If you want to pass values back to your caller, you have to return them.
Alternatively you could replace None by a guardian object that behaves like your node class and represents None.
Usually, though, there are better data structures you would use in Python than linked lists.
(Python lists for example are already linked lists internally and can be used instead.)
A much deeper analysis can be found here: https://stackoverflow.com/a/986145/110707 .

Referencing Python list elements without specifying indexes

How can I store values in a list without specifying index numbers?
For example
outcomeHornFive=5
someList = []
someList.append(outComeHornFive)
instead of doing this,
someList[0] # to reference horn five outcome
how can i do something like this? The reason is there are many items that I need to reference within the list and I just think it's really inconvenient to keep track of which index is what.
someList.hornFive
You can use another data structure if you'd like to reference things by attribute access (or otherwise via a name).
You can put them in a dict, or create a class, or do something else. It depends what kind of other interaction you want to have with that object.
(P.S., we call those lists, not arrays).
Instead of using a list you can use a dictionary.
See data types in the python documentation.
A dictionary allows you to lookup a value using a key:
my_dict["HornFive"] = 20
You cannot and you shouldn't. If you could do that, how would you refer to the list itself? And you will need to refer to the list itself.
The reason is there are many items that i need to reference within the list and I just think it's really inconvenient to keep track of which index is what.
You'll need to do something of that ilk anyway, no matter how you organize your data. If you had separate variables, you'd need to know which variable stores what. If you had your way with this, you'd still need to know that a bare someList refers to "horn five" and not to, say, "horn six".
One advantage of lists and dicts is that you can factor out this knowledge and write generic code. A dictionary, or even a custom class (if there is a finite number of semantically distinct attributes, and you'd never have to use it as a collection), may help with the readability by giving it an actual name instead of a numeric index.
referenced from http://parand.com/say/index.php/2008/10/13/access-python-dictionary-keys-as-properties/
Say you want to access the values if your dictionary via the dot notation instead of the dictionary syntax. That is, you have:
d = {'name':'Joe', 'mood':'grumpy'}
And you want to get at “name” and “mood” via
d.name
d.mood
instead of the usual
d['name']
d['mood']
Why would you want to do this? Maybe you’re fond of the Javascript Way. Or you find it more aesthetic. In my case I need to have the same piece of code deal with items that are either instances of Django models or plain dictionaries, so I need to provide a uniform way of getting at the attributes.
Turns out it’s pretty simple:
class DictObj(object):
def __init__(self, d):
self.d = d
def __getattr__(self, m):
return self.d.get(m, None)
d = DictObj(d)
d.name
# prints Joe
d.mood
# prints grumpy

Categories

Resources