Password cracking commenting in Python
1. The purpose of comments

Comments are a tool that you use in order to make code easier to understand and easier to maintain. But they are not the best tool to achieve that aim. Comments increase the amount of text that has to be read (you have to read the comment as well as the code) and there is a risk that when code is changed, a programmer will forget to change the nearby comments, leading to nonsense like the comments in this question.

So comments are a last resort when you can't make the code clear enough by other means. Before writing a comment you should ask these questions:


Do functions have documentation explaining their arguments and results? (In Python, do they have docstrings?)
Are there test cases (or documentation examples) demonstrating the correct behaviour of the code?
Do function names clearly describe what they do? And do variable names clearly indicate the meaning of their values?
Is the code written in the simplest, clearest way?


Only when the answers are all "yes", and the code is still not clear, should you consider writing a comment.

2. Worked example

Let's take the numberToBase function and ask these questions:

# converts number N base 10 to a list of digits base b
def numberToBase(n, b):
    digits = []
    while n: # takes n and the finds the modulus, the remainder of n % b
        digits.append(int(n % b)) # then it will append that to a list
        n //= b # following on it will then divide n into b
    return digits[::-1] #returns those digits into reverse order from -1, the end to the beginning



There's no documentation. Let's turn the first comment into a docstring:

def numberToBase(n, b):
    """Convert the number n to base b and return a list of digits."""
    digits = []
    while n:
        digits.append(int(n % b))
        n //= b
    return digits[::-1]

There are no examples. Let's add some:

def numberToBase(n, b):
    """Convert the number n to base b and return a list of digits.

        &gt;&gt;&gt; numberToBase(1234, 10)
        [1, 2, 3, 4]
        &gt;&gt;&gt; numberToBase(1023, 2)
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

    """
    digits = []
    while n:
        digits.append(int(n % b))
        n //= b
    return digits[::-1]


These are in the form of doctests so that they can be automatically checked using the doctest module.
There are bunch of improvements we can make to the names. (i) Something like number_to_digits would be clearer than numberToBase since the result is a list of digits. (ii) base would be clearer than b. (iii) The built-in function divmod would make it clear that we are computing the division and modulus. (iv) The name digit for the modulus would make its meaning clear. (v) Using the built-in functions list and reversed would make it clear that we are computing a list in reverse order.

def number_to_digits(n, base):
    """Convert the number n to a list of digits in the given base.

        &gt;&gt;&gt; number_to_digits(1234, 10)
        [1, 2, 3, 4]
        &gt;&gt;&gt; number_to_digits(1023, 2)
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

    """
    digits = []
    while n:
        n, digit = divmod(n, base)
        digits.append(digit)
    return list(reversed(digits))

The code seems clear and simple now: there is no need to add any comments.


3. Other review points


When n is 0, the result is an empty list. It might be better to return the list [0].
When b is 1, the function goes into an infinite loop. It might be better to raise an exception in this case.