Pergunta

Eu tenho uma função Python que leva um argumento numérico que deve ser um inteiro para que ele se comportar corretamente. O que é a forma preferida de verificar isso em Python?

A minha primeira reacção é fazer algo parecido com isto:

def isInteger(n):
    return int(n) == n

Mas eu não posso deixar de pensar que este é 1) caro 2) feio e 3) sujeito às misericórdias de epsilon máquina.

O Python fornecer quaisquer meios nativos de variáveis ??verificação de tipo? Ou isso é considerado uma violação da linguagem de tipagem dinâmica design?

EDIT: uma vez que um número de pessoas têm perguntado - a aplicação em questão trabalha com prefixos IPv4, o abastecimento de dados de arquivos de texto plano. Se qualquer entrada é analisado em uma bóia, esse registro deve ser visto como mal formada e ignorado.

Foi útil?

Solução

isinstance(n, int)

Se você precisa saber se ele é definitivamente um int real e não uma subclasse de int (geralmente você não deve precisar fazer isso):

type(n) is int

este:

return int(n) == n

não é uma idéia tão boa, como comparações de tipo cruzado pode ser verdade - nomeadamente int(3.0)==3.0

Outras dicas

Sim, como disse Evan, não digite cheque. Basta tentar usar o valor:

def myintfunction(value):
   """ Please pass an integer """
   return 2 + value

Isso não tem uma typecheck. É muito melhor! Vamos ver o que acontece quando eu experimentá-lo:

>>> myintfunction(5)
7

que funciona, porque é um número inteiro. Hm. Vamos tentar algum texto.

>>> myintfunction('text')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myintfunction
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Ela mostra um erro, TypeError, que é o que ele deve fazer de qualquer maneira. Se chamador quer pegar isso, é possível.

O que você faria se você fez um typecheck? Mostrar um certo erro? Então você não tem que typecheck porque o erro já está mostrando-se automaticamente.

Além disso, desde que você não typecheck, você tem sua função trabalhar com outros tipos:

Floats:

>>> print myintfunction(2.2)
4.2

Os números complexos:

>>> print myintfunction(5j)
(2+5j)

Decimals:

>>> import decimal
>>> myintfunction(decimal.Decimal('15'))
Decimal("17")

Mesmo objetos completamente arbitrárias que podem adicionar números!

>>> class MyAdderClass(object):
...     def __radd__(self, value):
...             print 'got some value: ', value
...             return 25
... 
>>> m = MyAdderClass()
>>> print myintfunction(m)
got some value:  2
25

Assim que você começa claramente nada por typechecking. E perder muito.


UPDATE:

Uma vez que você editou a questão, é agora claro que o aplicativo chama alguma rotina upstream que só faz sentido com ints.

Sendo esse o caso, eu ainda acho que você deve passar o parâmetro como recebeu para a função de upstream. A função montante vai lidar com isso corretamente por exemplo levantando um erro se ele precisa. I altamente dúvida de que a sua função que lida com IPs vai se comportar estranhamente, se você passá-lo um float. Se você pode nos dar o nome da biblioteca que possamos verificar isso para você.

Mas ... Se a função a montante irá se comportar de forma incorreta e matar algumas crianças se você passá-lo um float (eu ainda duvido muito), então basta apenas chamar int() nele:

def myintfunction(value):
   """ Please pass an integer """
   return upstreamfunction(int(value))

Você está ainda não typechecking, de modo a obter a maioria dos benefícios de não typechecking.


Se mesmo depois de tudo isso, você realmente deseja digitar cheque, apesar de reduzir a legibilidade e o desempenho do seu pedido de absolutamente nenhum benefício, use um assert para fazê-lo.

assert isinstance(...)
assert type() is xxxx

Dessa forma, podemos desligar asserts e remover este <sarcasm> recurso </sarcasm> do programa, chamando-o como

python -OO program.py
if type(n) is int

Este verifica se n é um int Python, e única um int. Ele não aceitará subclasses de int.

Tipo de verificação, no entanto, não se encaixa no "caminho Python". É melhor uso n como um int, e se ele lança uma exceção, pegá-lo e agir sobre ela.

