#๐Ÿ”’ Visualizing a tree

79 messages ยท Page 1 of 1 (latest)

lunar jetty
#

I'm using a data structure called a trie, which is a type of tree. When I construct a trie its hard to know if I'm doing it correctly without any way to actually print out or view the data structure. How would I go about viewing it for debugging purposes.

fading hareBOT
#

@lunar jetty

Python help channel opened

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.

obsidian storm
#

A recursive function that formats it as a branching tree is actually a great practice mini-project.

lunar jetty
#

interesting

#

i may be able to make something like that

obsidian storm
#

Have you worked with recursion before?

hardy summit
#

Also using a debugger can help immensely

lunar jetty
lunar jetty
#

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)

hardy summit
#

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

round star
#

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 ^^

lunar jetty
#

okay cool thats kinda what i was thinking

#

instead of just passing the subtree you need to pass the depth as well

round star
#

Yes., that's effective what the indent is.

lunar jetty
#

yup

hardy summit
round star
#

No.

hardy summit
#

Meh, ok

round star
#

It only has sep, end and file

obsidian storm
#

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.

lunar jetty
#

ill overload the print funtion and add a prefix argument ๐Ÿ˜‰

round star
#

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.)

lunar jetty
#

i dont know how to actually overload it

#

is it as easy as def print():

hardy summit
round star
#

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.

lunar jetty
#

can you not use the built in print function just by using print()? since it has different arguments it wont use the overloaded one?

round star
#

No.

lunar jetty
#

ah why not

round star
#

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.

lunar jetty
#

wait can you literally not do that in python

#

where the same name refers to 2 functions

#

depending on arguments

round star
#

You have to do the same result by other means.

hardy summit
lunar jetty
#

wow i didnt know that

round star
#

Yeah. Instead you have to have the function figure that out itself.

#

Assuming you go that route.

lunar jetty
#

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?

round star
#

Yeah.

#

A dunder method is what implements (typically) an operator. FOr a specific class.
So a + b calls type(a).__add__(a,b)

lunar jetty
#

i see

round star
#

So if a references an int, it runs int.__add__

lunar jetty
#

interesitng

#

like i knew that

#

but i didnt realize it was replacing the overloading i was used to

#

but like obviously it is

round star
#

Yeah. Different languages.

#

A def is really just a fancy assignment statement, rebinding the function name. So is an import.

hardy summit
# lunar jetty depending on arguments

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
lunar jetty
#

wowza

#

but c++ also has default arguments

round star
#

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.

hardy summit
#

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

lunar jetty
#

because everything in python is an object?

hardy summit
#

Not sure if that's really the "why", but it doesn't sound completely impossible

lunar jetty
#

fair enough

round star
#

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.

round star
#

You could make a wrapper which did that fanout though, returning a single function which examining its arguments and calls other functions.

hardy summit
# lunar jetty but c++ also has default arguments

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>"

crisp bison
# round star You _could_ make a wrapper which did that fanout though, returning a single func...

or for simple cases, you could use the one that's provided already ๐Ÿ˜‰
https://docs.python.org/3/library/functools.html#functools.singledispatch

Python documentation

Source code: Lib/functools.py The functools module is for higher-order functions: functions that act on or return other functions. In general, any callable object can be treated as a function for t...

#

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...

fading hareBOT
#
Python help channel closed for inactivity

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.