How to perform Intersection with custom property in python - python

class Random:
def __init__(self,id):
self.id=id
self.prop=None
list_1={Random(12), Random(15), Random(22)}
list_2={Random(22),Random(9),Random(88)}
list_3={Random(88),Random(22),Random(12)}
result=list_1.intersection(list_2).intersection(list_3)
print (list(result))
#expected result = Random Object containing id=22
#returned result =[]
How to custom intersect among lists with custom field - id in the above case ?

set() documentation says:
A set object is an unordered collection of distinct hashable objects.
And hashable documentation says:
An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value.
So you need to implement __hash__() and __eq__() for your class.
class Random:
def __init__(self,id):
self.id=id
self.prop=None
def __hash__(self):
return hash((self.id, self.prop))
def __eq__(self, other):
return self.id == other.id and self.prop == other.prop

class Random:
def __new__(cls, id):
return id
list_1 = {Random(12), Random(15), Random(22)}
list_2 = {Random(22), Random(9), Random(88)}
list_3 = {Random(88), Random(22), Random(12)}
result = list_1.intersection(list_2).intersection(list_3)
print(list(result))
if you need id then u can try new of class method because it returns a value.
without return u got the object of a class that is all different that's why your result is empty

Related

How to support the `in` operation in python with a class

What magic method do I have to modify to support the in operator. Here's an example of what I'm trying to do:
class DailyPriceObj:
def __init__(self, date, product_id=None):
self.date = date
self.product_id = product_id
self.sd_buy = None
l = list()
l.append(DailyPriceObj(date="2014-01-01"))
DailyPriceObj(date="2014-01-01") in l # how to get this to return True?
In other words, I want my object to "act like" the date property, so I can use that to see if that obj is in an interable (date should be a unique field here).
You need to implement __eq__ (and __hash__ for the sake of completeness):
class DailyPriceObj:
def __init__(self, date, product_id=None):
self.date = date
self.product_id = product_id
self.sd_buy = None
def __eq__(self, other):
return isinstance(other, self.__class__) and self.date == other.date
def __hash__(self):
return hash(self.date)
l = [DailyPriceObj(date="2014-01-01")]
s = {DailyPriceObj(date="2014-01-01")}
print(DailyPriceObj(date="2014-01-01") in l)
print(DailyPriceObj(date="2014-01-01") in s)
Output
True
True
From the documentation on __hash__:
Called by built-in function hash() and for operations on members of
hashed collections including set, frozenset, and dict. __hash__()
should return an integer. The only required property is that objects
which compare equal have the same hash value; it is advised to mix
together the hash values of the components of the object that also
play a part in comparison of objects by packing them into a tuple and
hashing the tuple.
You can implement __eq__ in such a way that both two ways of checking will work:
class DailyPriceObj:
def __init__(self, date, product_id=None):
self.date = date
self.product_id = product_id
self.sd_buy = None
def __eq__(self, other):
return self.date == other
l = list()
l.append(DailyPriceObj(date="2014-01-01"))
# both ways work:
print(DailyPriceObj(date="2014-01-01") in l) # True
print("2014-01-01" in l) # True

Add user defined object to list of objects only if it's new

I have a list of user defined objects (all of the same type) and I need to write a function that will add additional items of the same class to the list only if the item is not already in the list. The fake code looks like this:
object_list = [object1, object2]
def some_func(new_object):
if new_object not in object_list:
object_list.append(new_object)
The class has a number of attributes, none of which are necessarily unique to an instance.
Overriding the __eq__ method should solve the problem
https://docs.python.org/3/reference/datamodel.html#object.eq
def __eq__(self, other):
"""Overrides the default implementation"""
if not isinstance(other, DefinedClass):
return NotImplemented
# comparison logic
return self.id1 == other.id1 && self.id2 == other.id2

Python: Add/update instance attribute of custom object in a set of objects

