Reputation: 11543
I have following code:
class Foo(object):
def __init__(self):
baz=self.bar(10)
@staticmethod
def bar(n):
if n==0:
return 'bar'
else:
return bar(n-1)
bar() as a recursive function it needs reference to itself. However, bar() is inside a class, and calling return bar(n-1)
will not work, invoking NameError: global name 'bar' is not defined
. How can I deal with this kind of situation? Should I change bar() to a class or instance method, allowing access to self
or cls
?
Upvotes: 31
Views: 18235
Reputation: 1297
If the main goal is to run a recursive method, you can use plain methods for this.
I actually never saw the use for this until now. lets say you have integer thresholds you need to test, this pattern can be quite nice and easy: ( even though it can create a bit overheat, so be cautious)
class Foo(object):
def __init__(self, n):
self.baz = self.bar(n)
def bar(self, n):
if n < -10:
return 'bar < -10'
if n == -10:
return 'bar -10 - -1'
if n == 0:
return 'bar 0 - 9'
if n == 10:
return 'bar 10 - 19'
if n >= 20:
return 'bar >= 20'
return self.bar(n-1)
Upvotes: 0
Reputation: 2923
You can define bar() outside of Foo and then bring it in as a staticmethod so that you get all of the benefits of it being a method of the class while not having to close it or reference the class itself. I have needed something like this for class inheritance reasons.
def bar(n):
if n==0:
return 'bar'
else:
return bar(n-1)
class Foo(object):
bar = staticmethod(bar)
def __init__(self):
baz=self.bar(10)
Upvotes: 6
Reputation: 184345
An alternative to using a class method or calling the class by name (as shown by others) is to use a closure to hold the reference to the function:
class Foo(object):
def bar():
def bar(n):
if n == 0:
return "bar"
return bar(n-1)
return bar
bar = staticmethod(bar())
The (minor) advantage is that this is somewhat less susceptible to breaking when names change. For example, if you have a reference to Foo.bar
inside bar
, this relies on Foo
continuing to be a global name for the class that bar
is defined in. Usually this is the case but if it isn't, then the recursive call breaks.
The classmethod
approach will provide the method with a reference to the class, but the class isn't otherwise needed in the method, which seems inelegant. Using the closure will also be marginally faster because it isn't doing an attribute lookup on each call.
Upvotes: 13
Reputation: 1124020
You can refer to bar
by prefixing it with the class name:
class Foo(object):
def __init__(self):
baz=self.bar(10)
@staticmethod
def bar(n):
if n==0:
return 'bar'
else:
return Foo.bar(n-1)
Static methods are nothing but regular functions contained within the namespace of a class after all.
Alternatively, define bar
as a regular function instead:
def bar(n):
if n==0:
return 'bar'
else:
return bar(n-1)
class Foo(object):
def __init__(self):
baz=bar(10)
which avoids the whole issue altogether.
Upvotes: 61
Reputation: 6004
What about that?
class Foo(object):
def __init__(self):
baz = self.bar(10)
@classmethod
def bar(cls, n):
if n == 0:
return 'bar'
else:
return cls.bar(n-1)
Upvotes: 9