Python. How to efficiently remove custom object from array - python

Good afternoon dear colleagues! I have maybe quite an obvious question, but it can be considered as quite a mystery to me.
So, I have two custom classes, let it be Class A and Class B. Class B has a property, which contains multiple instances of Class A. It also contains methods to work with this property: add, remove, get single and all instances in this property.
However, apart from standard and quite over questioned deal with MVC pattern, I wonder: what is the most efficient and fast method to remove an object from this property (array) in Python, which implements some customization (e.g. compare objects by id, title and other properties).
I had implemented my own, but it seems way too complicated for such an essential operation.
class Skill:
def __init__(self, id_):
self.id = id_
class Unit:
def __init__(self):
self.skills = []
def get_skills(self):
return self.skills
def get_skill(self, index):
return self.skills[index]
def add_skill(self, skill):
self.skills.append(skill)
def remove_skill(self, skill_to_remove):
self.skills = filter(lambda skill: skill.id != skill_to_remove.id, self.skills)

If you need arbitrary criteria, then filtering is OK, but it is slightly shorter to use a list comprehension. For example, instead of
self.skills = filter(lambda skill: skill.id != skill_to_remove.id, self.skills)
use:
self.skills = [s for s in self.skills if s.id != skill_to_remove.id]
It's also possible to modify the list in-place (see this question) using slice assignment:
self.skills[:] = (s for s in self.skills if s.id != skill_to_remove.id)
If you are filtering skills based on an exact match with a "template" skill, i.e. matching all the properties of skill_to_remove then it might be better to implement an equality method for your Skill class (see this question). Then you could just use the remove method on self.skills. However, this will only remove the first matching instance.

Related

how to sort a list that is contained in an object

