#๐ Visualizing a tree
79 messages ยท Page 1 of 1 (latest)
@lunar jetty
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
A recursive function that formats it as a branching tree is actually a great practice mini-project.
Like shown on the right here: https://ascii-tree-generator.com/
Online interactive folder structure generator. Easily create and visualise your development tree for your new projects and your documentations.
Have you worked with recursion before?
For a simpler method regarding implementation: you can just implement pre-order, in-order, and post-order tree traversals and use these to identify what the tree looks like.
Also using a debugger can help immensely
Yeah I have
True but then Iโd have to decipher it kind of on my own right
Based on all the traversals
For the recursive approach where I print the tree, I would want pre order right
I guess Iโve never done a traversal of a non binary tree
But itโs probably the same concept right
(Tries are not binary)
Yeah, probably there's no really such a thing as an in-order traversal for a trie. But pre-order and post-order should still work fine
For me the quick thing (with any tree) is a recursive walk of the tree, passing an "indent" argument, default (and thus initially) 0. Call:
print(" "*indent, ...the-node...)
and then call traverse on each subnode with an increased indent value, +1 or +2 or such.
You can always sort the subnode values for a nice ordering.
@lunar jetty ^^
okay cool thats kinda what i was thinking
instead of just passing the subtree you need to pass the depth as well
Yes., that's effective what the indent is.
yup
Does print have some prefix argument, smth like end, but for the beginning of the string?
No.
Meh, ok
It only has sep, end and file
end probably only exists because you typically want to end in a newline, but also want that to be overrideable. You typically don't want to prefix something before every print, so there's nothing to override.
ill overload the print funtion and add a prefix argument ๐
Very sound.
(I actually do overload print in some of my programmes which has a "live" display, like a status bar and progress bars etc. Undraw them all, do the print, redraw below.)
I tried to do it myself, too. It was one of my first, if not my first, actual small project with Python: https://github.com/SamuelRoettgermann/temporary-print/tree/main
Yes. You would usually want to keep the old print for use.
builtin_print = print
def print(......):
builtin_print(.....)
For added fun you can monkeypatch builtins.print to affect most other prints.
can you not use the built in print function just by using print()? since it has different arguments it wont use the overloaded one?
No.
ah why not
You've rebound the name print.
So saying print now finds your new function.
There's no "overloading" like you might find in a polymorphic language.
wait can you literally not do that in python
where the same name refers to 2 functions
depending on arguments
You have to do the same result by other means.
no
wow i didnt know that
Yeah. Instead you have to have the function figure that out itself.
Assuming you go that route.
ah so when i overload the addition operator in cpp, i cant do it the same way in python
thats when you use dunder methods?
Yeah.
A dunder method is what implements (typically) an operator. FOr a specific class.
So a + b calls type(a).__add__(a,b)
i see
So if a references an int, it runs int.__add__
interesitng
like i knew that
but i didnt realize it was replacing the overloading i was used to
but like obviously it is
Yeah. Different languages.
A def is really just a fancy assignment statement, rebinding the function name. So is an import.
The way Python does that is by giving you the option to specify default arguments, e.g.:
def f(x: int = 4, y: str = "abc")
...
# all valid
f(2, 'x')
f(4)
f()
And if you want alternating types... well:
def f(x: int | str | None = None):
if isinstance(x, int):
...
elif isinstance(x, str):
...
else:
...
```That's one way to do it
Yes.
But python doesn't have a "switch the function based on the call signature". i.e. no overloading. It's just one function. If it receives different types, handling them is up to that single function.
Yeah, but C++ is different, because there a function is uniquely identified by it's name and its parameters. In Python there's just a single variable that's identified by name
because everything in python is an object?
Not sure if that's really the "why", but it doesn't sound completely impossible
fair enough
I've got an @promote decorator I use for "promoting" specific parameters. Eg:
@promote
def url_entity(self, url: URL):
''' Return the `SiteEntity` associated with this URL, or `None`
for an unrecognised URL.
Here an URL is a class for URLs, with various convenient methods and attributes. @promote will turn eg a str into URL so the function receives a URL.
Lets me call it with either a URL object or a string like "https://......"
It effectively does that instance stuff Monke showed earlier, then calls the original function.
No, because names just refer to objects (eg a function) and calling a function is based entirely on what the name references. So there's no "multiple functions" to pick.
You could make a wrapper which did that fanout though, returning a single function which examining its arguments and calls other functions.
Also in C++ you can't have a variable with multiple possible types.
*That's only partially correct because there is std::variant which allows you to "group" a bunch of types... It'd look like so:
void f(std::variant<int, std::string> *x = nullptr) {
if (!x) {
// None case in Python
} else if (std::holds_alternative<int>(*x)) {
int value = std::get<int>(*x);
// ...
} else if (std::holds_alternative<std::string>(*x)) {
auto value = std::get<std::string>(*x);
// ...
}
}
In that code, the type of x would be unique. Namely the type of x would be a "raw pointer to a std::variant<int, std::string>"
or for simple cases, you could use the one that's provided already ๐
https://docs.python.org/3/library/functools.html#functools.singledispatch
multiple dispatch can be thought of as just a combination of single dispatches, but to make that sort of thing work you're probably also getting into a lot of complicated functools.partial etc. work. Still...
This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.