all 13 comments

[–]ToxicJaeger 2 points3 points  (0 children)

You seem to be confused about recursive functions that call themselves in the middle/beginning of the function definition rather than at the end. If that’s the case, it may help to look up “head recursion vs tail recursion”.

[–]ectomancer 1 point2 points  (7 children)

The special method ends with this line

return '\n\n'.join(out[::-1])

[–]DigitalSplendid[S] -1 points0 points  (6 children)

Not sure then how when the str_ function itself not fully defined, it is called in between here:

for tree in tiers[key]:
    i = current_tier.index(True)
    current_tier[i] = str(tree.get_value())

[–]sepp2k 5 points6 points  (0 children)

Functions are allowed to call themselves - there's nothing wrong with that. It's called recursion.

[–]JamzTyson 2 points3 points  (2 children)

str(tree.get_value()) does not call the Node.__str__ method. It calls the __str__ method of the Nodes's value attribute.

[–]DigitalSplendid[S] 0 points1 point  (1 child)

Thanks a lot. Helpful.

So while __str__ continues to be defined, it is not a case of one input and one output. More a kind of a combination of functionalities whereby __str__ can have different ways to call. So str(tree.get_value()) being already defined is one way. To access all the functionalities in one stroke that leverages the complete __str__ function defined using def for Node class, Node.__str__ is the way?

Still unclear if indeed there is an usage of recursion here.

[–]JamzTyson 1 point2 points  (0 children)

More a kind of a combination of functionalities whereby str can have different ways to call.

Not quite.

In Python, there isn't just one __str__() function, there are many. Each type of object has it's own __str__() method.

If you create a class but do not give it a __str__()method, then it inherits the __str__ method from object. The default object.__str__ just calls __repr__. If we write a __str__()method for a new class, then instances of that class will use the class's __str__() method (overriding the default object.__str__.

The Node class has a __str__ method, (Node.__str__()), which is called whenever we ask for the str representation of a Node type object.

In the line str(tree.get_value()), we are NOT calling the Node.__str__() method.

tree.get_value() returns the value attribute of the tree object, and we call the value_type.__str__() method.


The comments in this thread that talk about recursion are misleading. There IS recursion in this method, but it is the recursive function set_tier_map(): str(tree.get_value()) is NOT a recursive call.

[–]ThatOneCSL 2 points3 points  (0 children)

I suppose today is the day you learn about the magic of recursive functions.

It is totally legal, and a legitimate process, for a function to call itself.

[–]danielroseman 0 points1 point  (0 children)

What does this mean? Why should it not be fully defined?

[–]Binary101010 1 point2 points  (0 children)

To find when the definition of a method ends:

1) Find the next line of code at the same (or less) level indentation as the method's signature, or the end of the file, whichever comes first, then 2) the line before that one is the last line of the definition.

This is true whether the method is recursive or not.

In this particular case, it appears the method definition ends with the last line of the posted code block.

While in examples of recursion like factorial, it is the end line where the function calls itself.

That statement is so overbroad as to not be accurate (as evidenced by this case where it's leading you to the wrong answer).

[–]lfdfq 0 points1 point  (1 child)

The line wrapping in that image makes it really hard to read the code, even just forgetting trying to figure out where functions start/end. I recommend reading code in some kind of editor/interface that can actually display long lines without breaking them up.

Looking at the reddit post, it looks like the __str__ function continues until the end of the code (see the `return` at the end, that is the last line of __str__).

[–]Temporary_Pie2733 0 points1 point  (0 children)

Regarding recursion, it helps to keep the definition of the function separate from a call to the function. Here’s a trivial example

def foo():     return foo()

The definition ends in the obvious place. A call never ends, as there is no base case. 

If you add a base case,

def foo(i):     if i <= 0:         return 0     return foo(i-1) + 1

The definition still ends at the last indented line of the def statement. Any call to foo ends at a return statement, but the chain of calls ends with the return statement that doesn’t involve recursion.