Dado um objeto Python arbitrário, qual é a melhor maneira de determinar se é um número? Aqui is
é definido como acts like a number in certain circumstances
.
Por exemplo, digamos que você esteja escrevendo uma classe de vetor. Se for dado outro vetor, você deseja encontrar o produto escalar. Se for fornecido um escalar, você deseja dimensionar todo o vetor.
Verificar se algo é int
, float
, long
, bool
é irritante e não cobre os objetos definidos pelo usuário que pode agir como números. Mas, verificar __mul__
, por exemplo, não é bom o suficiente porque a classe de vetor que acabei de descrever definiria __mul__
, mas não seria o tipo de número que desejo.
isinstance(value, Number) and type(value) != bool
Você quer verificar se algum objeto
Se você estiver usando Python 2.5 ou anterior, a única maneira real é verificar algumas dessas "circunstâncias específicas" e ver.
Em 2.6 ou melhor, você pode usar
isinstance
com números.Number - uma classe base abstrata (ABC) que existe exatamente para este propósito (muitos mais ABCs existem nocollections
módulo para várias formas de coleções / contêineres, novamente começando com 2.6; e, também apenas nessas versões, você pode adicionar facilmente suas próprias classes base abstratas, se necessário).Bach para 2.5 e anteriores, "pode ser adicionado
0
e não é iterável" pode ser uma boa definição em alguns casos. Mas, você realmente precisa se perguntar o que é que você está pedindo que o que você deseja considerar "um número" deve definitivamente ser capaz de fazer , e o que deve ser absolutamente incapaz de fazer - e verificar.Isso também pode ser necessário no 2.6 ou posterior, talvez com o propósito de fazer seus próprios registros para adicionar tipos de seu interesse que ainda não tenham sido registrados
numbers.Numbers
- se você quiser excluir alguns tipos que afirmam serem números, mas você simplesmente não consigo lidar, isso leva ainda mais cuidado, já que os ABCs não têm nenhumunregister
método [[por exemplo, você pode fazer seu próprio ABCWeirdNum
e registrar lá todos esses tipos estranhos para você, então primeiro verifique se há algum métodoisinstance
antes de prosseguir para verificarisinstance
o normalnumbers.Number
para continuar com êxito.BTW, se e quando você precisar verificar se
x
pode ou não fazer algo, geralmente você tem que tentar algo como:A presença de
__add__
per se não diz nada de útil, uma vez que, por exemplo, todas as sequências o possuem para fins de concatenação com outras sequências. Essa verificação é equivalente à definição "um número é algo tal que uma sequência dessas coisas é um único argumento válido para a função embutidasum
", por exemplo. Tipos totalmente estranhos (por exemplo, aqueles que levantam a exceção "errada" quando somados a 0, como, digamos, aZeroDivisionError
ouValueError
& c) irão propagar a exceção, mas tudo bem, avise o usuário o mais rápido possível que esses tipos malucos não são aceitáveis no bom companhia;-); mas, um "vetor" que pode ser somado a um escalar (a biblioteca padrão do Python não tem um, mas é claro que eles são populares como extensões de terceiros) também daria o resultado errado aqui, portanto (por exemploo "não permitido para ser iterável" (por exemplo, cheque queiter(x)
aumentaTypeError
, ou para a presença de método especial__iter__
- se você estiver no 2.5 ou anterior e, portanto, precisa de seus próprios cheques).Um breve vislumbre de tais complicações pode ser suficiente para motivá-lo a confiar em classes de base abstratas sempre que possível ... ;-).
fonte
Este é um bom exemplo onde as exceções realmente brilham. Basta fazer o que você faria com os tipos numéricos e pegar o
TypeError
de todo o resto.Mas, obviamente, isso só verifica se uma operação funciona , não se faz sentido ! A única solução real para isso é nunca misturar tipos e sempre saber exatamente a qual typeclass seus valores pertencem.
fonte
isinstance
pode realmente ser útil em muitos casos (== "verifique se faz sentido", bem como aplicabilidade formal das operações). Mudança difícil para pessoas de longa data apenas com Python, mas uma tendência sutil muito importante na filosofia do Python que seria um erro sério ignorar.collections.Sequence
e amigos). Mas afaik, não existem tais classes para números, vetores ou quaisquer outros objetos matemáticos.Multiplique o objeto por zero. Qualquer número vezes zero é zero. Qualquer outro resultado significa que o objeto não é um número (incluindo exceções)
Usar isNumber, portanto, fornecerá a seguinte saída:
Resultado:
Provavelmente existem alguns objetos não numéricos no mundo que definem
__mul__
retornar zero quando multiplicado por zero, mas essa é uma exceção extrema. Esta solução deve abranger todo o código normal e lógico que você gerar / encontrar.exemplo numpy.array:
resultado:
fonte
True * 0 == 0
int
então minha função dirá corretamente que booleanos são números.Para reformular sua pergunta, você está tentando determinar se algo é uma coleção ou um valor único. Tentar comparar se algo é um vetor ou um número está comparando maçãs com laranjas - posso ter um vetor de strings ou números, e posso ter uma única string ou um único número. Você está interessado em quantos você tem (1 ou mais) , não que tipo você realmente tem.
minha solução para esse problema é verificar se a entrada é um valor único ou uma coleção, verificando a presença de
__len__
. Por exemplo:Ou, para a abordagem de digitação de pato, você pode tentar iterar
foo
primeiro:Em última análise, é mais fácil testar se algo é semelhante a um vetor do que testar se algo é semelhante a escalar. Se você tiver valores de tipo diferente (ou seja, string, numérico, etc.), então a lógica do seu programa pode precisar de algum trabalho - como você acabou tentando multiplicar uma string por um vetor numérico em primeiro lugar?
fonte
Para resumir / avaliar os métodos existentes:
(Eu vim aqui por esta questão )
Código
fonte
float('nan'), 'nan', '123.45', '42', '42a', '0x8', '0xa'
math.isnan
Provavelmente é melhor fazer o contrário: você verifica se é um vetor. Se for, você faz um produto escalar e, em todos os outros casos, tenta a multiplicação escalar.
Verificar o vetor é fácil, pois ele deve ser do seu tipo de classe de vetor (ou herdado dele). Você também pode tentar primeiro fazer um produto escalar e, se isso falhar (= não era realmente um vetor), volte para a multiplicação escalar.
fonte
Apenas para acrescentar. Talvez possamos usar uma combinação de isinstance e isdigit da seguinte forma para descobrir se um valor é um número (int, float, etc)
if isinstance (num1, int) ou isinstance (num1, float) ou num1.isdigit ():
fonte
Para a aula de vetor hipotético:
Suponha que
v
seja um vetor e estejamos multiplicando porx
. Se faz sentido multiplicar cada componente dev
porx
, provavelmente isso é o que queríamos dizer, então tente primeiro. Se não, talvez possamos pontuar? Caso contrário, é um erro de tipo.EDIT - o código abaixo não funciona, porque em
2*[0]==[0,0]
vez de gerar umTypeError
. Deixo porque foi comentado.fonte
x
é um vetor, então[comp * x for comp in self]
, produzirá o produto externo dex
umv
. Este é um tensor de classificação 2, não um escalar.comp*x
será ampliadox
porcomp
, eu estava assumindo que iria levantar um TypeError. Infelizmente, ele realmente irá concatenarx
com o própriocomp
vezes. Opa.x
for um vetor, então ele deve ter um__rmul__
método (__rmul__ = __mul__
) para quecomp * x
seja escalonadox
da mesma forma quex * comp
aparentemente se pretende.Eu tive um problema semelhante, ao implementar uma espécie de classe de vetor. Uma maneira de verificar um número é apenas convertê-lo em um, ou seja, usando
Isso deve rejeitar os casos em que x não pode ser convertido em um número; mas também pode rejeitar outros tipos de estruturas semelhantes a números que podem ser válidas, por exemplo, números complexos.
fonte
Se você quiser chamar métodos diferentes dependendo do (s) tipo (s) de argumento (s), examine
multipledispatch
.Infelizmente, (até onde sei) não podemos escrever,
@dispatch(Vector)
pois ainda estamos definindo o tipoVector
, de modo que o nome do tipo ainda não foi definido. Em vez disso, estou usando o tipo baselist
, que permite até mesmo encontrar o produto escalar de aVector
e alist
.fonte
Forma curta e simples:
Resultado :
Se o objeto for uma string, 'False' será retornado:
Resultado :
fonte
Você tem um item de dados, digamos
rec_day
que, quando gravado em um arquivo, haverá umfloat
. Mas durante o programa de processamento pode serfloat
,int
oustr
digite (ostr
é usado ao inicializar um novo recorde e contém um valor bandeira simulado).Você pode então verificar se você tem um número com este
Estruturei um programa Python dessa maneira e apenas coloquei um 'patch de manutenção' usando isso como uma verificação numérica. É a maneira pitônica? Provavelmente não, já que eu costumava programar em COBOL.
fonte
Você pode usar a função isdigit ().
fonte