2
\$\begingroup\$

I have began taking the CS50 course on EDX the past couple of days, and one of the tasks to accomplish was to write a credit card validator in C. I wrote it in C, and then I thought that I could go about the same thing in Python, and wrote the same program in Python. For those of you unfamiliar with the problem, here is the description.

Because I took the program and converted from C to Python, it is probably not going to be written in the most Pythonic way. I tried to add some Pythonic ways of doing things, but there are probably many more things I could have done. If you find anything that could be done in a better, faster, or more Pythonic way, please let me know. Thanks.

def main():
    # cc_number = int(input("Enter a valid credit card number: "))

    cc_number = 12345678912356789
    if not checksum(cc_number):
        print("INVALID")
    else:
        print(check_provider(cc_number))


def check_provider(number):
    if len(str(number)) < 13 or len(str(number)) > 16:
        return 'INVALID'

    if ((list(str(number)))[:2]) == ['3', '4'] or ((list(str(number)))[:2]) == ['3', '7']:
        return 'AMEX'
    elif ((list(str(number)))[:2]) == ['5', '1'] or ((list(str(number)))[:2]) == ['5', '2'] \
            or ((list(str(number)))[:2]) == ['5', '3'] or ((list(str(number)))[:2]) == ['5', '4'] \
            or ((list(str(number)))[:2]) == ['5', '5']:
        return 'MASTERCARD'
    elif ((list(str(number)))[0]) == '4':
        return 'VISA'
    else:
        return 'INVALID'


def checksum(number):
    list_number = list(str(number))
    odd_indices = []
    even_indices = []

    last_index = len(list_number) - 1

    rev_list = list(reversed(list_number))

    for i in rev_list[1::2]:
        odd_indices.append(i)

    for i in rev_list[::2]:
        even_indices.append(i)

    sum_odd = sum(split_to_digits(''.join(int_to_str(mul(odd_indices, 2)))))
    sum_even = sum(split_to_digits(''.join(int_to_str(even_indices))))
    s = sum_odd + sum_even

    print(s)

    if s % 10 == 0:
        return True
    return False


def mul(list, x):
    return [(int(n) * 2) for n in list]


def split_to_digits(n):
    return [int(i) for i in str(n)]


def int_to_str(n):
    return [str(x) for x in n]


def str_to_int(n):
    return [int(x) for x in n]


main()
\$\endgroup\$
5
\$\begingroup\$

General notes:

  • use if __name__ == '__main__': to avoid the main() function to be executed when the module is imported
  • I'd pass around the credit card number as a string instead of converting it to string in every single validation step
  • add docstrings to each of the defined functions

Regarding check_provider() function:

  • you can check the length to be in range in one go:

    if not(13 <= len(str(number)) <= 16):
    
  • I would improve the way you distinguish between cards by introducing a mapping between brands and regular expressions (like it was done in pycard module). Then, match each of the expressions one by one until you find a match or a brand was not found:

    import re
    
    
    BRANDS = {
        'Visa': re.compile(r'^4\d{12}(\d{3})?$'),
        'Mastercard': re.compile(r'''
            ^(5[1-5]\d{4}|677189)\d{10}$|  # Traditional 5-series + RU support
            ^(222[1-9]|2[3-6]\d{2}|27[0-1]\d|2720)\d{12}$  # 2016 2-series
        ''', re.VERBOSE),
        'American Express': re.compile(r'^3[47]\d{13}$'),
        'Discover': re.compile(r'^(6011|65\d{2})\d{12}$'),
    }
    
    def check_provider(number):
        """Checks a credit card number and returns a matching brand name, or INVALID if no brand matched."""
        for brand, regexp in BRANDS.items():
            if regexp.match(number):
                return brand
        return 'INVALID'
    

Regarding implementing the Luhn algorithm, check the pycard's implementation - it is quite clean and understandable.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.