Python Forum

Full Version: Why does Function behave differently in a class vs. outside a class?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
# Why does this function behave differently in a class vs. outside a class?
class Test():
    def add_person(element, lineage=[]):
        lineage.append(element)  # AttributeError:  'str' object has no attribute 'append'
        return lineage
z = Test()
g = z.add_person("Test1")
h = z.add_person("Test2")
t = z.add_person("Test3")
print(g, h, t)
# >>Output:
# AttributeError: 'str' object has no attribute 'append'

def add_person3(element, lineage=[]):
    lineage.append(element)
    return lineage

d = add_person3("1")
e = add_person3("2")
f = add_person3("3")
print(d, e, f)

# >>Output:
# # >>Output: 
# ['1', '2', '3'] ['1', '2', '3'] ['1', '2', '3']
first of all your class is wrong. in order to work (although not as you would expect) it should be like this

 
class Test():
    @staticmethod
    def add_person(element, lineage=[]):
        lineage.append(element)  # AttributeError:  'str' object has no attribute 'append'
        return lineage
z = Test()
g = z.add_person("Test1")
h = z.add_person("Test2")
t = z.add_person("Test3")
print(g, h, t)
you should understand the difference between instance and class methods and properties, which is advanced OOP topic
https://docs.python.org/3/tutorial/class...at-classes
https://stackoverflow.com/a/7554899/4046632
https://stackoverflow.com/a/12179752/4046632

As to the result that differ from what you expect see
http://docs.python-guide.org/en/latest/writing/gotchas/
Change the method like this:

class Test():
    @staticmethod
    def add_person(element, lineage=[]):
        lineage.append(element)  # AttributeError:  'str' object has no attribute 'append'
        return lineage
[code] [/code]
 
Just to add, that you need to start with class basics before you start with more advanced topics. it looks like you are still not comfortable with the basics of OOP
Another pitfall is the default argument: lineage=[]
If you use this in a function definition, it's evaluated and the object is added to the function.

Lists are mutable objects. If you don't use an argument for lineage, lineage.append(element) appends to the list,
which is inside the function. This means that all future calls do have the same list object, if you don't supply
the lineage keyword with your own new list.

You can prevent this:

def wrong_way(n, some_list=[]):
    some_list.append(n)
    return some_list

def right_way(n, some_list=None):
    if not some_list:
        some_list = [] # this here creates every time a new list, if called without some_list
    some_list.append(n)
    return some_list
To test what happens, do following:

wrong_way(1)
wrong_way(2)
wrong_way(3)
Look what happens with the output.

Repeat this, with the second function:

right_way(1)
right_way(2)
right_way(3)
This version does not return the past elements which were added before.