Python: Refer to objects dynamically - python

Apologies if this is a silly question.
I have a list of potential dictionary keys here:
form_fields = ['sex',
'birth',
'location',
'politics']
I am currently manually adding values to these keys like so:
self.participant.vars["sex"] = [Constants.fields_dict["sex"][0], Constants.fields_dict["sex"][1], self.player.name]
self.participant.vars["birth"] = [Constants.fields_dict["birth"][0], Constants.fields_dict["birth"][1],self.player.age]
self.participant.vars["location"] = [Constants.fields_dict["location"][0], Constants.fields_dict["location"][1],self.player.politics]
I'd like to be able to do a use a for loop to do this all at once like so:
for i in form_fields:
self.participant.vars[i] = [Constants.fields_dict[i][0], Constants.fields_dict[i][1], self.player.`i`]
Obviously, however, I can't reference the object self.player.i like that. Is there a way to reference that object dynamically?

use getattr, For example, getattr(x, 'foobar') is equivalent to x.foobar.
for i in form_fields:
self.participant.vars[i] = [Constants.fields_dict[i][0], Constants.fields_dict[i][1], getattr(self.player, i)]

Related

Indexing a namedtuple nested in a dictionary

I'm looking to store a named tuple inside a dictionary. That parts easy. I don't know how to reference an individual bit in the namedtuple following that though.
I know that I could just use a dictionary and make life easier, but in the case where you have values you know you don't want to change, it'd be nice to use a namedtuple here (more so just out of interest - I realize strings are immutable as well).
from collections import namedtuple
Rec = namedtuple('name', ['First', 'Middle', 'Last'])
name = Rec('Charles', 'Edward', 'Bronson')
info = dict(identity=name)
print(name.First)
print(info['identity'])
print(type(info['identity']))
Results:
Charles
name(First='Charles', Middle='Edward', Last='Bronson')
<class '__main__.name'>
I expect to be able to access name.First through calling info['identity'][name.First] or something similar, but I can't seem to index inside the nested namedtuple.
as you probably know, namedtuples support multiple types of indexing
tuple[0] returns the first field (order is defined from the list of fields you gave during the namedtuple definition)
tuple.field_name returns the field named field_name
info['identity'] is the namedtuple you want to index, so let's go :)
print(info['identity'] == name)
# True
print(info['identity'].First)
# Charles
# or
print(info['identity'][0])
# Charles
# OR, splitting the operations
name_field = info['identity']
print(name_field.First)

Entire dictionary being updated when using "append" or "extend", despite accessing a single element in the dictionary

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 +.

Dynamically creating a class

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.

Python dictionary reference returning something strange

I have a list of python dictionaries called checkout_items, created by a simple function (further simplified here, for ease of reading):
def checkout_items(request):
items = get_cart_items(request)
co_items = [] #a list of dictionaries to be used by the cart
#iterate through the items and homogenize them into a standardized checkout_item format
for i in items:
co_item = {'number': num,
'name': i.name,
'sku': i.sku,
'quantity': i.quantity,
'price': i.price}
I reference this list elsewhere in a view (again, simplified):
checkout_items = cart.checkout_items(request)
attributes = {}
for i in checkout_items:
attributes['item_name_'+ str(i['number'])] = str(i['name'])
attributes['item_number_'+ str(i['number'])] = str(i['sku'])
attributes['quantity_'+ str(i['number'])] = str(i['quantity'])
But the name variable is being set to this: <bound method CartItem.name of <CartItem: CartItem object>
Yet the sku (alphanumeric string, just like "name") comes through just fine, it seems. Both are coming directly from MySQL. Any ideas what's going on?
<bound method CartItem.name of <CartItem: CartItem object>
is an error usually given when you are calling to see if a method is there, not actually calling the method itself. I would try adding () so i.name()
as you say, the data you give to the function checkout_items() is from get_cart_items().
So items is not a stupid namespace-like object, but an object that has methods that you wrote, and all of them are CartItems.
Then when you build co_item, you give i.name to the dictionary, that is later printed out as bound method CartItem.name of <CartItem: CartItem object>.
It looks like your CartItem object has a method name! You should try i.name(). Or use whatever property that really has the name if name() is something else.

How can i add extra data in object list in django python

I am extending the list view and in every object i need to add a dictionary.
My dic look like this
mydict1['var1'] = {'value':20, 'result':None}
mydict1['var2'] = {'value':20, 'result':None}
mydict1['var3'] = {'value':20, 'result':None}
now i want to add that dictionary to all objects like
for myobj in self.get_queryset():
myobj.add(mydict1)
so that i access in my template like this
{{myobj.dict1.var1.value}}
It looks like you just want to set an attribute on your objects?
So this should work:
for myobj in self.get_queryset():
myobj.dict1 = mydict1

Categories