How to search a Python List via Object Attribute? - python

Consider the following python class:
class Event(Document):
name = StringField()
time = DateField()
location = GeoPointField()
def __unicode__(self):
return self.name
Now I create a list of Events:
x = [Event(name='California Wine Mixer'),
Event(name='American Civil War'),
Event(name='Immaculate Conception')]
Now I want to add only unique events by searching via the event name.
How is this done with the boolean in syntax?
The following is incorrect:
a = Event(name='California Wine Mixer')
if a.name in x(Event.name):
x.append(a)

By unique I think you want something like "if a.name not in x(Event.name):", which can be written as
if not any(y.name == a.name for y in x):
...
But if the name acts as an index, it is better to use a dictionary to avoid the O(N) searching time and the more complex interface.
event_list = [Event(name='California Wine Mixer'), ...]
event_dict = dict((b.name, b) for b in event_list)
# ignore event_list from now on.
....
a = Event(name='California Wine Mixer')
event_dict.setdefault(a.name, a)

Related

Python: how to utilize instances of a class

New to OOP and python, I am struggling enormously to grasp what good classes actually are for. I tried to ask help from a lecturer who said "oh, then you should read about general methods to classes". Been putting in a days work but get no where.
I get it that a class allow you to collect an instance structure and methods to it, like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idA.show_list()
But what is even the point of a class if there were not MANY instances you would classify? If I have a method within the class, I must hard code the actual instance to call the class for. What if you want a user to search and select an instance, to then do operations to (e.g. print, compute or whatever)??
I thought of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
select_item = input("enter item id")
select_item.show_list()
Replacing hard coded variable with input variable doesn't work, probably logically. I then played with the idea of doing it like this:
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
iL = [Items('idA', 'A'), Items('idB', 'B')]
selected_item = input("enter item id")
for selected_item in iL:
print(f'{selected_item.item_id} {selected_item.item_name}')
Now all are called thanks to making it a list instead of separate instances, but how do I actually apply code to filter and only use one instance in the list (dynamically, based on input)?
I would love the one who brought me sense to classes. You guys who work interactively with large data sets must do something what I today believe exist in another dimension.
See examples above^^
It seems you want to find all the instances of a certain element within a class.
This is as simple as:
print([x for x in iL if x.item_id == selected_item])
Now, you may ask why you can't just store the elements of iL as tuples instead of classes. The answer is, you can, but
("idA", "A")
is much less descriptive than:
item_id = "idA"
item_name = "A"
Any code you write with classes, you should in theory be able to write without classes. Classes are for the benefit of the coder, not the end-user of the program. They serve to make the program more readable, which I'm sure you'll find is a desirable property.
Your point here is to lookup for Items instances based on their item_id attribute.
That's a thing to create instances of a class.
It's a completely different thing to search for items objects stored in memory - that is not directly linked to the concept of OOP, classes and instances.
You could use dictionary to store references of your objects and then lookup in your dictionary.
class Items:
def __init__(self, item_id, item_name):
self.item_id = item_id
self.item_name = item_name
def show_list(self):
print(self.item_id, self.item_name)
idA = Items("idA", "A")
idB = Items("idB", "B")
lookup_dict = {"idA": idA, "idB": idB}
select_item = input("enter item id")
found_item = lookup_dict.get(select_item)
if found_item:
found_item.show_list()
else:
print(f"item {select_item} not found")

List Manipulation Based on Class Variables