The task is to code a sorting algorithm using the below code as a starting point. The issue is I cannot seem to figure out how I go about starting the code, I'm not looking for the full solution - just techniques in how to sort lists of tuples that are actually part of an object. I get errors when I try to iterate through the list, saying cannot iterate through an object.
class LinkedList:
def __init__(self, data):
self.label = data[0][0]
self.value = data[0][1]
self.tail = None if (len(data) == 1) else LinkedList(data[1:])
countries = LinkedList([("Ukraine",41879904),("Brunei",442400),("Christmas Island (Australia)",1928)
You can use a pointer to iterate through linked list.:
curr = countries
while curr:
print("Label {}, Value {}".format(curr.label, curr.value))
curr = curr.tail
In order to sort linked list, firstly, you need to implement helper functions to remove/insert a node to given linked list at certain position. Once you have such methods, you can implement any of the famous sorting algorithms (e.g quick sort) using your helper methods you just created.
To iterate over this list you need to keep getting the tail reference of the object:
class LinkedList:
def __init__(self, data):
self.label = data[0][0]
self.value = data[0][1]
self.tail = None if (len(data) == 1) else LinkedList(data[1:])
countries = LinkedList([("Ukraine",41879904),("Brunei",442400),("Christmas Island (Australia)",1928)])
nextObj = countries
while nextObj is not None:
print(nextObj.label, nextObj.value)
nextObj = nextObj.tail
print("done!")
output:
Ukraine 41879904
Brunei 442400
Christmas Island (Australia) 1928
done!
To get an element at a certain index, you start iterating from the first element and just keep a counter.
functools, #total_ordering
One of the powerful features in python. you can sort objects in a classic and easy straitforward way.
Functools module in python helps in implementing higher-order functions. Higher-order functions are dependent functions that call other functions. Total_ordering provides rich class comparison methods that help in comparing classes without explicitly defining a function for it. So, It helps in the redundancy of code.
There are 2 essential conditions to implement these comparison methods
At least one of the comparison methods must be defined from lt(less than), le(less than or equal to), gt(greater than) or ge(greater than or equal to).
The eq function must also be defined
from functools import total_ordering
#total_ordering
class LinkedList(object):
def __init__(self, data):
self.label = data[0][0]
self.value = data[0][1]
def __lt__(self, other):
return self.label < other.value ##lets assume that the sort is based on label data member(attribute)
def __eq__(self, other):
return self.label == other.value
##I dont know what data is. just pass your data objects to list of LinkedList objects. and sort it with sorted method (treat them like int objects)!
my_list = [LinkedList(data0),LinkedList(data1),LinkedList(data2)]
new_list=my_list.sorted()
for obj in new_list:
print(...)

Python - Recommended way to dynamically add methods within a class

I have a class where I want to initialize an attribute self.listN and an add_to_listN method for each element of a list, e.g. from attrs = ['list1', 'list2'] I want list1 and list2 to be initialized as empty lists and the methods add_to_list1 and add_to_list2 to be created. Each add_to_listN method should take two parameters, say value and unit, and append a tuple (value, unit) to the corresponding listN.
The class should therefore look like this in the end:
class Foo():
def __init__(self):
self.list1 = []
self.list1 = []
def add_to_list1(value, unit):
self.list1.append((value, unit))
def add_to_list2(value, unit):
self.list2.append((value, unit))
Leaving aside all the checks and the rest of the class, I came up with this:
class Foo():
def __init__(self):
for attr in ['list1', 'list2']:
setattr(self, attr, [])
setattr(self, 'add_to_%s' % attr, self._simple_add(attr))
def _simple_add(self, attr):
def method(value, unit=None):
getattr(self, attr).append((value, unit))
return method
I also checked other solutions such as the ones suggested here and I would like to do it "right", so my questions are:
Are/Should these methods (be) actually classmethods or not?
Is there a cost in creating the methods in __init__, and in this case is there an alternative?
Where is the best place to run the for loop and add these methods? Within the class definition? Out of it?
Is the use of metaclasses recommended in this case?
Update
Although Benjamin Hodgson makes some good points, I'm not asking for a (perhaps better) alternative way to do this but for the best way to use the tools that I mentioned. I'm using a simplified example in order not to focus on the details.
To further clarify my questions: the add_to_listN methods are meant to be additional, not to replace setters/getters (so I still want to be able to do l1 = f.list1 and f.list1 = [] with f = Foo()).
You are making a design error. You could override __getattr__, parse the attribute name, and return a closure which does what you want, but it's strange to dynamically generate methods, and strange code is bad code. There are often situations where you need to do it, but this is not one of them.
Instead of generating n methods which each do the same thing to one of n objects, why not just write one method which is parameterised by n? Something roughly like this:
class Foo:
def __init__(self):
self.lists = [
[],
[]
]
def add(self, row, value):
self.lists[row].append(value)
Then foo.add1(x) becomes simply foo.add(1, x); foo.add2(x) becomes foo.add(2, x), and so on. There's one method, parameterised along the axis of variation, which serves all cases - rather than a litany of ad-hoc generated methods. It's much simpler.
Don't mix up the data in your system with the names of the data in your system.

Variable referring to class members - Python

I'm trying to create a way to apply a prefix to an item which would modify the item's existing stats. For example in the code below I am trying to apply the 'huge' prefix to the 'jar' item. I'd like to make the code reusable so that I could have different prefixes ('fast', 'healthy') that would modify different item stats.
Is it possible to hold the name of a class member in a variable?
If so, is there any reason I shouldn't?
If not, what alternatives are there?
class Prefix(object):
def __init__(self, word, stat, valu):
self.word = word
self.stat = stat
self.valu = valu
class Item(object):
def __init__(self, name, size):
self.name = name
self.size = size
def apply_prefix(self, prefix):
self.prefix.stat += prefix.valu # <-- Here is my issue
self.name = prefix.word + ' ' + self.name
# My hope is to make the code reusable for any stat
def print_stats(self):
print self.name, self.size
def main():
jar = Item('jar', 10)
huge_prefix = Prefix('huge', 'size', 5)
jar.apply_prefix(huge_prefix)
jar.print_stats()
You're trying to dynamically refer to some attribute. You do that by using getattr. And if you want to set the attribute, well... that's setattr :)
def apply_prefix(self, prefix):
target_attr = getattr(self,prefix.stat) #dynamically gets attr
setattr(self,prefix.stat,target_attr+prefix.valu)
As to whether this is the best coding style: it depends. There are some instances that code is made more clear by use of getattr. Since right now you only have two stats, it seems excessive to need this kind of dynamic attribute referencing, since I could easily do:
bogus_prefix = Prefix('huge','bogus',3)
Which is a valid Prefix, but throws an AttributeError when I try to apply it. That's not the most straightforward thing to debug.
However, there are bonuses to the getattr approach: if you add more stats, you don't have to change a bit (haha) of code in Prefix.
Other alternatives? There are always options in Python. :-)
The way I'd do it is to make Prefix just a dict of word:value pairs. Then apply_prefix would loop over the word keys, updating as many values as I wanted in one shot. It's a similarly dynamic approach, but a bit more scalable.

