views:

176

answers:

5

I've wondered why extend/append methods of Python don't return a reference to result list. To build string of all combination of list with last element, I would like to write simple:

for i in range(l, 0, -1):
    yield " ".join(src[0:i-1].append(src[-1]))

But I've got: TypeError. Instead following code with intermediate variable is used:

 for i in range(l, 0, -1):
        sub = src[0:i-1]
        sub.append(src[-1])
        yield " ".join(sub)

Correct me please if I'm wrong

+1  A: 

The general reasoning is that the return type in None to indicate the list is being modified in-place.

Hank Gay
Yes. I understand this, but question is about more shorter way to deal with combined list. In c/c++ I could use operator "," - to exec multiple operations before result is calculated. What does Python provides instead?
Dewfy
A: 
for i in range(l-1, 0, -1):
    yield ' '.join(src[:i] + src[-1:])

will do.

Extend/append methods modify list in place and therefore don't return the list.

SilentGhost
I think there's an error - "+" operator joins two lists, doesn't append an element to a list.
Rafał Dowgird
It also causes "TypeError"
Dewfy
yeah, it was fixed before you posted the comment.
SilentGhost
Thanks in anyway
Dewfy
Is "for i in range(l, 0, -1):" supposed to iterate over all the indexes in src in reverse order? This would be better: "for i in reversed(range(len(src))):" and it would hit the 0 index as well.
hughdbrown
Sorry. Meant to comment below -- it really follows OP's comment on my question.
hughdbrown
+1 for trolling j/k
kaizer.se
+7  A: 

Hm, maybe replace:

src[0:i-1].append(src[-1])

with:

src[0:i-1] + src[-1:] #note the trailing ":", we want a list not an element
Rafał Dowgird
A: 

To operate on the list and then return it, you can use the or construction:

def append_and_return(li, x):
  """silly example"""
  return (li.append(x) or li)

Here it is so that X or Y evaluates X, if X is true, returns X, else evaluates and returns Y. X needs to be always negative.

However, if you are only acting on a temporary list, the concatenation operation already suggested is just as good or better.

Edit: It is not worthless

>>> li = [1, 2, 3]
>>> newli = append_and_return(li, 10)
>>> li
[1, 2, 3, 10]
>>> newli is li
True
kaizer.se
append always returns `None`. You're code is rather useless.
SilentGhost
sure, when you change you code it becomes *not* useless.
SilentGhost
SilentGhost, stop trolling please. I didn't change the code, I changed my comments since I made a thinko. It said X has to be always True but I meant X has to be always false (since we want to return Y) here. The code didn't change.
kaizer.se
code changed twice, from simple line of code to a function. from `or x` to `or li`.
SilentGhost
and? the x -> li was an obvious typo. Stop trolling. This is an answer that does exactly what the questioner asked. That's worth -1?
kaizer.se
does my answer worth -1?
SilentGhost
+7  A: 

The reason mutating methods in Python do NOT return a reference to the object they've mutated can be found in the Command-Query Separation principle (CQS for short). Python does not apply CQS as thoroughly as Meyer's Eiffel language does (since -- as per the Zen of Python, aka import this, "practicality beats purity"): for example, somelist.pop() does return the just-popped element (still NOT the container that was just mutated;-), while in Eiffel popping a stack has no return value (in the common case in which you need to pop and use the top element, your first use a "query" to peek at the top, and later a "command" to make the top go away).

The deep motivation of CQS is not really "mutators should return nothing useful": rather, it's "queries should have no side effect". Keeping the distinction (be it rigidly or "as more of a guideline than a rule") is supposed to help you keep it in mind, and it does work to some extent (catching some accidental errors) though it can feel inconvenient at times if you're used to smoothly flowing "expressions and statements are the same thing" languages.

Another aspect of CQS (broadly speaking...) in Python is the distinction between statements and expressions. Again, that's not rigidly applied -- an expression can be used wherever a statement can, which does occasionally hide errors, e.g. when somebody forgets that to call a function they need foo(), NOT just foo;-). But, for example (and drastically different from C, Perl, etc), you can't easily assign something while at the same testing it (if(a=foo())...), which is occasionally inconvenient but does catch other kinds of accidental errors.

Alex Martelli