Apologies if I explain something wrong or use the wrong wording, my programmer vocabulary isn't the best. If anyone understands my problem and has better ways of explaining it feel free to do so. I have a problem similar to a problem here. I want to remove items from a list that occur in another list. But one list will have strings that reference the variable "name" within class objects.
class sword:
name = 'swordName'
class bow:
name = 'bowName'
class axe:
name = 'axeName'
inventory = [sword, bow, sword, axe]
select = ['bowName', 'swordName']
I want to be able to create a list "selectedItems" with the class objects out of inventory based off of the strings in "select" that are equal to the "name" of the class objects. It also needs to work if "inventory" and "select" both have duplicates in them.
Output:
>> inventory = [bow, axe]
>> selectedItems = [bow, sword]
One other thing I would like the program to ignore if there are more "name"s in select than there are corresponding class objects in "inventory", and to ignore if a string in "select" has no corresponding class objects.
For example, if "inventory" is [sword, axe] and "select" is ['bowName', 'non-existent', 'axeName'], the result is that "inventory" is [sword] and "selectedItems" is [axe].
A simple way of explaining this is that select will take from inventory, but if select can't take from inventory nothing happens.
You may make base class with magic methods __eq__ and __hash__ which can allow you to manage comparing your objects as you want:
class BaseItem:
name = None
def __init__(self):
self.__name = self.name
def __eq__(self, other):
return self.__name == other
def __hash__(self):
return id(self.__name)
def __repr__(self):
return f"'{self.__name}'"
class Sword(BaseItem):
name = "swordName"
class Bow(BaseItem):
name = "bowName"
class Axe(BaseItem):
name = "axeName"
inventory = [Sword(), Bow()]
select = ["swordName", "bowName", "axeName", "swordName", "bowName"]
# casting lists into sets and getting difference between them
result = set(inventory) - set(select)
print(result) # output {'swordName', 'bowName'}
eq - actually is unused here but i added that you can compare your objects with strings, lists etc:
Sword() in ["swordName"] # true
Sword() in ["bowName"] # false
Sword() == "swordName" # true
Sword() == "bowName" # false
hash - need to comparing two objects, actually it use for getting difference between two sets
repr - it is not really required method, it needs just for pretty displaying of objects
selectedItems = list()
# make a new list of the names of the objects in the inventory
# inventory and inventory names have the same index for the same item
inventory_names = [x.name for x in inventory]
for s in select:
if s in inventory_names:
index = inventory_names.index(s)
inventory_names.pop(index)
selectedItems.append(inventory.pop(index))

How can I check if an attribute of a class exists in array?

I want to know if it is possible to check if an array of a class has a specific instance of an attribute, and return True if it does. In other words, does an instance of a class attribute exist in an array of that class?
In my example, I have an array of class Team. The class Team has an attribute, name. I want to check if a Team instance with a specific name exists by iterating over an array of Team instances.
Class Team:
class Team:
def __init__(self):
self.name = name # (String)
[Invalid] This is the how I wanted to write the function:
# team_name is a String variable
# teams is an array of the Team class
def team_name_taken(team_name, teams):
if team_name in teams.name:
return True
else:
return False
I know this doesn't work, but is it possible to iterate over the same attribute within an array in this fashion?
[Valid] Regarding the goal of my code, I have the following code that works properly:
def team_name_taken(team_name, teams):
for team in teams:
if team_name == team.name:
return True
return False
I know that this works, I was just wondering if there was another way to do it, similar to the invalid way I represented above.
What you could do is the following:
def team_name_taken(team_name, teams):
team_names = [team.name for team in teams]
if team_name in team_names:
return True
else:
return False
This will generate a list with the items of the list being all team names. Once you have done that you can do if team_name in team_names: and get the desired outcome.
If on the other hand you just want to make it a oneliner you could do this:
def team_name_taken(team_name, teams):
return len([ team for team in teams if team.name == team_name ]) >= 1
This will make a list then check if the len() of the list is 1 (or bigger) and if that is the case return True else False.
The following class definition allows name from the user to be assigned to the Team.name attribute and forces it to be a str object:
class Team(object):
def __init__(self, name):
self.name = str(name)
Here is an example list of Team instances:
teams = [Team(x) for x in range(10)]
You can do what I think you want with some one-liners:
Using another list comprehension to find out if any of the names equal '3':
any([team.name == '3' for team in teams])
Or if you really want to use a function you can use the following:
any(map(lambda obj: obj.name == '3', teams))

