I have a function which returns me two lists, symbols and data where the corresponding values are with the same index. For example symbols[i] gives the variable name and data[i] gives the actual value (int).
I would like to use these two lists to dynamically create a class with static values of the following format:
class a:
symbols[i] = data[i]
symbols[i+1] = data[i+1]
and so on so that I could later refer to the values like this:
a.symbols[i]
a.symbols[i+1]
where symbols[i] and symbols[i+1] should be replaced with the wanted variable name, like a.var1 or a.var2
How could this be achieved?
Edit: added detail below
So I have a main program lets say def main() which should read in a list.dat of this style:
dimension1;0.1
dimension2;0.03
dimension3;0.15
and separate the values to symbols and data lists.
So I don't know how many values there are exactly in these lists. I want to create a class dynamically to be able to refer to the values in the main program and to give the class to sub functions as an argument like def sub1(NewClass, argument1, argument2) etc. At the moment I am using a manually created simple python list (list.py) of the following format:
dimension1 = 0.1
dimension2 = 0.03
dimension3 = 0.15
and then using from list import * in the main program and also in the sub functions, which causes a SyntaxWarning telling me that import * only allowed at module level. So what I actually want is a smart and consistent way of handling the parameters list and transferring it to another functions
You can create a class dynamically with type. If I understand what you want to achieve here, your code will look like:
my_classes = []
for i in range(0, len(data), 2):
my_classes.append(
type('A%d' % i, (), {'var1': data[i], 'var2': data[i+1]})
)
I suspect what you actually want, re-reading the description, is to use type as follows:
NewClass = type('NewClass', (object,), dict(zip(symbols, data)))
Given a minimal example:
>>> symbols = 'foo bar baz'.split()
>>> data = range(3)
The outcome would be:
>>> NewClass.foo
0
>>> NewClass.bar
1
>>> NewClass.baz
2
Using zip allows you to easily create a dictionary from a list of keys and a list of associated values, which you can use as the __dict__ for your new class.
However, it's not clear why you want this to be a class, specifically.
Related
I wonder if there is a way to create variables automatically using strings, e.g. I have the following code (which does not work properly in Python):
def function(lst1, string1):
lst2 = 'processed_' + string1
lst2 = [] #here I created a string called lst2, but I want to use the string as the variable name.
for i in range(len(lst1)):
if abs(lst1[i]) >= 0.0001 :
lst2.append(i)
return lst2
function(list1, 'price') # list1 is a list which contains the index for column numbers, e.g., [1,2,3]
function(list1, 'promotion')
function(list1, 'calendar')
I would expect that with the function I would be able to create lists such as processed_price, processed_promotion, and processed_calendar, and the function will return these lists.
However the code above would not work as in Python. I wonder how should I write the code properly to achieve the same goal?
getattr(object, name, [default])
setattr(object, name, value)
To get or set values for a variable named via a string, use one of the above as appropriate. However, any time you use user input, it can be a source of injection attacks — the user could use a name that you did not expect them to use but the name is valid so the user gets access to data they should not have access to.
So it is usually advisable to use the user input as a key into a dictionary you define.
dictionary = {
'apple': 'my_value'
}
dictionary[user_input] = 'their_value'
This is probably a very basic question but I haven't been able to figure this out.
I'm currently using the following to append values to an empty list
shoes = {'groups':['running','walking']}
df_shoes_group_names = pd.DataFrame(shoes)
shoes_group_name=[]
for type in df_shoes_group_names['groups']:
shoes_group_name.append(type)
shoes_group_name
['running', 'walking']
I'm trying to accomplish the same using a for loop, however, when I execute the loop the list comes back as blank
shoes_group_name=[]
def list_builder(dataframe_name):
if 'shoes' in dataframe_name:
for type in df_shoes_group_names['groups']:
shoes_group_name.append(type)
list_builder(df_shoes_group_names)
shoes_group_name
[]
Reason for the function is that eventually I'll have multiple DF's with different product's so i'd like to just have if statements within the function to handle the creation of each list
so for example future examples could look like this:
df_shoes_group_names
df_boots_group_names
df_sandals_group_names
shoes_group_name=[]
boots_group_name=[]
sandals_group_name=[]
def list_builder(dataframe_name):
if 'shoes' in dataframe_name:
for type in df_shoes_group_names['groups']:
shoes_group_name.append(type)
elif 'boots' in dataframe_name:
for type in df_boots_group_names['groups']:
boots_group_name.append(type)
elif 'sandals' in dataframe_name:
for type in df_sandals_group_names['groups']:
sandals_group_name.append(type)
list_builder(df_shoes_group_names)
list_builder(df_boots_group_names)
list_builder(df_sandals_group_names)
Not sure if I'm approaching this the right way so any advice would be appreciated.
Best,
You should never call or search a variable name as if it were a string.
Instead, use a dictionary to store a variable number of variables.
Bad practice
# dataframes
df_shoes_group_names = pd.DataFrame(...)
df_boots_group_names = pd.DataFrame(...)
df_sandals_group_names = pd.DataFrame(...)
def foo(x):
if shoes in df_shoes_group_names: # <-- THIS WILL NOT WORK
# do something with x
Good practice
# dataframes
df_shoes_group_names = pd.DataFrame(...)
df_boots_group_names = pd.DataFrame(...)
df_sandals_group_names = pd.DataFrame(...)
dfs = {'shoes': df_shoes_group_names,
'boots': df_boots_group_names,
'sandals': df_sandals_group_names}
def foo(key):
if 'shoes' in key: # <-- THIS WILL WORK
# do something with dfs[key]
I have a dictionary in the format:
dictionary= {reference:annotation}
where the reference refers to a position, and the annotation contains information about that location.
I want to find reference positions that overlap, and update the annotation when that occurs. The annotation that I want to update is accessed by dictionary["reference"].qualifiers["ID"] (the annotation contains a second dictionary, where I can access the information I want).
When if I try to add another ID to the annotation using: d
dictionary[reference].qualifiers["ID"].extend(["new ID"])
or
dictionary[reference].qualifiers["ID"].append("new ID")
all reference annotations in my dictionary are being updated with that new ID.
However, if do this using basic list comprehension I get the desired result:
dictionary[reference].qualifiers["ID"] = dictionary[reference].qualifiers["ID"] + ["new ID"]
Only the annotation at that reference is updated. Can anyone explain why I am getting a different result using "append" or "extend"?
The first example you give as not working works for me:
class Annotation:
def __init__(self, initial_val):
self.qualifiers = {'ID': [initial_val]}
an1 = Annotation("foo")
an2 = Annotation("bar")
d = {'ref1' : an1, 'ref2': an2}
print d['ref1'].qualifiers['ID']
print d['ref2'].qualifiers['ID']
d['ref1'].qualifiers['ID'].extend(['new foo'])
print d['ref1'].qualifiers['ID']
print d['ref2'].qualifiers['ID']
results in:
~ mgregory$ python foo.py
['foo']
['bar']
['foo', 'new foo']
['bar']
~ mgregory$
I think you have something wrong with the way you are creating annotations - possibly mistaking a shallow copy for a deep one, or a similar data structure pitfall like that.
You need to post actual code that doesn't work.
As a side note, the code you described as a comprehension, is not. It's just use of the array operator +.
I have a function that takes given initial conditions for a set of variables and puts the result into another global variable. For example, let's say two of these variables is x and y. Note that x and y must be global variables (because it is too messy/inconvenient to be passing large amounts of references between many functions).
x = 1
y = 2
def myFunction():
global x,y,solution
print(x)
< some code that evaluates using a while loop >
solution = <the result from many iterations of the while loop>
I want to see how the result changes given a change in the initial condition of x and y (and other variables). For flexibility and scalability, I want to do something like this:
varSet = {'genericName0':x, 'genericName1':y} # Dict contains all variables that I wish to alter initial conditions for
R = list(range(10))
for r in R:
varSet['genericName0'] = r #This doesn't work the way I want...
myFunction()
Such that the 'print' line in 'myFunction' outputs the values 0,1,2,...,9 on successive calls.
So basically I'm asking how do you map a key to a value, where the value isn't a standard data type (like an int) but is instead a reference to another value? And having done that, how do you reference that value?
If it's not possible to do it the way I intend: What is the best way to change the value of any given variable by changing the name (of the variable that you wish to set) only?
I'm using Python 3.4, so would prefer a solution that works for Python 3.
EDIT: Fixed up minor syntax problems.
EDIT2: I think maybe a clearer way to ask my question is this:
Consider that you have two dictionaries, one which contains round objects and the other contains fruit. Members of one dictionary can also belong to the other (apples are fruit and round). Now consider that you have the key 'apple' in both dictionaries, and the value refers to the number of apples. When updating the number of apples in one set, you want this number to also transfer to the round objects dictionary, under the key 'apple' without manually updating the dictionary yourself. What's the most pythonic way to handle this?
Instead of making x and y global variables with a separate dictionary to refer to them, make the dictionary directly contain "x" and "y" as keys.
varSet = {'x': 1, 'y': 2}
Then, in your code, whenever you want to refer to these parameters, use varSet['x'] and varSet['y']. When you want to update them use varSet['x'] = newValue and so on. This way the dictionary will always be "up to date" and you don't need to store references to anything.
we are going to take an example of fruits as given in your 2nd edit:
def set_round_val(fruit_dict,round_dict):
fruit_set = set(fruit_dict)
round_set = set(round_dict)
common_set = fruit_set.intersection(round_set) # get common key
for key in common_set:
round_dict[key] = fruit_dict[key] # set modified value in round_dict
return round_dict
fruit_dict = {'apple':34,'orange':30,'mango':20}
round_dict = {'bamboo':10,'apple':34,'orange':20} # values can even be same as fruit_dict
for r in range(1,10):
fruit_set['apple'] = r
round_dict = set_round_val(fruit_dict,round_dict)
print round_dict
Hope this helps.
From what I've gathered from the responses from #BrenBarn and #ebarr, this is the best way to go about the problem (and directly answer EDIT2).
Create a class which encapsulates the common variable:
class Count:
__init__(self,value):
self.value = value
Create the instance of that class:
import Count
no_of_apples = Count.Count(1)
no_of_tennis_balls = Count.Count(5)
no_of_bananas = Count.Count(7)
Create dictionaries with the common variable in both of them:
round = {'tennis_ball':no_of_tennis_balls,'apple':no_of_apples}
fruit = {'banana':no_of_bananas,'apple':no_of_apples}
print(round['apple'].value) #prints 1
fruit['apple'].value = 2
print(round['apple'].value) #prints 2
Very beginner question but it is driving me mad. sample1, sample2 etc. are Pygame.mixer.sound objects.
sample_list = []
sample_list.append(sample1)
sample_list.append(sample2)
sample_list.append(sample3)
Is fine, but I want to do that using a for style loop, e.g.
for j in range(1, 3, 1):
sample_list.append(sample + j)
But that is trying to add a number to a sound object so isn't right. I can add the equivalent string by;
for j in range(1, 3, 1):
sample_list.append("sample" + str(j))
But that doesn't refer to the objects I want, just adds those strings.
I've tried must permutations of syntax I can think of but it is still alluding me!
Thanks.
Don't store the objects in variables in the first place; store them directly into a list, and then you will be able to index them by integer.
If the integer identifiers are sparse, use a dict indexed by integer.
I would recommend storing these in a dict to begin with. It is almost the same effect for you to reference by a name, but without the explicit object symbol for each:
samples = {
"sample1": Sample(),
"sample2": Sample()
}
samples['sample3'] = Sample()
This is the preferred approach when you have a dynamic number of objects you are creating and want to be able to grab them by a name later. You can store 100's of these in your dict without cluttering up your namespace.
And later if you are trying to apply this to your loop, you can reference the string names:
for i in xrange(1,4):
sample_list.append(samples["sample" + str(i)])
As a side note another way to get attributes by name when they live on some object is to use getattr. Assume you have this:
class Sampler(object):
pass
sampler = Sampler()
sampler.sample1 = Sample()
sampler.sample2 = Sample()
sampler.sample3 = Sample()
You can then reference by name via: getattr(sampler, "sample1")
Note: As mentioned in comments by #Marcin, if you don't care about having a string identifier to be able to look up your items, and they are just purely sequential by number, you can use this same approach but with a list. It depends on your needs.
It is possible you might want to end up doing something like:
samples = {
"bang1": Sample(),
"bang2": Sample(),
"bang3": Sample(),
"shot1": Sample(),
"shot2": Sample(),
...
}
... Which would then allow you to look up sequential subsets of those sounds.
You can dynamically load variables from the locals() mapping:
for j in range(1, 4):
sample_list.append(locals()["sample" + str(j)])
Generally, you want to avoid such tricks; find other ways to store your sample variables, in a mapping or a list for example.
Looks like the wrong approach, but nevertheless.
sample_list = [eval('sample' + str(i)) for i in range(1, 4)]