[python] 객체가 숫자인지 확인하는 가장 비단뱀적인 방법은 무엇입니까?

임의의 파이썬 객체가 주어지면 그것이 숫자인지 결정하는 가장 좋은 방법은 무엇입니까? 여기에서 is로 정의됩니다 acts like a number in certain circumstances.

예를 들어 벡터 클래스를 작성한다고 가정 해보십시오. 다른 벡터가 주어지면 내적을 찾고 싶습니다. 스칼라가 주어지면 전체 벡터를 스케일링하려고합니다.

어떤 경우 검사 int, float, long, bool성가신 숫자처럼 행동 수있는 사용자 정의 개체에 적용되지 않습니다. 그러나 __mul__예를 들어를 확인하는 것은 내가 방금 설명한 벡터 클래스가를 정의 할 것이기 때문에 충분하지 __mul__않지만 내가 원하는 종류의 숫자는 아닙니다.



답변

모듈 Number에서 사용 numbers하여 테스트합니다 isinstance(n, Number)(2.6부터 사용 가능).

>>> from numbers import Number
... from decimal import Decimal
... from fractions import Fraction
... for n in [2, 2.0, Decimal('2.0'), complex(2, 0), Fraction(2, 1), '2']:
...     print(f'{n!r:>14} {isinstance(n, Number)}')
              2 True
            2.0 True
 Decimal('2.0') True
         (2+0j) True
 Fraction(2, 1) True
            '2' False

물론 이것은 덕 타이핑과는 반대입니다. 객체 가 무엇인지보다 객체가 작동 하는 방식에 더 관심 있다면 숫자가있는 것처럼 작업을 수행하고 예외를 사용하여 달리 알려주십시오.


답변

어떤 물체가 있는지 확인하고 싶습니다.

특정 상황에서 숫자처럼 행동

Python 2.5 또는 이전 버전을 사용하는 경우 유일한 실제 방법은 이러한 “특정 상황”중 일부를 확인하고 확인하는 것입니다.

