I have a list of strings, say something like:
listofstuff = ['string1', 'string2', 'string3', ...]
I have a created a custom class object for what I want to do. All I want now is to create a bunch of said objects that are named the strings in my list. How can I do this?
So I have something like:
for object in listofstuff:
object = classthing(inputs)
But it doesn't work. How do I do this?
EDIT: Maybe I should clarify. I have an input file that can change, and in said input file is a list of names. I want to create a bunch of class objects that are all called the names in the list.
So someone gives me a list like
stuff = ['car1', 'car2', 'car3']
and I now want to create a bunch of new Car objects, each one called car1, car2, etc. So that later I can do things like car1.calculate_price() or whatever.
EDIT 2: Sorry for all the edits, but I also wanted to share something. In what I am trying to do, objects are grouped together in specific ways, but ways that aren't obvious to the user. So it would be like 'car1_car23_car4'. So I wanted, if I asked the user, which car do you want to pick? And they chose car4, it would create an object instead named car1_car23_car4, instead of car4.
Creating names dynamically is not the right approach. It is very easy to loose track of them, to make more or less than you need, or to accidentally overwrite an existing name.
A better approach would be to make a dictionary where the keys are your strings from listofstrings and the values are instances of your class. You can use a dict comprehension and write something like:
dct = {name: classthing(inputs) for name in listofstuff}
Below is a demonstration1 of what this does:
>>> class classthing: # This represents your class
... def __init__(self, name):
... self.name = name
...
>>> listofstuff = ['Joe', 'Bob', 'Mary']
>>>
>>> dct = {name: classthing(name) for name in listofstuff}
>>> dct # dct now holds all the data you need
{'Mary': <__main__.classthing object at 0x0205A6D0>, 'Joe': <__main__.classthing object at 0x0205A690>, 'Bob': <__main__.classthing object at 0x0205A6B0>}
>>>
>>> # Each value in dct is an individual instance of your class
>>> dct['Joe'].name
'Joe'
>>> dct['Bob'].name
'Bob'
>>> dct['Mary'].name
'Mary'
>>>
1For the sake of the demonstration, I replaced inputs with name. You do not have to do this in your real code though.
Assuming your strings are in a list called listofstrings, this creates a corresponsing list constructing objects from the strings (also assuming the __init__ method for the class expects one string argument):
listofobjects = [classthing(s) for s in listofstrings]
If that's what you're looking for, read further about list comprehensions.
While this answers your question, the other answer is probably better way of doing it.
Related
Background
I have a module called db.py that is basically consist of wrapper functions that make calls to the db. I have a table called nba and that has columns like player_name age player_id etc.
I have a simple function called db_cache() where i make a call to the db table and request to get all the player ids. The output of the response looks something like this
[Record(player_id='31200952409069'), Record(player_id='31201050710077'), Record(player_id='31201050500545'), Record(player_id='31001811412442'), Record(player_id='31201050607711')]
Then I simply iterate through the list and dump each item inside a dictionary.
I am wondering if there is a more pythonic way to populate the dictionary?
My code
def db_cache():
my_dict: Dict[str, None] = {}
response = db.run_query(sql="SELECT player_id FROM nba")
for item in response:
my_dict[item.player_id] = None
return my_dict
my_dict = db_cache()
This is built-in to the dict type:
>>> help(dict.fromkeys)
Help on built-in function fromkeys:
fromkeys(iterable, value=None, /) method of builtins.type instance
Create a new dictionary with keys from iterable and values set to value.
The value we want is the default of None, so all we need is:
my_dict = dict.from_keys(db.run_query(sql="SELECT player_id FROM nba"))
Note that the value will be reused, and not copied, which can cause problems if you want to use a mutable value. In these cases, you should instead simply use the dict comprehension, as given in #AvihayTsayeg's answer.
my_arr = [1,2,3,4]
my_dict = {"item":item for item in my_arr}
I am experimenting using lambda functions to create a list that contains only the values of a particular key to a list.
I have the following:
names = None
names = list(map(lambda restaurant: dict(name=restaurant['name']
).values(), yelp_restaurants))
names
# This is what I want for the list:
# ['Fork & Fig',
# 'Salt And Board',
# 'Frontier Restaurant',
# 'Nexus Brewery',
# "Devon's Pop Smoke",
# 'Cocina Azul',
# 'Philly Steaks',
# 'Stripes Biscuit']
What I get however, is the following:
[dict_values(['Fork & Fig']),
dict_values(['Salt And Board']),
dict_values(['Frontier Restaurant']),
dict_values(['Nexus Brewery']),
dict_values(["Devon's Pop Smoke"]),
dict_values(['Cocina Azul']),
dict_values(['Philly Steaks']),
dict_values(['Stripes Biscuit'])]
Is there a way to only pass the values, an eliminate the redundant 'dict_values' prefix?
The function you are using to create names is a bit redundant:
names = list(map(lambda restaurant: dict(name=restaurant['name']
).values(), yelp_restaurants))
The control flow that you have outlined is "from a list of dict entries called yelp_restaurants, I want to create a dict of each name and grab the values from each dict and put that in a list."
Why? Don't get hung up on lambda functions yet. Start simple, like a for loop:
names = []
for restaurant in yelp_restaurants:
names.append(restaurant['name'])
Look at how much simpler that is. It does exactly what you want, just get the name and stuff it into a list. You can put that in a list comprehension:
names = [restaurant['name'] for restaurant in yelp_restaurants]
Or, if you really need to use lambda, now it's much easier to see what you actually want to accomplish
names = list(map(lambda x: x['name'], yelp_restaurants))
Remember, the x in lambda x: is each member of the iterable yelp_restaurants, so x is a dict. With that in mind, you are using direct access on name to extract what you want.
I have a set of data that looks like so:
OutletCntrTemp|25degreesC|ok
InletTemp|17degreesC|ok
PCHTemp|46degreesC|ok
P0ThermMargin|-57degreesC|ok
P1ThermMargin|-59degreesC|ok
P0DIMMTemp|27degreesC|ok
P1DIMMTemp|27degreesC|ok
HSC0InputPower|60Watts|ok
HSC0InputVolt|12.46Volts|ok
CPU0Tjmax|90degreesC|ok
......
Now I want to loop through this data and create a list or a tuple in a function and return each row but name that tuple using the first part of the string:
CPUTjmax = ('90degreesC','ok')
now i did some spliting up of the string via | but hit a wall when i tried to use string[0] = (string[1],string[2]) to define the tuple.
Could anyone give me a pointer here please.
Ric
What you can do is, create a dict, and add them as key:value pair in it:
>>> d = dict()
>>>
>>> s = 'CPU0Tjmax|90degreesC|ok'
>>> li = s.split("|")
>>>
>>> d[li[0]] = (li[1], li[2])
>>> d
{'CPU0Tjmax': ('90degreesC', 'ok')}
You almost certainly don't want to create variables, use a dict instead:
data = [
'CPU0Tjmax|90degreesC|ok',
'InletTemp|17degreesC|ok'
]
d = {el[0]: tuple(el[1:]) for el in (item.split('|') for item in data)}
# {'InletTemp': ('17degreesC', 'ok'), 'CPU0Tjmax': ('90degreesC', 'ok')}
The other answers are good. Here is one more way, similar to the answer using locals(). You just create an empty object, and fill its __dict__:
class X(object):
pass
Var = X()
for ...:
Var.__dict__[string[0]] = (string[1], string[2])
#now you can refer to your vars as Var.whatever
if Var.InletTemp[1] != 'ok':
...
Use should definitely use a dictionary variable.
For completeness here a non-standard solution for creating new local variables:
for line in open("data.dat"):
e=line.split("|")
locals()[e[0]] = ( e[1], e[2] )
Internally, the local variables are also a dictionary which you can access with locals().
However, as the documentation says:
The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
I need a data structure of this form:
test_id1: resultValue, timeChecked
test_id2: resultValue, timeChecked
test_id3: resultValue, timeChecked
test_id4: resultValue, timeChecked
...
up until now I have dealt with it by just using a dictionary with key value for the id and the result. But I would like to add the time I checked.
What would be the best way to do this? Can I make the value a tuple? Or is a new class better suited in this case?
What would my class need to look like to accommodate the above?
One lightweight alternative to making a class that both 1) retains the simplicity of a tuple and 2) allows named (as opposed to positional) field access is namedtuple.
from collections import namedtuple
Record = namedtuple("Record", ["resultValue", "timeChecked"])
s = {"test_id1": Record("res1", "time1"), "test_id2": Record("res2", "time2")}
You can now use the values in this dict as if you had a class with the resultValue and timeChecked fields defined...
>>> s["test_id1"].resultValue
'res1'
...or as simple tuples:
>>> a, b = s["test_id1"]
>>> print a, b
res1 time1
Can I make the value a tuple?
Yes, and I'm not really sure why you don't want to. If it's to make look-ups easier to read, you can even make the value another dictionary.
{"test_id1" : (resultValue, timeChecked)}
or
{"test_id1" : {"resultValue": resultValue, "timeChecked" : timeChecked }}
I think a whole new class is overkill for this situation.
You could also use a pandas DataFrame for your whole structure. It's probably waaaay overkill unless you're planning to do some serious data processing, but it's a nice thing to know about and directly matches your problem.
I have a dictionary, containing several hundred entries, of format:
>>>dict
{'1620': 'aaaaaa'}
I would like to make new empty lists named '1620', etc. I have tried variations of the following but it doesn't recognize eachkey as a variable to be used when creating the list. Instead, it names the list literally "eachkey" and my key, in this example '1620', is not connected to the new list.
>>>for eachkey in dict.keys():
>>> eachkey=[]
>>>
>>>eachkey
[]
>>>'1620'
1620
Edited to add:
Maybe I could make the list at the same time as I make the dictionary? Slip it in here below? The str(eachfile[-4:]) is what I want the list named.
files=open(sys.argv[1])
dict={}
for eachfile in files:
value=open(eachfile)
key=str(eachfile[-4:])
dict[key]=value
eachfile.close()
Edit: it would be fine for me to add letters along w/ the numbers if that's what it needs.
I don't think it's possible to change the integer literal 1620 so that it gives you an object other than the integer 1620. Similarly I don't think you can change the string literal '1620' to give you a list instead of a string.
You could do it if you prefix the variable names with some letters to make them valid names. For example you could use my1620 instead of 1620. I wouldn't advise doing this, but it's possible:
>>> d = {'1620': 'aaaaaa'}
>>> for k,v in d.items():
... locals()['my'+k] = []
>>> my1620
'aaaaaa'
With a dict like this:
d1 = {'foo':'bar', '1621':'hello'}
Try doing this:
d2 = dict((k,list()) for k in d1.keys())
Now d2 is:
{'1621': [], 'foo': []}
And you can reference your lists list so:
d2['1621'].append(20)
d2['foo'].append(5)
d2['foo'].append('zig')
Which makes d2:
{'1621': [20], 'foo': [5, 'zig']}
As Gareth said, it's VERY unlikely you really want to do what you're asking to do. This is probably better.