What I need to do is take a 10-digit ISBN number and check if it's valid, according to this rule:
According to the 2001 edition of the International ISBN Agency's official user manual,[47] the ISBN-10 check digit (which is the last digit of the 10-digit ISBN) must range from 0 to 10 (the symbol 'X' is used for 10), and must be such that the sum of the ten digits, each multiplied by its (integer) weight, descending from 10 to 1, is a multiple of 11.
In other words, if the number is 0-306-40615-2, I need to calculate:
(0 * 10) + (3 * 9) + (0 * 8) + (6 * 7) + (4 * 6) + (0 * 5) + (6 * 4) + (1 * 3) + (5 * 2) + (2 * 1) mod 11
While suggestions or hints on how to write such a function are welcome, my main question is simply whether Python already has a way of doing this, perhaps in the math
module.
This is my attempt, but the for loops don't work because the inner one keeps starting over. Plus it just seems messy!
checksum = 0
for digit in isbn:
for weight in range(10, 0, -1):
if digit == 'X':
checksum += 10 * weight
break
checksum += int(digit) * weight
break
return checksum % 11```
No, that is way too specific to be something in a standard library. It is fairly simple to write though:
def check_isbn(isbn):
isbn_digits = (
10 if ch == 'X' else int(ch)
for ch in isbn
if ch.isdigit() or ch == 'X')
checksum = sum(
(10 - index) * digit
for index, digit
in enumerate(isbn_digits)
) % 11
return checksum % 11 == 0
I like the comprehension way; but the imperative way should also work, you just have some logic errors. In particular, you don't want to iterate all weights for each digit. Each character has exactly one weight if it's a digit, or none if it is not. So an imperative rewrite would be:
def check_isbn(isbn):
checksum = 0
weight = 10
for ch in isbn:
if ch == 'X':
digit = 10
elif ch.isdigit():
digit = int(ch)
else:
continue
checksum += digit * weight
weight -= 1
return checksum % 11 == 0
EDIT: various bugs