remove multiple "classes" from a list in python

I have
class rel:
child=''
parent=''
listPar=[]
and in listPar I have a list of these classes (sorry for terms, I'm not sure if it is called class, is it?) so in listPar I have for example: room book ; book title ; room book;book title
And now im trying to remove all non unique occurences, so I want to have only
room book ; book title in listPar
Let's assume, that i have following code:
variable="Book"
variable2="Author"
toIns=rel()
toIns.parent=variable
toIns.child=variable2
listPar.append(toIns)
toIns2=rel()
toIns2.parent=variable
toIns2.child=variable2
listPar.append(toIns2)
and now how to remove all duplicates? (result ->
for elem in listPar:
print "child:",elem.child,"parent:",elem.parent
#child:author, parent:book
I have tried several things, but none of them seemed to fully work..could you please help me?
I'm presuming that the class you have given there isn't the actual class (as it would be worthless), but the easiest thing for you to do here - presuming the order of your elements doesn't matter to you, is to make your list into a set, which will remove all duplicates.
>>> a = ["test", "test", "something", "else"]
>>> a
['test', 'test', 'something', 'else']
>>> set(a)
{'test', 'something', 'else'}
Here I have use strings, but you could use any class that provides the equality operator and hash function. The equality function is used to check if the two classes are the same (as for a custom class, you need to define that) and a hash is used to make sets very efficient. Two classes giving the same hash must be the same. You can have two classes with the same hash that are not the same (it will fall back to the equality operator), but the more this happens the slower it will be. In general, using the sum of the hashes of the components of the class you use to check for equality is a good way to generate a decent hash.
So, for example:
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __eq__(self, other):
return self.title == other.title and self.author == other.author
def __hash__(self):
return hash(self.title)+hash(self.author)
def __repr__(self):
return "Book("+repr(self.title)+", "+repr(self.author)+")"
We can use this class like before.
>>> a = [Book("Some Book", "Some Guy"), Book("Some Book", "Some Guy"), Book("Some Other Book", "Some Other Guy")]
>>> a
[Book('Some Book', 'Some Guy'), Book('Some Book', 'Some Guy'), Book('Some Other Book', 'Some Other Guy')]
>>> set(a)
{Book('Some Other Book', 'Some Other Guy'), Book('Some Book', 'Some Guy')}
If you do care about the order of the elements, even after removing duplicates, then you could do this:
def remove_duplicates_preserving_order(seq):
seen = set()
return [ x for x in seq if x not in seen and not seen.add(x)]
This works by hacking the dictionary comprehension a little - set.add() always returns 0, so you can check it is false (which it always will be) to add the element to the set.
Edit for update:
Please note that PEP-8 reccomends
using CapWords for classes, and lowercase_with_underscores for local
variables.
You seem to have a misunderstanding about how Python classes work. This class
doesn't make much sense, as these are all class attributes, not instance
attributes. This means that they will be the same for all instances of the
class, and that's not what you want. This means that when you change them the
second time, you will be changing it for all the instances, making them all
the same.
To make instance variables (the type you want) you want to create them inside
the constructor (__init__()) - check my example class to see how this works.
Once you have done this, you then need to implement __eq__() and __hash__()
functions so that Python knows what it means for two items of your class to be
equal. You can then use the methods I described above (either a set or the function
I gave) to remove duplicates.
Note that if this is all you wish to do with your data, a class might be overkill.
If you are always going to have two items, you could just use a tuple:
>>> a = [("Book", "Author"), ("Book", "Author"), ("OtherBook", "OtherAuthor")]
>>> set(a)
{('Book', 'Author'), ('OtherBook', 'OtherAuthor')}
As tuples already define equality for you as a sum of their parts.
Overall, you seem to lack an understanding of how classes are constructed and used in Python - I would suggest you go read up and learn how to use them before anything else, as not doing so will cause you a lot of problems.

Python: dynamically create methods based on other classes'

I've looked for quite a while but couldn't find a proper answer to my question:
I have a class containing methods which operate on arrays and I want dynamically create methods with a similar name in another class with a modified output.
I've got something like this so far, can anyone guide me ?
Thanks
Class A():
def__init__(self,array):
self.data = array
def method1(self,*args):
newarray = whatever(self.data,*args)
return newarray
def method2(self,*args):
newarray = whatever2(self.data,*args)
return newarray
I want to be able to use those methods to generate new ones in a more complex class, say:
class B(C): #inherits from C
def __init__(self,[arg1,array]):
#initialize from parent class
C.__init__(self,[arg1,array])
#create new methods for this class using same name
methodnames = [element for element in dir(A) if element[0] != '_']
for methodname in methodnames:
##following works but this is not the output I want here
#self.__dict__[methodname] = getattr(A(array),methodname)
#following doesn't work... at least not as I expect it to
#case1
#self.__dict__[methodname] = [arg1,getattr(A(array),methodname)]
#case2
self.__dict__[methodname] = list([arg1,getattr(A(array),methodname)])
a = array
#following returns a list of [arg1, method] but what I really want is [arg1,newarray]
C([arg1,array]).method1(*args)
OK, so let's try to be clearer:
Class A contains filters, takes an array and applies filter as method, returns filtered data.
Class filters()
def__init__(self,array):
self.data = array
def filter1(self,*args):
newarray = median(self.data,*args)
return newarray
def filter2(self,*args):
newarray = gaussian(self.data,*args)
return newarray
...
In another module, I have class SpecialData, which operates on a list of x,y data (where x and y are iterables, i.e. lists, arrays...). So something like
Class SpecialData():
def __init__(self,[x,y]):
self.data = [x,y]
def power(self,power):
ypow = self.data[1]**power
return [x,pow]
def porod(self):
return [x**4,x**4*y]
....
Now, what I want is to add the filter methods contained in class filters to class SpecialData.
I could, of course do this by re-coding all filters with proper format for SpecialClass. but what I really want, is that each time a new filter is added to class filters, to make it available at runtime in class SpecialData without having to re-hard code the new filter.
So, not being very clever, I tried to read the list of available filters in class filters by:
import filters
filternames = [element for element in dir(filters) if element[0] != '_']
for fitlername in filternames:
generate_filters_in_class_SpecialClass
How do I do this properly ?
I found a number of posts related to this, some using super(), others using SpecialData.dict or even setattr. Since the 2nd seemed more understandable to me, I focused on this one and came up with:
import filters
Class SpecialData():
def __init__(self,[x,y]):
self.data = [x,y]
filternames = [element for element in dir(filters) if element[0] != '_']
for fitlername in filternames:
self.__dict__[fitlername ] = [self.data[0],getattr(filters(self.data[1]),fitlername)]
Of course, this doesn't work, because the list is not callable. If I change the last line to :
self.dict[fitlername ] = list([self.data[0],getattr(filters(self.data[1]),fitlername)])
it returns the method as the 2nd element, rather than the result.
Note that the following works, but this is not what I want...
self.dict[fitlername ] = getattr(filters(self.data[1]),fitlername)
Hope this is clearer now...
I think you are trying to make an advanced use of Python without using/knowing its advanced features, like you are borrowing techniques from another language.
This is not a criticism, but you should have a look on Python tutorial, Python introspection or metaclasses.
I think that if you just complete your knowledge on Python functions you will be easily able to solve your problem in a much simpler way.
Rather than generating a proposed solution, you should make it clearer what you are trying to achieve. Class A is a clear example of the starting point; please post an example of your desired ending point, e.g.
Class B():
def__init__(self,array):
self.data = array
def method1(self,*args):
newarray = ComplexWhatever(self.data,*args)
return newarray
def method2(self,*args):
newarray = EvenBiggerWhatever2(self.data,*args)
return newarray
a = A(input_array)
b = B(input_array)
print(a.method1(args))
print(b.method1(args))
What isn't clear is how you want to "dynamically generate" the new function "ComplexWhatever()" instead of writing the function by hand.

Categories