I'd like to add an attribute to an instance which is in a set.
The set of objects of the class Problem is identified by attribue uid (that's why they are hashed and compared):
class Problem:
allowed_keys = [
'flag1',
'a_list_of_objects'
]
def __init__(self, uid, name, **kwargs):
self.uid = uid
self.name = name
self.__dict__.update((k, v) for k, v in kwargs.iteritems() if k in self.allowed_keys)
def __eq__(self, other):
return isinstance(other, self.__class__) and getattr(other, 'uid', None) == self.uid
def __hash__(self):
return hash(self.uid)
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return json.dumps(self.__dict__, sort_keys=True)
All instances of this problem are added to a set.
problem_set = set()
problem1 = Problem(uid="abc123", name="name1", flag1=True)
problem_set.add(problem1)
problem2 = Problem(uid="xyz789", name="name2", flag2=False)
problem_set.add(problem2)
Now if I want to update the object problem1 with another attribute (it will never exist before), it just won't add the a_list_of_objects to the existing problem1
my_list = [{"a": "avalue", "b": "bvalue"}]
problem3 = Problem(uid="abc123", name="name1", a_list_of_objects=my_list
print list(problem_set)
# same list as before
What do I need to do in order to achieve this? Using #property and create getters and setters for each attribute of class Problem?
You are not modifying the existing problem1 instance. You are creating an entirely different instance problem3 albeit equal to problem1 going by your implementation of __eq__. Instances satisifying equality are not merged or synced in the way I think you expect. Instances of your class with the same uid and thus hash value can exist freely outside a set as independent objects. Trying to add one of both to a set will drop one, not sync them.
To modify problem1 you should instead do:
problem1.a_list_of_objects = my_list
Or you could assign to a copy of my_list to avoid sharing the same list among instances:
import copy
problem1.a_list_of_objects = copy.deepcopy(my_list)
New attributes can be bound to an existing instance of your class.

typecast classes in python: how?

Here, I am attempting to mock up a social media profile as a class "Profile", in which you have name, a group of friends, and the ability to add and remove friends. There is a method that I would like to make, that when invoked, will print the list of friends in alphabetical order.
The issue: I get a warning that I cannot sort an unsortable type. Python is seeing my instance variable as a "Profile object", rather than a list that I can sort and print.
Here is my code:
class Profile(object):
"""
Represent a person's social profile
Argument:
name (string): a person's name - assumed to uniquely identify a person
Attributes:
name (string): a person's name - assumed to uniquely identify a person
statuses (list): a list containing a person's statuses - initialized to []
friends (set): set of friends for the given person.
it is the set of profile objects representing these friends.
"""
def __init__(self, name):
self.name = name
self.friends = set()
self.statuses = []
def __str__(self):
return self.name + " is " + self.get_last_status()
def update_status(self, status):
self.statuses.append(status)
return self
def get_last_status(self):
if len(self.statuses) == 0:
return "None"
else:
return self.statuses[-1]
def add_friend(self, friend_profile):
self.friends.add(friend_profile)
friend_profile.friends.add(self)
return self
def get_friends(self):
if len(self.friends) == 0:
return "None"
else:
friends_lst = list(self.friends)
return sorted(friends_lst)
After I fill out a list of friends (from a test module) and invoke the get_friends method, python tells me:
File "/home/tjm/Documents/CS021/social.py", line 84, in get_friends
return sorted(friends_lst)
TypeError: unorderable types: Profile() < Profile()
Why can't I simply typecast the object to get it in list form? What should I be doing instead so that get_friends will return an alphabetically sorted list of friends?
Sorting algorithms look for the existence of __eq__, __ne__, __lt__, __le__, __gt__,__ge__ methods in the class definition to compare instances created from them. You need to override those methods in order to tweak their behaviors.
For performance reasons, I'd recommend you to define some integer property for your class like id and use it for comparing instead of name which has string comparison overhead.
class Profile(object):
def __eq__(self, profile):
return self.id == profile.id # I made it up the id property.
def __lt__(self, profile):
return self.id < profile.id
def __hash__(self):
return hash(self.id)
...
Alternatively, you can pass a key function to sort algorithm if you don't want to bother yourself overriding those methods:
>>> friend_list = [<Profile: id=120>, <Profile: id=121>, <Profile: id=115>]
>>> friend_list.sort(key=lambda p: p.id, reverse=True)
Using operator.attrgetter;
>>> import operator
>>> new_friend_list = sorted(friend_list, key=operator.attrgetter('id'))
I think i'll take a crack at this. first, here's teh codes:
from collections import namedtuple
class Profile(namedtuple("Profile", "name")):
def __init__(self, name):
# don't set self.name, it's already set!
self.friends = set({})
self.statuses = list([])
# ... and all the rest the same. Only the base class changes.
what we've done here is to create a class with the shape of a tuple. As such, it's orderable, hashable, and all of the things. You could even drop your __str__() method, namedtuple provides a nice one.

overidding Pythons __eq__ method , isistance & eq mothods return false

I'm new to Python from the Java world.
I have written a Python class called "Instance" with 3 properties(attribute, value, and class). I want to override the "eq" method & also the "hash" method, I'm using the "attribute" & "value" properties used for object comparison. I instantiated two objects with the same values, however they return as not equal.
Code is below , Class Instance:
'''Class of type Instance'''
class Instance(object):
__attribute = None;
__value = None;
__classification = None;
#constructor
def __init__(self,attribute,value,classification):
self.attribute = attribute;
self.value = value;
self.classification = classification;
#setters & getters
def setAttribute(self,attribute):
self.attribute = attribute
def setValue(self,value):
self.value = value
def setClassification(self,classification):
self.classification = classification
def getAttribute(self):
return self.Attribute;
def getValue(self):
return self.Value
def getClassification(self):
return self.Classification
def __eq__(self, other):
#if self & other are the same instance & attribute & value equal
return isinstance(self,other) and (self.attribute == other.attribute) and (self.value == other.value)
def __hash__(self):
return hash(self.attribute, self.value)
I'm instantiating in , another Python module called Testing:
if __name__ == '__main__':
pass
from Instance import *
instance1 = Instance('sameValue', 1,'Iris-setosa')
instance2 = Instance('sameValue', 1,'Iris-setosa')
if (instance1 is instance2):
print "equals"
else:
print "not equals"
The program returns: not equals.
Your first problem is isinstance(self, other) isn't asking whether self and other are both instances of compatible types, or whether they're the same instance (as your comment says), it's asking whether self is an instance of the type other. Since other isn't even a type, the answer is always false.
You probably wanted isinstance(self, type(other)). Or maybe something more complicated, like isinstance(self, type(other)) or isinstance(other, type(self)).
Or maybe you don't really want this at all; even for equality testing, duck typing is often a good idea. If other has the same attributes as self, and also hashes to the same value, is that good enough? The answer may be no… but you definitely should ask the question.
Your second problem is a misunderstanding of is:
if (instance1 is instance2):
print "equals"
else:
print "not equals"
The whole point of is is that it's asking whether these are the same object, not whether these two (possibly distinct) objects are equal to each other. For example:
>>> a = []
>>> b = []
>>> a == b
True
>>> a is b
False
They're both empty lists, so they're equal to each other, but they're two different empty lists, which is why you can do this:
>>> a.append(0)
>>> b
[]
And the same is true with your class. Each Instance that you create is going to be a different, separate instance—even if they're all equal.
The __eq__ method that you define customized the == operator. There is no way to customize the is operator.

Categories

Resources