개발/Python

Python에서 유형을 확인하는 표준 방법은 무엇입니까?

MinorMan 2020. 9. 18. 03:19
반응형

<질문>

주어진 객체가 주어진 유형인지 확인하는 가장 좋은 방법은 무엇입니까? 객체가 주어진 유형에서 상속되는지 확인하는 것은 어떻습니까?

객체 o가 있다고 가정 해 봅시다. str인지 어떻게 확인합니까?


<답변1>

o가 str의 인스턴스인지 또는 str의 하위 클래스인지 확인하려면 isinstance를 사용합니다 ( "표준"방식).

if isinstance(o, str):

o의 유형이 정확히 str인지 확인하려면 (서브 클래스 제외) :

if type(o) is str:

다음도 작동하며 경우에 따라 유용 할 수 있습니다.

if issubclass(type(o), str):

관련 정보는 Python 라이브러리 참조의 내장 함수를 참조하십시오.

한 가지 더 참고 :이 경우 Python 2를 사용하는 경우 실제로 다음을 사용할 수 있습니다.

if isinstance(o, basestring):

이것은 또한 유니 코드 문자열을 잡을 것이기 때문입니다 (유니 코드는 str의 서브 클래스가 아닙니다; str과 unicode는 모두 basestring의 서브 클래스입니다). 문자열 (str)과 바이너리 데이터 (바이트)를 엄격하게 구분하는 Python 3에는 basestring이 더 이상 존재하지 않습니다.

또는 isinstance는 클래스의 튜플을 허용합니다. o가 (str, unicode)의 하위 클래스의 인스턴스이면 True를 반환합니다.

if isinstance(o, (str, unicode)):

<답변2>

객체의 유형을 확인하는 가장 파이썬적인 방법은 확인하지 않는 것입니다.

파이썬은 덕 타이핑을 장려하므로 객체의 메서드를 원하는 방식으로 사용하는 것을 제외하고는 시도해야합니다. 따라서 함수가 쓰기 가능한 파일 객체를 찾고 있다면 파일의 하위 클래스인지 확인하지 말고 .write () 메서드를 사용하십시오!

물론 때로는 이러한 멋진 추상화가 무너지고 isinstance (obj, cls)가 필요한 것입니다. 그러나 아껴서 사용하십시오.


<답변3>

isinstance (o, str)은 o가 str이거나 str에서 상속 된 유형이면 True를 반환합니다.

type (o) is str은 o가 str 인 경우에만 True를 반환합니다. o가 str에서 상속 된 유형이면 False를 반환합니다.


<답변4>

질문을 받고 답변 한 후 Python에 유형 힌트가 추가되었습니다. Python의 유형 힌트는 유형을 확인할 수 있지만 정적으로 유형이 지정된 언어와는 매우 다른 방식입니다. Python의 유형 힌트는 예상되는 인수 유형을 함수와 관련된 런타임 액세스 가능 데이터로 함수와 연결하며이를 통해 유형을 확인할 수 있습니다. 유형 힌트 구문의 예 :

def foo(i: int):
    return i

foo(5)
foo('oops')

이 경우 주석이 달린 인수 유형이 int이기 때문에 foo ( 'oops')에 대해 오류가 트리거되기를 원합니다. 추가 된 유형 힌트는 스크립트가 정상적으로 실행될 때 오류가 발생하지 않습니다. 그러나 다른 프로그램이 쿼리하고 유형 오류를 확인하는 데 사용할 수있는 예상 유형을 설명하는 함수에 속성을 추가합니다.

유형 오류를 찾는 데 사용할 수있는 다른 프로그램 중 하나는 mypy입니다.

mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"

(패키지 관리자에서 mypy를 설치해야 할 수도 있습니다. CPython과 함께 제공되지는 않지만 "공식"수준이있는 것 같습니다.)

이 방식의 유형 검사는 정적으로 유형이 지정된 컴파일 된 언어의 유형 검사와 다릅니다. 파이썬에서 유형은 동적이기 때문에 유형 검사는 런타임에 수행되어야하며, 올바른 프로그램에서도 모든 기회에 발생한다고 주장하면 비용이 발생합니다. 명시 적 유형 검사는 필요한 것보다 더 제한적일 수 있으며 불필요한 오류를 유발할 수 있습니다 (예 : 인수가 실제로 정확히 목록 유형이어야합니까, 아니면 충분한 반복 가능한 것이 있습니까?).

명시 적 유형 검사의 장점은 덕 타이핑보다 더 일찍 오류를 포착하고 더 명확한 오류 메시지를 제공 할 수 있다는 것입니다. 오리 유형의 정확한 요구 사항은 외부 문서로만 표현할 수 있으며 (완전하고 정확하길 바랍니다) 호환되지 않는 유형의 오류는 출처에서 멀리 떨어져 발생할 수 있습니다.

Python의 유형 힌트는 유형을 지정하고 확인할 수 있지만 일반적인 코드 실행 중에 추가 비용이 발생하지 않는 절충안을 제공하기위한 것입니다.

타이핑 패키지는 특정 유형을 요구하지 않고 필요한 동작을 표현하기 위해 유형 힌트에서 사용할 수있는 유형 변수를 제공합니다. 예를 들어, Iterable 및 Callable과 같은 변수를 포함하여 이러한 동작이있는 모든 유형의 필요성을 지정하는 힌트를 제공합니다.

