If I have a class
class Kid():
def __init(name):
self.name = name
what should I add to it to be able to do this:
def is_cool(kid):
cool_kids = {"Jim","Bill","Nebuchadnezzar II"}
return kid in cool_kids
Do I have to inherit Kid from str?
ADD 1: I know I can write return kid.name in cool_kids, but I am looking for a little syntax sugar for my code. I want a way to check for obj in set of very different objects.
How about this:
class Kid():
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other
def __ne__(self, other):
return not self.name == other
def __hash__(self):
return hash(self.name)
def is_cool(kid):
cool_kids = {"Jim","Bill","Nebuchadnezzar II"}
return kid in cool_kids
if __name__ == "__main__":
print is_cool(Kid("Bob"))
print is_cool(Kid("Jim"))
print is_cool(Kid("Bill"))
Result:
False
True
True
You need to override both __eq__ and __hash__, because both need to be satisfied from an element to be member of a hashtable. When Python evaluates if an element is a member of a hashtable, it first looks at whether hash matches, and if it does then it looks at equality. Overriding __ne__ is not necessary for this example, but it is a good practice to do so, you don't want equals and not equals to be out of sync.
You can do it like this:
class Kid:
def __init__(self, name):
self.name = name
def is_cool(kid):
cool_kids = {"Jim", "Bill", "Nebuchadnezzar II"}
return kid.name in cool_kids
print(is_cool(Kid("Daniel")))
print(is_cool(Kid("Jim")))
Output
False
True
Your code has a few issues, you need to remove the parenthesis from the Kid class definition and change the method __init to __init__ passing self as the first parameter.
UPDATE
If you want to inherit from str you can do it like this:
class Kid(str):
def __new__(cls, *args, **kw):
return str.__new__(cls, *args, **kw)
def is_cool(kid):
cool_kids = {"Jim", "Bill", "Nebuchadnezzar II"}
return kid in cool_kids
print(is_cool(Kid("Daniel")))
print(is_cool(Kid("Jim")))
Output
False
True
You can find more about inheriting from str here
I suspect that the following will do what you wish:
def is_cool(kid):
cool_kids = {"Jim","Bill","Nebuchadnezzar II"}
return kid.name in cool_kids
Related
I have a class which has its own methods, for example:
class Original():
def __init__(self, dummy=False):
self.dummy = dummy
def funcA(self):
print('funcA')
And I want that, in case the variable dummy is true, all the custom made functions from class Original (e.g., funcA) become dummy (i.e., don't do nothing and return nothing).
I have managed to do a dummy class like this:
class Dummy(object):
def dummy(*args, **kwargs):
pass
def __getattr__(self, _):
return self.dummy
a = Dummy()
a.asd() # returns nothing
However, I can't manage to make a class in which the writen functions work in case the variable dummy is False, and they don't if the variable is True.
Any help please?
Managed to figure it out based on Alex Hall's comment. Hope this helps anyone out there:
class Dummy(object):
def __init__(self, isDummy):
self.isDummy = isDummy
def dummy(*args, **kwargs):
pass
def __getattribute__(self, item):
if item in ['isDummy', 'dummy'] or self.isDummy is False:
attr = object.__getattribute__(self, item)
return attr
else:
return self.dummy
def funcA(self):
print('funcA')
print('Dummy:')
dummy = Dummy(isDummy=True)
dummy.funcA() # returns nothing
print('---')
print('nonDummy:')
nonDummy = Dummy(isDummy=False)
nonDummy.funcA() # prints 'funcA'
I would like to implement a function which is similar to getattr but will accept a dotted string and traverse through each attributes.
def getattr_multiple_level(obj, attr_string):
attr_names = attr_string.split('.')
next_level = obj
for attr_name in attr_names:
next_level = getattr(next_level, attr_name)
return next_level
class Test():
def make_name(self, pre, suffix=""):
return str(pre) + "_my_office_" + suffix
p = Test()
p.room = Test()
p.room.office = Test()
attr = getattr_multiple_level(p, 'room.office.make_name')
Is there already a built-in way to do this? Or what improvements can be made in above code to handle all possible exceptions and edge cases?
Yes, there is "build-in way". You can use property decorator. https://docs.python.org/2/library/functions.html#property
class Author(object):
def __init__(self, full_name):
self.full_name = full_name
class Book(object):
def __init__(self, name):
self.name = name
#property
def author(self):
return Author("Philip Kindred Dick")
class Library(object):
#property
def book_ubik(self):
return Book("ubik")
library = Library()
print(library.book_ubik.name)
print(library.book_ubik.author.full_name)
Result:
grzegorz#grzegorz-GA-78LMT-USB3:~/tmp$ python3 propery_test.py
ubik
Philip Kindred Dick
I am trying Overloading an operator forcing it to return an object of the same instance of the current class not the parent class where the method was overloaded.
class Book:
def __init__(self,name,pages):
self.name=name
self.pages=pages
def __add__(self,other):
return Book(self.name,(self.pages + other.pages))
class Encyclopedia(Book):
def __init__(self,name,pages):
Book.__init__(self,name,pages)
a=Encyclopedia('Omina',234)
b=Encyclopedia('Omnia2',244)
ab=a+b
print ab
Out: <__main__.Book instance at 0x1046dfd88>
For instance in this case I would like to return an Encycolpedia instance (not a Book instance) without overloading another time the operator __add__ with the same line with Encyclopedia instead of Book I have tried:
return self(self.name,(self.pages + other.pages))
But it doesn't work.
What if the Class Enclcopedia has another attribute:
class Encyclopedia(Book):
def __init__(self,name,pages,color):
Book.__init__(self,name,pages)
self.color=color
You could utilize self.__class__ instead of casting to Book. Your original add function should look like:
def __add__(self,other):
return self.__class__(self.name,(self.pages + other.pages))
You would need to do it something like this, which overloads the base class's methods (in this case, generally by calling them first and then doing additional processing on the result — although that's not a requirement):
class Book(object):
def __init__(self, name, pages):
self.name = name
self.pages = pages
def __add__(self, other):
return Book(self.name, self.pages+other.pages)
def __str__(self):
classname = self.__class__.__name__
return '{}({}, {})'.format(classname, self.name, self.pages)
class Encyclopedia(Book):
def __init__(self, name, pages, color):
Book.__init__(self, name, pages)
self.color = color
def __add__(self, other):
tmp = super(Encyclopedia, self).__add__(other)
return Encyclopedia(tmp.name, tmp.pages, self.color+other.color)
def __str__(self):
classname = self.__class__.__name__
return '{}({!r}, {}, {!r})'.format(classname, self.name, self.pages,
self.color)
a = Encyclopedia('Omina', 234, 'grey')
b = Encyclopedia('Omnia2', 244, 'blue')
ab = a+b
print(ab) # -> Encyclopedia('Omina', 478, 'greyblue')
I have a graph class that uses an adjacency list to keep track of vertices and edges, as well as a vertex class with a predefined hash function that looks like the following:
class Vertex():
def __init__(self, name):
self.name = name
def __hash__(self):
return hash(self.name)
Essentially, in my Graph class, I have a method called addVertex that takes in a vertex object and checks to see if it exists in the Graph already before adding it. If it does already exist, I want to return the object that is already in the graph, not the parameter I passed into the method. How would I go about implementing this?
class Graph():
def __init__(self):
self.adjList = {}
def addVertex(vertex):
try:
self.adjList[vertex]
return ???????????
except:
self.adjList[vertex] = {}
return vertex
Just use a membership test:
if vertex in self.adjList:
The dict.__contains__ implementation will then use the __hash__ special method automatically.
Note that your Vertex class must also implement a __eq__ equality method:
class Vertex():
def __init__(self, name):
self.name = name
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
return self.name == other.name
suppose I have a class:
class Cat:
def __init__(self, name = "default", age = 0):
self.name = name
self.age = age
I also have a list of Cats:
l = [Cat('Joe')]
Now I can't call the following:
if 'Joe' in l: # the right syntax would be if Cat('Joe') in list
Which operator do I need to overload to be able to identify objects of class Cat by their member variable name?
You have to define the __eq__ method, as shown below:
class Cat:
def __init__(self, name = "default", age = 0):
self.name = name
self.age = age
def __eq__(self, other):
if isinstance(other, str):
return self.name == other
elif isinstance(other, Cat):
return self.name == other.name
So that when you run your check:
l = [Cat('Joe')]
'Joe' in l
#True
__contains__ on list objects is implemented by checking for equality, so override __eq__:
class Cat:
def __init__(self, name = "default", age = 0):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other
This works irrespective of ordering because equality checking swaps its arguments when the left side does not support the operation.
If you want it to work with hash-based containers (e.g. set, dict) you'll have to override __hash__ as well:
def __hash__(self):
return hash(self.name)