Python agora suporta digitação gradual através das digitação módulo e mypy. O módulo typing é uma parte do stdlib como do Python 3.5 e pode ser baixado de PyPI se você precisa backports para Python 2 ou versão anterior do Python 3. você pode instalar mypy executando pip install mypy a partir da linha de comando.

Em suma, se você quiser verificar se alguma função leva em um int, float, e retorna uma string, você anotar sua função assim:

def foo(param1: int, param2: float) -> str:
    return "testing {0} {1}".format(param1, param2)

Se o arquivo foi nomeado test.py, você poderia, então, typecheck uma vez que você tenha instalado mypy executando mypy test.py a partir da linha de comando.

Se você estiver usando uma versão mais antiga do Python sem suporte para anotações de função, você pode usar os comentários do tipo para realizar o mesmo efeito:

def foo(param1, param2):
    # type: (int, float) -> str
    return "testing {0} {1}".format(param1, param2)

Você usa o mesmo mypy test.py de comando para Python 3 arquivos, e mypy --py2 test.py para Python 2 arquivos.

As anotações de tipo são ignorados inteiramente pelo interpretador Python em tempo de execução, para que eles impõem mínima ou nenhuma sobrecarga - o fluxo de trabalho normal é trabalhar em seu código e executá mypy periodicamente para erros de captura e erros. Algumas IDEs, como PyCharm, vai entender dicas de tipo e pode alertá-lo para problemas e tipo inadequações em seu código enquanto você está editando diretamente.

Se, por algum motivo, você precisa dos tipos a ser verificado em tempo de execução (? Talvez você precise validar um monte de entrada), você deve seguir os conselhos listados em outras respostas - por exemplo, uso isinstance, issubclass, e similares. Há também algumas bibliotecas como impor que a tentativa de realizar typechecking (respeitando suas anotações de tipo) em tempo de execução, embora eu tenho certeza de como pronto para produção são como do tempo da escrita.

Para mais informações e detalhes, consulte a mypy website , a mypy FAQ , e PEP 484 .

Não digite cheque. O ponto inteiro de tipagem pato é que você não deve ter que. Por exemplo, se alguém fez algo parecido com isto:

class MyInt(int):
    # ... extra stuff ...

Programação em Python e realizando typechecking como você pode em outros idiomas parece ser a escolha de uma chave de fenda para bater um prego com. É mais elegante para usar os recursos de manipulação de exceção do Python.

A partir de uma linha de comando interativo, você pode executar uma instrução como:

int('sometext')

Isso irá gerar um erro - ipython me diz:

<type 'exceptions.ValueError'>: invalid literal for int() with base 10: 'sometext'

Agora você pode escrever algum código como:

try:
   int(myvar) + 50
except ValueError:
   print "Not a number"

Isso pode ser personalizado para executar qualquer operações são necessárias e para detectar quaisquer erros que são esperados. Parece um pouco complicado, mas se encaixa a sintaxe e expressões idiomáticas de Python e resulta em código muito legível (uma vez que você se acostumar a falar Python).

Eu seria tentado a para algo como:

def check_and_convert(x):
    x = int(x)
    assert 0 <= x <= 255, "must be between 0 and 255 (inclusive)"
    return x

class IPv4(object):
    """IPv4 CIDR prefixes is A.B.C.D/E where A-D are 
       integers in the range 0-255, and E is an int 
       in the range 0-32."""

    def __init__(self, a, b, c, d, e=0):
        self.a = check_and_convert(a)
        self.b = check_and_convert(a)
        self.c = check_and_convert(a)
        self.d = check_and_convert(a)
        assert 0 <= x <= 32, "must be between 0 and 32 (inclusive)"
        self.e = int(e)

Dessa forma, quando você estiver usando-tudo pode ser passado ainda só armazenar um número inteiro válido.

como sobre: ??

def ip(string):
    subs = string.split('.')
    if len(subs) != 4:
        raise ValueError("incorrect input")
    out = tuple(int(v) for v in subs if 0 <= int(v) <= 255)
    if len(out) != 4:
        raise ValueError("incorrect input")
    return out

é claro, há o isinstance padrão (3, int) função ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top