2.6 이상에서는 numbers.Numberisinstance 와 함께 사용할 수 있습니다 . 이 목적을 위해 정확히 존재하는 추상 기본 클래스 (ABC) ( collections2.6부터 다시 시작하는 다양한 형태의 컬렉션 / 컨테이너 에 대해 모듈에 더 많은 ABC가 존재합니다 . 또한 해당 릴리스에서만 필요한 경우 자체 추상 기본 클래스를 쉽게 추가 할 수 있습니다.

Bach가 2.5 0이하인 경우 ” 추가 할 수 있지만 반복 할 수 없음”은 경우에 따라 좋은 정의가 될 수 있습니다. 그러나, 당신은 정말 당신이 당신이 고려해야 할 것 “숫자”확실히 할 수 있어야한다는 요구하고 있다는 것입니다 무엇인지, 자신을 요청해야 , 그리고 절대적으로 무엇을해야 할 수없는 및 확인 – 할.

이것은 2.6 이상에서 필요할 수 있습니다. 아직 등록되지 않은 관심있는 유형을 추가하기 위해 자신의 등록을 할 목적으로 numbers.Numbers필요할 수 있습니다. 이는 숫자라고 주장하는 일부 유형 을 제외 하려는 경우 ABC에는 unregister방법 이 없기 때문에 처리 할 수 ​​없습니다. 더 많은주의가 필요 합니다. [[예를 들어 자신 만의 ABC를 만들어서 WeirdNum그런 모든 이상한 유형을 등록한 다음 isinstance진행하기 전에 먼저 구제를받을 수 있는지 확인하십시오. 성공적으로 계속 isinstance하려면 정상 을 확인합니다 numbers.Number.

BTW, x무언가를 할 수 있는지 여부를 확인해야하는 경우 일반적으로 다음과 같이 시도해야합니다.

try: 0 + x
except TypeError: canadd=False
else: canadd=True

__add__예를 들어 모든 시퀀스에는 다른 시퀀스와 연결하기위한 목적으로 사용되기 때문에 그 자체가 존재 한다고해서 유용한 것은 없습니다. 예를 들어,이 검사는 “숫자는 그러한 것의 시퀀스가 ​​내장 함수에 대한 유효한 단일 인수가되는 것입니다”라는 정의와 동일합니다 sum. 완전히 이상한 유형 (예 : a ZeroDivisionError또는 ValueError& c 와 같이 0으로 합산 될 때 “잘못된”예외를 발생시키는 유형 )은 예외를 전파하지만 괜찮습니다. 사용자에게 그러한 미친 유형은 좋은 상태에서 허용되지 않는다는 것을 최대한 빨리 알립니다. 회사;-); 그러나 스칼라로 합산 할 수있는 “벡터”(Python의 표준 라이브러리에는 없습니다. 물론 타사 확장으로 널리 사용됨)도 여기서 잘못된 결과를 제공하므로 (예 :하나 “반복자가 될 수 없습니다”(예를 들어, 그 확인 iter(x)인상을 TypeError, 또는 특별한 방법의 존재를 __iter__– 당신은 2.5에있어 이전함으로써 자신의 확인이 필요한 경우).

이러한 복잡성을 간단히 살펴보면 가능할 때마다 추상 기본 클래스에 의존하도록 동기를 부여하기에 충분할 수 있습니다 … ;-).


답변

이것은 예외가 실제로 빛나는 좋은 예입니다. 숫자 유형으로 수행 할 작업을 수행하고 TypeError다른 모든 것에서를 잡으십시오 .

그러나 분명히 이것은 작동이 작동 하는지 확인하는 것이지 의미가 있는지 여부 는 확인 하지 않습니다 ! 이에 대한 유일한 해결책은 유형을 혼합하지 않고 항상 값이 속한 유형 클래스를 정확히 아는 것입니다.


답변

개체에 0을 곱합니다. 0을 곱한 숫자는 0입니다. 다른 결과는 객체가 숫자가 아님을 의미합니다 (예외 포함).

def isNumber(x):
    try:
        return bool(0 == x*0)
    except:
        return False

따라서 isNumber를 사용하면 다음과 같은 출력이 제공됩니다.

class A: pass

def foo(): return 1

for x in [1,1.4, A(), range(10), foo, foo()]:
    answer = isNumber(x)
    print('{answer} == isNumber({x})'.format(**locals()))

산출:

True == isNumber(1)
True == isNumber(1.4)
False == isNumber(<__main__.A instance at 0x7ff52c15d878>)
False == isNumber([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
False == isNumber(<function foo at 0x7ff52c121488>)
True == isNumber(1)

__mul__0을 곱하면 0을 반환 하도록 정의 하는 숫자가 아닌 개체가있을 수 있지만 이는 극단적 인 예외입니다. 이 솔루션은 생성 / 암호화하는 모든 정상정상 코드를 포함해야합니다.

numpy.array 예 :

import numpy as np

def isNumber(x):
    try:
        return bool(x*0 == 0)
    except:
        return False

x = np.array([0,1])

answer = isNumber(x)
print('{answer} == isNumber({x})'.format(**locals()))

산출:

False == isNumber([0 1])


답변

질문을 바꾸려면 무언가가 컬렉션인지 단일 값인지 확인하려고합니다. 어떤 것이 벡터인지 숫자인지 비교하려고하면 사과와 오렌지를 비교하는 것입니다. 저는 문자열 또는 숫자의 벡터를 가질 수 있으며 단일 문자열 또는 단일 숫자를 가질 수 있습니다. 당신은 당신이 실제로 가지고있는 유형이 아니라 얼마나 많은 (1 개 이상) 가지고 있는지에 관심 이 있습니다.

이 문제에 대한 내 해결책은 입력이 단일 값인지 또는 컬렉션인지 확인하여 __len__. 예를 들면 :

def do_mult(foo, a_vector):
    if hasattr(foo, '__len__'):
        return sum([a*b for a,b in zip(foo, a_vector)])
    else:
        return [foo*b for b in a_vector]

또는 덕 타이핑 방식의 경우 foo먼저 반복을 시도 할 수 있습니다 .

def do_mult(foo, a_vector):
    try:
        return sum([a*b for a,b in zip(foo, a_vector)])
    except TypeError:
        return [foo*b for b in a_vector]

궁극적으로, 무언가가 스칼라와 같은지 테스트하는 것보다 벡터와 같은지 테스트하는 것이 더 쉽습니다. 다른 유형 (예 : 문자열, 숫자 등)의 값이 들어 오면 프로그램 논리에 약간의 작업이 필요할 수 있습니다. 처음에 문자열에 숫자 벡터를 곱하려고 시도한 이유는 무엇입니까?


답변

기존 방법을 요약 / 평가하려면 :

Candidate    | type                      | delnan | mat | shrewmouse | ant6n
-------------------------------------------------------------------------
0            | <type 'int'>              |      1 |   1 |          1 |     1
0.0          | <type 'float'>            |      1 |   1 |          1 |     1
0j           | <type 'complex'>          |      1 |   1 |          1 |     0
Decimal('0') | <class 'decimal.Decimal'> |      1 |   0 |          1 |     1
True         | <type 'bool'>             |      1 |   1 |          1 |     1
False        | <type 'bool'>             |      1 |   1 |          1 |     1
''           | <type 'str'>              |      0 |   0 |          0 |     0
None         | <type 'NoneType'>         |      0 |   0 |          0 |     0
'0'          | <type 'str'>              |      0 |   0 |          0 |     1
'1'          | <type 'str'>              |      0 |   0 |          0 |     1
[]           | <type 'list'>             |      0 |   0 |          0 |     0
[1]          | <type 'list'>             |      0 |   0 |          0 |     0
[1, 2]       | <type 'list'>             |      0 |   0 |          0 |     0
(1,)         | <type 'tuple'>            |      0 |   0 |          0 |     0
(1, 2)       | <type 'tuple'>            |      0 |   0 |          0 |     0

( 이 질문으로 여기에 왔습니다 )

암호

#!/usr/bin/env python

"""Check if a variable is a number."""

import decimal


def delnan_is_number(candidate):
    import numbers
    return isinstance(candidate, numbers.Number)


def mat_is_number(candidate):
    return isinstance(candidate, (int, long, float, complex))


def shrewmouse_is_number(candidate):
    try:
        return 0 == candidate * 0
    except:
        return False


def ant6n_is_number(candidate):
    try:
        float(candidate)
        return True
    except:
        return False

# Test
candidates = (0, 0.0, 0j, decimal.Decimal(0),
              True, False, '', None, '0', '1', [], [1], [1, 2], (1, ), (1, 2))

methods = [delnan_is_number, mat_is_number, shrewmouse_is_number, ant6n_is_number]

print("Candidate    | type                      | delnan | mat | shrewmouse | ant6n")
print("-------------------------------------------------------------------------")
for candidate in candidates:
    results = [m(candidate) for m in methods]
    print("{:<12} | {:<25} | {:>6} | {:>3} | {:>10} | {:>5}"
          .format(repr(candidate), type(candidate), *results))


답변

아마도 다른 방법으로하는 것이 더 낫습니다. 벡터인지 확인합니다. 그렇다면 내적을 수행하고 다른 모든 경우에는 스칼라 곱셈을 시도합니다.

벡터는 벡터 클래스 유형 (또는 상 속됨)이어야하므로 벡터를 확인하는 것은 쉽습니다. 먼저 내적을 시도하고 실패하면 (= 실제로 벡터가 아님) 스칼라 곱셈으로 돌아갈 수 있습니다.