1

I have this code:

class Pet(object):

    def __init__(self,name=""):
        self.name = name 
        self.kind = "Unknown"
        self.toys = []  
    def add_toys(self,toys):
        new_list = []
        for toy in self.toys:
            if toy not in new_list:
                new_list.append(toy)   
        return new_list
    def __str__(self):
        toys_list = add_toys(self,toys)  
        if self.toys == []:
            return "{} is a {} that has no toys".format(self.name,self.kind)
        else:
            return "{} is a {} that has the following toys: {}".format(self.name,self.kind,toys_list)     

In the function add_toys() I have the return value new_list. I want to use that return value in the function __ str__ and define it as toys_list. However, when I write toys_list = add_toys(self, toys) it says that:

add_toys is an undefined variable

hc_dev
  • 8,389
  • 1
  • 26
  • 38
  • 2
    I am not fully sure what you are trying to achieve, but for the error where you say "it says that add_toys is an undefined variable.", I believe you need `self.add_toys`. – Dimitar Hristov Apr 10 '21 at 13:26
  • Does this answer your question? [function name is undefined in python class](https://stackoverflow.com/questions/28805028/function-name-is-undefined-in-python-class) – Tomerikoo Apr 10 '21 at 13:36

4 Answers4

4

Your add_toys method isn't good, you're not using the toys parameters and it shouldn't return anything, it should be like

class Pet:
    # __init__ is OK

    def add_toys(self, *toys):
        for toy in toys:
            if toy not in self.toys:
                self.toys.append(toy)

    def __str__(self):
        if not self.toys:
            return "{} is a {} that has no toys".format(self.name, self.kind)
        else:
            return "{} is a {} that has the following toys: {}".format(self.name, self.kind, self.toys)

Use like

p = Pet("Foo")
p.add_toys("ball")
p.add_toys("plate", "frisbee")
print(p) # Foo is a Unknown that has the following toys: ['ball', 'plate', 'frisbee']

You could use directly a set

class Pet:

    def __init__(self, name, kind="Unknown"):
        self.name = name
        self.kind = kind
        self.toys = set()

    def add_toys(self, *toys):
        self.toys.update(toys)
azro
  • 53,056
  • 7
  • 34
  • 70
0

First thing in add_toys you are accesing toys variable from the class level variable, so remove that argument and the second is add_toys(self,toys) is not correct syntax, you will need to use it like self.add_toys()

class Pet(object):
    def __init__(self,name=""):
        self.name = name
        self.kind = "Unknown"
        self.toys = []
    
    def add_toys(self):
        new_list = []
        for toy in self.toys:
            if toy not in new_list:
                new_list.append(toy)
        return new_list
    
    def __str__(self):
        toys_list = self.add_toys()
        if self.toys == []:
            return "{} is a {} that has no toys".format(self.name, self.kind)
        else:
            return "{} is a {} that has the following toys: {}".format(self.name, self.kind, toys_list)

Alternative:

class Pet(object):
    def __init__(self,name=""):
        self.name = name
        self.kind = "Unknown"
        self.toys = []
    
    def add_toys(self, toys):
        new_list = []
        for toy in toys:
            if toy not in new_list:
                new_list.append(toy)
        return new_list
    
    def __str__(self):
        toys_list = self.add_toys(self.toys)
        if self.toys == []:
            return "{} is a {} that has no toys".format(self.name, self.kind)
        else:
            return "{} is a {} that has the following toys: {}".format(self.name, self.kind, toys_list)
Kumar Shivam Ray
  • 337
  • 2
  • 10
0

Issue is the undefined function. A referencing self (needed for each class member, field or method) was missing: toys_list = self.add_toys().

Reconsider design

Why have the collection of toys managed twice? (a) as field toys wich can have duplicates, (b) as return from add_toys which will hide duplicates and ensures unique elements.

You will have to maintain both in sync. They differ in their capabilities and should be applied to different use-cases.

Assumption: unique toys

I would also go with a set as type for the field toys directly. Because this way you can reuse an existing data structure which guarantees the uniqueness you have implemented explicitly in add_toys. Additionally the add/update function is convenient to modify the collection.

Improve: string building

Furthermore your string function can be refactored:

def __str__(self):
    subject = "{} is a {}".format(self.name, self.kind)
    hasToys = "has no toys" if not self.toys else "has the following toys: {}".format(self.toys)
    return "{subject} that {hasToys}".format (subject, hasToys)

it uses a ternary operator instead of the if statement; with referencing (via self!) new set field directly: self.toys Plus a 3 step building to allow the single return as clearly visible expectation at the end.

hc_dev
  • 8,389
  • 1
  • 26
  • 38
-1

you can't call class method directly, you must call it using self.

like this ..

self.toys_list= self.add_toys(self, toys)
  • Can't we omitt the first argument `self` when inside the class: `self.add_toys( toys )` ? – hc_dev Apr 10 '21 at 14:53
  • yes, we can omitt that first argument ` self` , but i am talking about that `self.` which comes before method name, any method or variable under a class can't call directly, it leads to undefined error. we must have to call it using `self.` like `self.method_name()` and `self.variable_name` .. – Omkar Kalantre Apr 11 '21 at 15:50