-1

I want to write a preorder recursion of a tree in python. I can use for statement, but if I use list comprehension, I hope to achieve the recursive effect through its side effects, why it doesn't?

this method works:

def preorder(t):
    ret = [label(t)]
    for branch in branches(t):
    ret.extend(preorder(branch))
    return ret

but this didn't give me proper result.

def preorder(t):
    ret = [label(t)]
    a = (ret.extend(preorder(b)) for b in branches(t))
    return ret

with the second method:

T = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])])
preorder(T)

the return is only[1]

Detail of tree ADT

def tree(label, branches=[]):
    """Construct a tree with the given label value and a list of branches."""
    for branch in branches:
        assert is_tree(branch), 'branches must be trees'
    return [label] + list(branches)


def label(tree):
    """Return the label value of a tree."""
    return tree[0]


def branches(tree):
    """Return the list of branches of the given tree."""
    return tree[1:]

  • Can you show the code that includes the list comprehension you are trying? None of the code in the current question has a listcomp. – slothrop Apr 23 '23 at 15:26
  • There are no list comprehensions here. Your working and non-working examples are equivalent (ignoring various indentation issues that would prevent *either* from executing at all). – chepner Apr 23 '23 at 15:26
  • sorry, here i changed the code, i did't post list comprehension i'm trying before – Callum Ethan Apr 23 '23 at 15:30
  • 2
    What is `x` in your function? – slothrop Apr 23 '23 at 15:31
  • @slothrop sorry, it's ret – Callum Ethan Apr 23 '23 at 15:32
  • 2
    It looks like your first two snippets should be equivalent (assuming there is no indentation error in the first). How do you know that the second `"didn't give me proper result"`? – quamrana Apr 23 '23 at 15:35
  • @chepner sorry, could you please see it again, i just edited the code properly, thanks. – Callum Ethan Apr 23 '23 at 15:35
  • 1
    Although it's considered a bad idea to use listcomps for their side effect (https://stackoverflow.com/questions/5753597/is-it-pythonic-to-use-list-comprehensions-for-just-side-effects), Python doesn't prevent it. So as quamrana said, it would help to know more about what isn't working. – slothrop Apr 23 '23 at 15:36
  • @quamrana the function of the second snippet only returns the label of the root, not including the branches – Callum Ethan Apr 23 '23 at 15:37
  • Please update your question with a complete example which shows this. – quamrana Apr 23 '23 at 15:38
  • @slothrop Thankyou, i had read about the article that you mentioned, although I know it's not good, i want to figure out why my second method does't work properly(not good but should have worked...) – Callum Ethan Apr 23 '23 at 15:39
  • @quamrana here i added the example – Callum Ethan Apr 23 '23 at 15:43
  • 3
    I get the same result with both versions. – quamrana Apr 23 '23 at 15:44
  • 1
    I can't reproduce the issue. I get `[1, 2, 3, 4, 5, 6, 7]` with your listcomp code – slothrop Apr 23 '23 at 15:44
  • 3
    Strictly speaking, list comprehensions do not have a side effect; it's `ret.extend` that has a side effect of mutating `ret` in place, regardless of where it gets called. As others have pointed out, I cannot reproduce the difference you claim to see. – chepner Apr 23 '23 at 15:45
  • Listcomp version giving `[1, 2, 3, 4, 5, 6, 7]` - [Try it online!](https://tio.run/##dZHLasMwEEX3@orBK4ua0DR9QCCr/kHJTmghx@NaYCQjj9P26109LDsE4o2Hqzv3zEjDH3XWHOa5wRYGh9Y16EriRwb@c0hwAtGrGnsvyigKr@7wl9A05dpRcw6tdVCDNlA7ZS4djmuL75icCT/GAogcYhlTq9V8EnKhFkXxac1IbroQqGiGH00dUIfwra9oIPbCVfUTgjKNd/V6JLDtGrfzKbfstISEp@gss42zNNGyokdtQ3ylzkC95XlIGuoeETTxLJfE7RIeht6NHOptxYeE/TEgzv5h4jXuKxCxeOFVUg5Zec3KG5e5fM@HH16TnA1OG9re8cz5PP8D "Python 3 – Try It Online") – slothrop Apr 23 '23 at 15:46
  • In your updated code, you create a generator `a` but don't iterate over it. So `extend` is never executed – slothrop Apr 23 '23 at 15:48
  • i see, if i changed the second method to a() instead of [], it doesn't work. – Callum Ethan Apr 23 '23 at 15:49
  • @slothrop does my updated code run the for expression, or it just creats the a but didn't use it? – Callum Ethan Apr 23 '23 at 15:50
  • 1
    Right, which is expected for the reason I just explained. But it doesn't explain why you found the code wasn't working when it was a list comp. – slothrop Apr 23 '23 at 15:50
  • 1
    It creates a generator but doesn't iterate over it, so the code within the generator isn't executed. – slothrop Apr 23 '23 at 15:51
  • @slothrop i have tried the [...] comprehension just now and it does work properly, thank you. By the way, the reason why the updated version doesn't work is () or that i let "a" equal to it? – Callum Ethan Apr 23 '23 at 15:52
  • 1
    It's the difference between the `()` (generator comprehension) and `[]` (list comprehension) – slothrop Apr 23 '23 at 15:53
  • I got it! Thank you! It bothers me for a long time. – Callum Ethan Apr 23 '23 at 15:54

1 Answers1

0

Thankyou for everyone on the comment. Here i know

(expression for item in Sequence )

is a gernerator comperhension, which returns a generator, if i did't call it,(iterate over it), it will do nothing. but list comprehension as below creats a list but also have side-effect:

[expression for item in Sequence]

to make the () work, i can:

def preorder(t):
    ret = [label(t)]
    a = (ret.extend(preorder(b)) for b in branches(t))
    for _ in a:
        continue
    return ret

This will give me the right answer as well as:

def preorder(t):
    ret = [label(t)]
    [ret.extend(preorder(b)) for b in branches(t)]
    return ret

Nevertheless, it is not a good way to rely on the side-effect of a list comprehension, to see detail: Is it Pythonic to use list comprehensions for just side effects?