Python: Define Object within a Class

Very new to Python and could do with some help. How do I go about referencing members in a class?
I have two csv files. One contains a series of parts and associated material ID. The other is a material index that contains materials ID's and some information about that material.
My intention is to create a third file that contains all of the parts, their material Id's and the information if present in the material index.
I have created a class for the material index and am trying to access objects in this class using material Ids from the part file however, this is not working and I am unsure as to why. Any help is appreciated:
class material():
def __init__(self, name, ftu, e, nu):
self.name = name
self.ftu = ftu
self.e = e
self.nu = nu
def extract_FTU_Strain(input_file_parts,input_file_FTU,output_file):
parts = {}
materials = {}
for aline in open(input_file_FTU, 'r'):
comma_split = aline.strip().split(',')
name = comma_split[1]
ftu = comma_split[8]
e = comma_split[9]
nu = comma_split[7]
try:
materials[int(comma_split[0])] = material(comma_split[1],comma_split[8],comma_split[9],comma_split[7])
#materials[comma_split[0]] = material(comma_split[1],comma_split[8],comma_split[9],comma_split[7])
except:
pass
for i in open(input_file_parts, 'r'):
semicolon_split = i.strip().split(';')
material_id = semicolon_split[3]
part = semicolon_split[0]
part_id = semicolon_split[1]
material_name = materials[material_id].name
FTU = materials[material_id].ftu
Stress = materials[material_id].e
output.write(','.join([part,part_id,material_name,material_id,FTU,Stress]) + '\n')
output = open (output_file,'w')
output.write('Part Title, Part Id, Material Id, FTU, e' + '\n')
output.close()
import sys
input_file_parts = '/parttable.csv'
input_file_FTU = '/Material_Index.csv'
output_file = '/PYTHONTESTING123.csv'
extract_FTU_Strain(input_file_parts,input_file_FTU,output_file)
Since in the comments you said your error is in materials[material_id] make material_id an integer as it was an integer when you created the object.
You created it this way
materials[int(comma_split[0])]=...
But later called it without converting material_id to an int. Do this before calling it in your for loop to write in the output.
material_id = int(material_id)
I may have misinterpreted your question, but going off the line 'How do I go about referencing members in a class?' you can reference member variables like so:
class Demonstration:
def __init__(self, a, b):
self.a = a
self.b = b
def printMembers(self):
print self.a, self.b
So inside the class you can use self.someVariable to reference member variables.
If you want to access them outside of the class:
myclass.myvariable
I'll happily edit the answer if I have't quite understood your question or if there is a specific error you are getting.
I did not understand what error you have, could you put the traceback? Anyway, you are creating a class instance at the time of assignment. For more elegant programming, you could simply do:
m = materials(name, ftu, e, nu)
This way you can access the instance variables like this:
m.name
m.ftu
...
And try, except -> pass it's very dangerous

Dynamic keyword with database value

I have a model like this:
class meter1(models.Model):
U1N = models.FloatField(default=0)
U2N = models.FloatField(default=0)
In my view (simplified) I want to set the value for the database dynamically:
def import_data:
dict = {"1":"U1N","2":"U2N",}
c = "1"
q = meter1()
q.eval('dict[c]') = "1"
q.save()
In real dict contains 60 items, and c changes every time in a for loop. The code in this example results in an error: NameError: name 'U1N' is not defined.
How do I dynamically set the keyword for q?
You can also dynamically build a dict from your dict (you shouldn't use a builtin name as identifier BTW) and pass it as kwargs to meter1() (you shouldn't use all-lowers as class names BTW). Oh and yes: you may want to have a look at modelmanager.create() too.
def import_data():
fieldmap = {"1":"U1N","2":"U2N",}
fieldindex = "1"
kw = {fieldmap[fieldindex]: 1.0}
# either:
q = Meter1(**kw)
q.save()
# or:
q = Meter1.objects.create(**kw)
You can use setattr to dynamically set attributes to the objects.

Categories

Resources