-1

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.

  • 2
    What do you mean `syntax sugar`? returning `kid.name in cool_kids` is by far the simplest solution. – N Chauhan Aug 30 '18 at 18:25
  • 1
    Possible duplicate of [add object into python's set collection and determine by object's attribute](https://stackoverflow.com/questions/10547343/add-object-into-pythons-set-collection-and-determine-by-objects-attribute) – mkrieger1 Aug 30 '18 at 18:28
  • Because I simplified my question. My actual Kid has no member `name` or function `name()`, I can compare Kid to str but I can not generate name because comparison requires regexp juggling. –  Aug 30 '18 at 18:30
  • Could you add a more complex example in order to better understand your context and your issue? – abc Aug 30 '18 at 18:34

3 Answers3

1

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

Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
1

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.

Akavall
  • 82,592
  • 51
  • 207
  • 251
  • Yes. This is what solves my simplified example. Unfortunately, in real case I can not provide meaningful `hash` because Kids names aren't necessary an exact match. So this is impossible. I can live without it, I only wanted to have less explicit loops in code. –  Aug 30 '18 at 18:43
  • @BarafuAlbino, I don't think you can do what you are looking for with `hash`, you could do something like that with `__eq__`, then iterate over you set of elements and compare each with `kid` instance. This, however, will make your `is_cool` function O(n) as opposed to O(1) like it is now. – Akavall Sep 01 '18 at 03:41
-1

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
hd1
  • 33,938
  • 5
  • 80
  • 91