유형 힌트는 유형을 확인하는 가장 파이썬적인 방법이지만 유형을 전혀 확인하지 않고 덕 타이핑에 의존하는 것이 더 파이썬적인 경우가 많습니다. 유형 힌트는 상대적으로 새롭고 가장 파이썬적인 솔루션 일 때 배심원 단은 여전히 외부에 있습니다. 비교적 논란의 여지가 없지만 매우 일반적인 비교 : 유형 힌트는 시행 할 수있는 문서 형식을 제공하고, 코드를 더 일찍 생성하고 더 쉽게 이해할 수있는 오류를 생성하고, 덕 타이핑이 할 수없는 오류를 포착 할 수 있으며, 정적으로 확인할 수 있습니다. 감각이지만 여전히 런타임 외부에 있습니다). 다른 한편으로, 오리 타이핑은 오랫동안 파이썬적인 방식이었고, 정적 타이핑의인지 적 오버 헤드를 부과하지 않으며, 덜 장황하며 모든 실행 가능한 유형을 받아 들일 것입니다.


<답변5>

다음은 위험 할 때를 모른 채 오리 타이핑이 나쁜 이유입니다. 예를 들어 다음은 Python 코드입니다 (적절한 들여 쓰기 생략 가능).이 상황은 isinstance 및 issubclassof 함수를 처리하여 피할 수 있습니다.

class Bomb:
    def __init__(self):
        ""

    def talk(self):
        self.explode()

    def explode(self):
        print "BOOM!, The bomb explodes."

class Duck:
    def __init__(self):
        ""
    def talk(self):
        print "I am a duck, I will not blow up if you ask me to talk."    

class Kid:
    kids_duck = None

    def __init__(self):
        print "Kid comes around a corner and asks you for money so he could buy a duck."

    def takeDuck(self, duck):
        self.kids_duck = duck
        print "The kid accepts the duck, and happily skips along"

    def doYourThing(self):
        print "The kid tries to get the duck to talk"
        self.kids_duck.talk()

myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()

<답변6>

isinstance(o, str)

문서 링크


<답변7>

유형의 __name__을 사용하여 변수 유형을 확인할 수 있습니다.

전의:

>>> a = [1,2,3,4]  
>>> b = 1  
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'

<답변8>

파이썬과 같은 동적 언어를 사용하는 것에 대한 멋진 점은 실제로 그런 것을 확인할 필요가 없다는 것입니다.

개체에 필요한 메서드를 호출하고 AttributeError를 잡을 것입니다. 나중에 이것은 테스트를 위해 개체를 조롱하는 것과 같은 다른 작업을 수행하기 위해 다른 (겉보기에 관련이없는) 개체와 함께 메서드를 호출 할 수 있습니다.

객체와 같은 파일을 반환하는 urllib2.urlopen ()을 사용하여 웹에서 데이터를 가져올 때 이것을 많이 사용했습니다. 이것은 실제 파일과 동일한 read () 메서드를 구현하기 때문에 파일에서 읽는 거의 모든 메서드에 전달 될 수 있습니다.

하지만 isinstance ()를 사용할 시간과 장소가 있다고 확신합니다. 그렇지 않으면 아마 거기에 없을 것입니다. :)


<답변9>

더 복잡한 유형 유효성 검사의 경우 파이썬 유형 힌트 주석을 기반으로 유효성을 검사하는 typeguard의 접근 방식을 좋아합니다.

from typeguard import check_type
from typing import List

try:
    check_type('mylist', [1, 2], List[int])
except TypeError as e:
    print(e)

매우 깔끔하고 읽기 쉬운 방식으로 매우 복잡한 유효성 검사를 수행 할 수 있습니다.

check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo) 

<답변10>

휴고에게 :

아마도 배열보다는 목록을 의미하지만 유형 검사의 전체 문제를 가리 킵니다. 문제의 객체가 목록인지 알고 싶지 않고 어떤 종류의 시퀀스인지 아니면 단일인지 알고 싶습니다. 목적. 그래서 그것을 시퀀스처럼 사용하십시오.

개체를 기존 시퀀스에 추가하거나 개체 시퀀스 인 경우 모두 추가한다고 가정 해 보겠습니다.

try:
   my_sequence.extend(o)
except TypeError:
  my_sequence.append(o)

이것에 대한 한 가지 트릭은 문자열 및 / 또는 문자열 시퀀스로 작업하는 경우입니다. 문자열은 종종 단일 객체로 간주되지만 문자 시퀀스이기도하므로 까다 롭습니다. 실제로 단일 길이 문자열의 시퀀스이기 때문에 그보다 더 나쁩니다.

일반적으로 단일 값 또는 시퀀스 만 허용하도록 API를 디자인하기로 선택합니다. 이렇게하면 작업이 더 쉬워집니다. 필요한 경우 전달할 때 단일 값 주위에 []를 넣는 것은 어렵지 않습니다.

(이로 인해 문자열이 시퀀스처럼 보이므로 오류가 발생할 수 있습니다.)


<답변11>

유형을 확인하는 간단한 방법은 유형을 알고있는 것과 비교하는 것입니다.

>>> a  = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True

<답변12>

가장 좋은 방법은 변수를 잘 입력하는 것입니다. "typing"라이브러리를 사용하여이를 수행 할 수 있습니다.

예:

입력에서 import NewType UserId = NewType ( 'UserId', int) some_id = UserId (524313)`

https://docs.python.org/3/library/typing.html 참조


<답변13>

아래 줄에서 주어진 값이 어떤 문자 유형인지 확인할 수 있습니다.

def chr_type(chrx):
    if chrx.isalpha()==True:
        return 'alpha'
    elif chrx.isdigit()==True:
        return 'numeric'
    else:
        return 'nothing'

chr_type("12)
반응형