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.
Related
class Websites
default = 'https://google.com'
spotify = 'https://spotify.com'
facebook = 'https://facebook.com'
twitter = 'https://twitter.com'
[...]
from websites import Websites
random_website = random.choice(list(vars(Websites).values()))
browser.get(random_website) # This line fails like 30-50% of the time
Note that I am purposefully not using a dictionary here, because I would like to use the random value to get the key.
Debugging, I've found that it will randomly get set to something like this:
random_website = {getset_descriptor} <attribute '__dict__' of 'Websites' objects>
I'm really not sure why it wouldn't be working, because I've tested all of the URLs multiple times.
Also note that this application uses threads -- there are multiple instances of this application (usually 4) and at any given time roughly 1-2 fail, in case that might matter. I'm still very new to Python and Selenium (and still not that experienced in coding, honestly). Please let me know if I can provide more information that might be helpful.
vars(Websites)
is a dictionary
has all kinds of objects in it, mostly inherited from object
If you print it, you will see all kinds of things like unbound methods and other normal object attributes. This happens because an object's __dict__ automatically gets some default elements assigned by the type metaclass. All these attributes should be dunders.
You therefore have two options:
Persist in your current course and filter for dunders:
items = [v for k, v in vars(Website).items() if not k.startswith('__')]
This is not the recommended approach.
Just use a normal dictionary that only contains what you want. You're calling values on it either way. If you don't really need the labels, just use a list.
You laid out your thought process pretty clearly in the comments to Mad Physicists's answer so you just need a mini-tutorial in Python.
A. How to store the data. As suggested above, a dictionary is probably the best way, with strings as keys and values. You probably want to deal with strings, not with variables.
websites = {'default':'https://www.google.com', 'stack':'https://stackoverflow.com'}
B. You can get a list of all the keys in the dictionary, or a list of (key, value) pairs called tuples. This means replacing vars(Websites).values() with websites.keys() or websites.items(). Then your code will give you a random key or item.
C. If you chose ```keys()``, then you can just print the random thing you got, and use that key to get the corresponding value from the dictionary.
random_key = random.choice(websites.keys())
print(random_key)
random_website = websites[random_key] # this is how you get values using keys
D. If you chose items(), then the tuple you got is basically an immutable list (you can't change or assign to either value). You can pull them out by specifying an index in the list. Python indices start at 0.
random_item = random.choice(websites.items())
print(random_item) # something like ('default', 'https://www.google.com')
random_key = random_item[0] # this is how you choose an item from a list or tuple
print(random_key)
random_website = random_item[1]
As the title asks. Python has a lot of special methods, __add__, __len__, __contains__ et c. Why is there no __max__ method that is called when doing max? Example code:
class A:
def __max__():
return 5
a = A()
max(a)
It seems like range() and other constructs could benefit from this. Am I missing some other effective way to do max?¨
Addendum 1:
As a trivial example, max(range(1000000000)) takes a long time to run.
I have no authoritative answer but I can offer my thoughts on the subject.
There are several built-in functions that have no corresponding special method. For example:
max
min
sum
all
any
One thing they have in common is that they are reduce-like: They iterate over an iterable and "reduce" it to one value. The point here is that these are more of a building block.
For example you often wrap the iterable in a generator (or another comprehension, or transformation like map or filter) before applying them:
sum(abs(val) for val in iterable) # sum of absolutes
any(val > 10 for val in iterable) # is one value over 10
max(person.age for person in iterable) # the oldest person
That means most of the time it wouldn't even call the __max__ of the iterable but try to access it on the generator (which isn't implemented and cannot be implemented).
So there is simply not much of a benefit if these were implemented. And in the few cases when it makes sense to implement them it would be more obvious if you create a custom method (or property) because it highlights that it's a "shortcut" or that it's different from the "normal result".
For example these functions (min, etc.) have O(n) run-time, so if you can do better (for example if you have a sorted list you could access the max in O(1)) it might make sense to document that explicitly.
Some operations are not basic operations. Take max as an example, it is actually an operation based on comparison. In other words, when you get a max value, you are actually getting a biggest value.
So in this case, why should we implement a specified max function but not override the behave of comparison?
Think in another direction, what does max really mean? For example, when we execute max(list), what are we doing?
I think we are actually checking list's elements, and the max operation is not related to list itself at all.
list is just a container which is unnecessary in max operation. It is list or set or something else, it doesn't matter. What really useful is the elements inside this container.
So if we define a __max__ action for list, we are actually doing another totally different operation. We are asking a container to give us advice about max value.
I think in this case, as it is a totally different operation, it should be a method of container instead of overriding built-in function's behave.
I'm trying to lookup a static value combined with a dynamic variable in a dictionary.
For example, a key in my_dict is: static_value1
My current code is:
dynamic_variable = 1
string = "static_value" + str(dynamic_variable)
my_dict[string]
But, with this code string is actually: 'static_value1'
I need it without the quotes to properly look up the dictionary key.
How could I do this? Hope it makes sense.
You can get the value of a "dynamic variable" by using the globals function:
my_dict[globals()[string]]
assuming that the variable is in global (module) scope. (If it isn't, use locals() instead).
This is faster and safer than using eval.
In general, you should try to avoid looking variables up dynamically in Python (the exception is when working with functions like __getattr__). Instead, consider using a dictionary to store mappings of names to keys. Dictionaries are more convenient than a collection of similarly-named variables in several ways.
It sounds like you are trying to change the string into a variable name before using it as a key. Perhaps this?
my_dict[eval(string)]
As nneonneo mentioned in his answer, using eval with a user supplied string is generally a bad idea, because it represents a security vulnerability, since you have just given your user the ability to execute arbitrary code on your system.
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)
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