Receita: Verificador de CPF
Esse módulo contém algumas funções e classes úteis para aplicações que envolvam cadastros e necessitem validar números de CPF antes de incluir no banco de dados. Além de útil, também é um bom exemplo de como otimizar código que lida com manipulação de números e strings, usando as funções reduce(), map() e list compreensions.
Código
1 #/usr/bin/env python
2 # -*- coding:UTF-8 -*-
3
4
5 def _gen(cpf):
6 """Gera o próximo dígito do número de CPF
7
8 """
9 res = []
10 for i in range(len(cpf)):
11 a = cpf[i]
12 b = (len(cpf) + 1 - i)
13 res.append(b * a)
14
15 res = reduce(int.__add__, res) % 11
16
17 if res > 1:
18 return (11 - res)
19 else:
20 return 0
21
22
23 def _translate(cpf):
24 """Traduz o número como string na forma:
25
26 123.456.789-10
27
28 para a forma:
29
30 12345678910
31
32 """
33
34 i = xrange(256)
35 t = [' '] * 256
36 e = ''.join([chr(x) for x in i if not chr(x).isdigit()])
37
38 for x in i:
39 if chr(x).isdigit():
40 t[x] = chr(x)
41
42 return cpf.translate(''.join(t), e)
43
44
45
46 class CPF(object):
47
48 _gen = staticmethod(_gen)
49 _translate = staticmethod(_translate)
50
51 def __init__(self, cpf):
52 """O argumento cpf pode ser uma string nas formas:
53
54 12345678910
55 123.456.789-10
56
57 ou uma lista ou tuple
58 [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]
59 (1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0)
60
61 """
62
63 if isinstance(cpf, basestring):
64 if not cpf.isdigit():
65 cpf = self._translate(cpf)
66
67 self.cpf = [int(x) for x in cpf]
68
69 def __getitem__(self, index):
70 """Retorna o dígito em index como string
71
72 """
73
74 return self.cpf[index]
75
76 def __repr__(self):
77 """Retorna uma representação 'real', ou seja:
78
79 eval(repr(cpf)) == cpf
80
81 """
82
83 return "CPF('%s')" % ''.join([str(x) for x in self.cpf])
84
85 def __eq__(self, other):
86 """Provê teste de igualdade para números de CPF
87
88 """
89
90 if isinstance(other, CPF):
91 return self.cpf == other.cpf
92 return False
93
94 def __str__(self):
95 """Retorna uma representação do CPF na forma:
96
97 123.456.789-10
98
99 """
100
101 d = iter("..-")
102 s = map(str, self.cpf)
103 for i in xrange(3, 12, 4):
104 s.insert(i, d.next())
105 r = ''.join(s)
106 return r
107
108 def isValid(self):
109 """Valida o número de cpf
110
111 """
112
113 s = self.cpf[:9]
114 s.append(self._gen(s))
115 s.append(self._gen(s))
116 return s == self.cpf[:]
Exemplo de uso
1 #/usr/bin/env python
2 # -*- coding:UTF-8 -*-
3
4
5 from cpf import CPF
6
7 # Estes números foram gerados aleatoriamente :)
8
9 VALIDO = "113.451.253-80"
10 INVALIDO = "31354110274"
11
12 # qualquer um dos dois formatos (com pontos ou não) pode ser usado
13
14 valido = CPF(VALIDO)
15 invalido = CPF(INVALIDO)
16
17 assert valido.verificar()
18 assert not invalido.verificar()
Volta para CookBook.
Pedro Werneck