Why Does My Python Code Output None Instead of the Next Permutation?

  • Context: Python 
  • Thread starter Thread starter member 428835
  • Start date Start date
  • Tags Tags
    Code Python
Click For Summary

Discussion Overview

The discussion revolves around a Python coding issue where a user is attempting to implement a function to find the next lexicographic permutation of a list of integers. The focus is on debugging the code, particularly why it outputs None instead of the expected result. Participants explore potential errors in the code, including issues with function returns and variable naming.

Discussion Character

  • Technical explanation
  • Debate/contested
  • Mathematical reasoning

Main Points Raised

  • One participant points out that the reverse function may not be returning a value, which could lead to the None output.
  • Another participant suggests that the reverse function should mutate the nums variable in place instead of returning a new value.
  • There are mentions of typos in the code, specifically the use of capital 'I' instead of lowercase 'i', which raises a NameError when the code is executed.
  • Some participants discuss the possibility that browser behavior may have altered the capitalization of variable names when posting the code.
  • A later reply indicates that adding a return statement to the reverse function resolved the issue for the original poster.
  • Participants express uncertainty about the exact cause of the capitalization issue, with suggestions that it may relate to BBCode formatting or JavaScript behavior in the forum editor.

Areas of Agreement / Disagreement

Participants generally agree that the code contains errors and that the reverse function's lack of a return statement is a significant issue. However, there is no consensus on the exact cause of the capitalization problem or how to best handle the reverse function's implementation.

Contextual Notes

Limitations include unresolved assumptions about the behavior of the reverse function and the impact of browser or forum software on code formatting. The discussion does not resolve the broader implications of these issues on coding practices.

  • #31
PeterDonis said:
Please post an explicit interactive session showing the case you are talking about. I have posted two interactive sessions showing what it actually takes to get Python to clone the elements of a list as well as the list itself, namely, copy.deepcopy. I am not aware of any other way of doing it.
For short lists, making copies isn't very inefficient, but you really shouldn't use deepcopy() if you don't have to.

720.000 iterations of nextpermutation(), starting with [1,2,3,4,5,6] took:
0.84s with the reverse function modifiying the list, and not returning anything from reverse()
0.91s with making a copy of the list with newlist = list[::]
1.06s using copy.copy() to make a copy of the list
3.81s using copy.deepcopy().
deepcopy still needs to examine all the objects in the list to see if any of them are lists , even if the result is the same as copy() for a list of numbers.
 
Technology news on Phys.org
  • #32
But the point is not really about cost, it is about the Principle of Least Astonishment.

If you have a function doSomethingToAList(list, moreArgs...) that does not return anything (or returns, say, an integer giving the number of entries that were affected) then it is clear that if it is going to work at all then it must mutate the list argument. You therefore know that if you don't want your list to be mutated you need to copy (or deepcopy) it first.

On the other hand you would expect a function extractMaximumValuesFrom(list, count) to return a new list with no more than [count] entries; you would NOT expect it to mutate the list argument.

pbuk said:
 
  • #33
pbuk said:
If you have a function doSomethingToAList(list, moreArgs...) that does not return anything (or returns, say, an integer giving the number of entries that were affected) then it is clear that if it is going to work at all then it must mutate the list argument. You therefore know that if you don't want your list to be mutated you need to copy (or deepcopy) it first.

On the other hand you would expect a function extractMaximumValuesFrom(list, count) to return a new list with no more than [count] entries; you would NOT expect it to mutate the list argument.
This assumes that knowing which option is the "least astonishment" option for a given function name is a simple thing. Is it?

The relevant function name in the OP is nextPermutation. Just looking at the name, would you expect this to mutate the list in place? Or would you expect it to return a new list containing the next permutation? I would expect the latter, but you were arguing earlier in the thread that this function should not return a value but should mutate the list in place, which seems to indicate that you would expect the former.
 
  • #34
PeterDonis said:
This assumes that knowing which option is the "least astonishment" option for a given function name is a simple thing. Is it?
Well-chosen names can help this.

PeterDonis said:
The relevant function name in the OP is nextPermutation.
No, the relevant function name is reverse:
pbuk said:
joshmccraney said:
Edit: all I changed was adding the return nums in the reverse function and it works. Thanks for bringing this to my attention! I appreciate it!
Yes but that was the wrong thing to fix, read on.

As this is a verb I would expect it to do something. It would be better named reversePart because that is what it does (and to avoid confusion with a list object's reverse method). A function that returned a part-reversed list would be better named getPartReversed.

PeterDonis said:
you were arguing earlier in the thread that this function should not return a value but should mutate the list in place
The point I was trying to make was that a function should not both mutate a list and return the mutated list; it should either mutate the list or return a new list. As a secondary point, I was arguing that in this case there was no advantage in returning a new list so I would choose mutation with a void return value.
 
  • #35
pbuk said:
No, the relevant function name is reverse:
Ah, yes, that's right. That one I agree would be naturally interpreted as mutating in place.

pbuk said:
The point I was trying to make was that a function should not both mutate a list and return the mutated list; it should either mutate the list or return a new list.
Yes, agreed.

pbuk said:
As a secondary point, I was arguing that in this case there was no advantage in returning a new list so I would choose mutation with a void return value.
For this particular problem, since it's only asking for the next permutation, I agree it's simpler just to mutate in place. I always tend to think in more general terms, and I can think of plenty of reasons why it would be better to return a new list in a more general purpose program. But there might also be reasons in other particular use cases to mutate in place instead.
 
  • Like
Likes   Reactions: pbuk

Similar threads

  • · Replies 28 ·
Replies
28
Views
5K
  • · Replies 5 ·
Replies
5
Views
2K
Replies
3
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
Replies
7
Views
2K
  • · Replies 10 ·
Replies
10
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 3 ·
Replies
3
Views
3K
  • · Replies 3 ·
Replies
3
Views
3K
Replies
55
Views
7K