Reputation: 1742
I am trying to understand why a function would work as an external function, but won't work if I move it into the class as a method.
Quickly I created a Linked list class:
class Link:
"""A linked list."""
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __str__(self):
string = '<'
while self.rest is not Link.empty:
string += str(self.first) + ', '
self = self.rest
return string + str(self.first) + '>'
so when I try to create a function called stretch, so that I can:
def stretch(s, repeat=0):
"""Replicate the kth element k times, for all k in s."""
if s is not Link.empty:
stretch(s.rest, repeat+1)
for i in range(repeat):
s.rest = Link(s.first, s.rest)
It worked:
a = Link(3, Link(4, Link(5, Link(6))))
print(a) # >>> <3, 4, 5, 6>
stretch(a)
print(a) # >>> <3, 4, 4, 5, 5, 5, 6, 6, 6, 6>
However, when I try to create this function as a class method:
def stretch(self, repeat=0):
"""Replicate the kth element k times, for all k in a linked list."""
if self is not Link.empty:
self.rest.stretch(repeat+1)
for i in range(repeat):
self.rest = Link(self.first, self.rest)
Now it won't work:
b = Link(3, Link(4, Link(5, Link(6))))
b.stretch()
print(b)
# >>> AttributeError: 'tuple' object has no attribute 'stretch'
I understand that when b
get to the last element, b.rest
will be an empty tuple, but in the method, it says if self is not Link.empty
it should not execute anything. Why is it giving me error message?
Thanks!
Upvotes: 0
Views: 50
Reputation: 308412
The first function works whether s
passed to stretch
is either a Link
object or Link.empty
.
The second member function doesn't work when the object is Link.empty
, because Link.empty
is a tuple that doesn't have the method. You never even make it into the function where your if
would catch it.
You need to move the if
outside, before the call.
Upvotes: 1
Reputation: 57085
The problem happens on the line self.rest.stretch(repeat+1)
. Since you do not pass the second parameter to the constructor in Link(3, Link(4, Link(5, Link(6))))
, the default value of ()
is used to initialize the field self.rest
, and the value of this field never changes thereafter. Thus, self.rest.stretch(repeat+1)
is actually ().stretch(repeat+1)
. Naturally, ()
, an empty tuple, does not have the attribute stretch
.
The first function works because it does not have the offending statement.
Upvotes: 1