이것이 내가 일반적으로 입력이 있음을 확인하기 위하여 않는 것입니다 list
/ tuple
아니지만 - str
. 함수가 str
실수 로 객체를 전달하는 버그를 여러 번 발견했기 때문에 대상 함수 는 실제로 또는로 for x in lst
가정합니다 .lst
list
tuple
assert isinstance(lst, (list, tuple))
내 질문은 : 이것을 달성하는 더 좋은 방법이 있습니까?
이것이 내가 일반적으로 입력이 있음을 확인하기 위하여 않는 것입니다 list
/ tuple
아니지만 - str
. 함수가 str
실수 로 객체를 전달하는 버그를 여러 번 발견했기 때문에 대상 함수 는 실제로 또는로 for x in lst
가정합니다 .lst
list
tuple
assert isinstance(lst, (list, tuple))
내 질문은 : 이것을 달성하는 더 좋은 방법이 있습니까?
답변:
파이썬 2에서만 (파이썬 3 아님) :
assert not isinstance(lst, basestring)
실제로 원하는 것입니다. 그렇지 않으면 목록처럼 작동하지만 list
또는의 하위 클래스가 아닌 많은 것들을 놓칠 수 tuple
있습니다.
basestring
사라졌으며 확인하십시오 isinstance(lst, str)
.
set
생성자 표현식, 반복자). 같은 이국적인 것들이 있습니다 mmap
. 덜 이국적인 것들이 array
목록과 거의 비슷하게 작용하며 아마도 잊어 버린 것들이 더 많습니다.
lst
원본이 수행하는 동안 (예 : int가이 검사를 통과 할 때) 이것이 반복 가능 하다는 보장은하지 않습니다.
assert isinstance(lst, (list, tuple)) and assert not isinstance(lst, basestring)
파이썬에서는 "오리 타이핑"을 사용하고 싶다는 것을 기억하십시오. 따라서 목록처럼 작동하는 모든 것을 목록으로 취급 할 수 있습니다. 따라서 목록의 유형을 확인하지 말고 목록처럼 작동하는지 확인하십시오.
그러나 문자열도 목록처럼 작동하며 종종 우리가 원하는 것이 아닙니다. 심지어 문제 일 때도 있습니다! 따라서 문자열을 명시 적으로 확인한 다음 오리 타이핑을 사용하십시오.
다음은 내가 재미있게 작성한 기능입니다. repr()
꺾쇠 괄호 ( '<', '>')로 시퀀스를 인쇄 하는 특수 버전입니다 .
def srepr(arg):
if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
return repr(arg)
try:
return '<' + ", ".join(srepr(x) for x in arg) + '>'
except TypeError: # catch when for loop fails
return repr(arg) # not a sequence so just return repr
이것은 전체적으로 깨끗하고 우아합니다. 그러나 그 isinstance()
검사는 무엇 입니까? 그것은 일종의 해킹입니다. 그러나 필수입니다.
이 함수는 목록처럼 작동하는 모든 것을 재귀 적으로 호출합니다. 문자열을 특수하게 처리하지 않으면 목록처럼 취급되어 한 번에 한 문자 씩 분할됩니다. 그러나 재귀 호출은 각 문자를 목록으로 취급하려고 시도하며 작동합니다! 한 문자 문자열조차도 목록으로 작동합니다! 이 함수는 스택 오버플로가 발생할 때까지 계속 재귀 적으로 호출합니다.
수행 할 작업을 세분화하는 각 재귀 호출에 의존하는 이와 같은 함수는 문자열을 특수 사례로 묶어야합니다. 한 문자열 이하의 문자열을 분해 할 수 없기 때문에 -문자열은 목록처럼 작동합니다.
참고 : try
/ except
는 의도를 표현하는 가장 깨끗한 방법입니다. 그러나이 코드가 어떻게 시간이 중요하다면, 우리는이 코드가 arg
시퀀스 인지 확인하기 위해 일종의 테스트로 대체하고 싶을 것입니다 . 유형을 테스트하는 대신 동작을 테스트해야합니다. .strip()
메서드 가 있으면 문자열이므로 시퀀스로 간주하지 마십시오. 그렇지 않으면 색인 가능하거나 반복 가능하면 시퀀스입니다.
def is_sequence(arg):
return (not hasattr(arg, "strip") and
hasattr(arg, "__getitem__") or
hasattr(arg, "__iter__"))
def srepr(arg):
if is_sequence(arg):
return '<' + ", ".join(srepr(x) for x in arg) + '>'
return repr(arg)
편집 : 원래 위의 내용을 확인 __getslice__()
했지만 collections
모듈 설명서에서 흥미로운 방법은 다음과 같습니다 __getitem__()
. 이것은 의미가 있습니다. 이것이 객체를 색인하는 방법입니다. 그보다 더 근본적인 것처럼 보이 __getslice__()
므로 위의 내용을 변경했습니다.
srepr
매우 흥미로운 아이디어입니다. 그러나 나는 특별한 경우가 필요한지에 대해 당신과 다른 의견을 가지고 있습니다 str
. 그렇습니다 . str
에서 무한 재귀를 일으키는 가장 명백하고 일반적인 반복 가능입니다 srepr
. 그러나 나는 타당한 이유가 있거나없는 동일한 방식으로 동작하는 사용자 정의 반복 가능을 쉽게 상상할 수 있습니다. 특별한 경우가 아니라 str
, 우리는이 접근법이 무한한 재귀를 겪을 수 있음을 인정하고 그것을 다루는 방법에 동의해야합니다. 답변에 제 제안을 게시하겠습니다.
srepr()
괜찮다고 생각 합니다. 우리는 다른리스트 안에 중첩 된리스트와 같은 것을 처리하기 위해 재귀 함수가 필요하다. 그러나 문자열의 "foo"
경우보다로 인쇄해야합니다 <'f', 'o', 'o'>
. 따라서 문자열을 명시 적으로 확인하는 것이 좋습니다. 또한 반복이 항상 반복 가능 을 반환하고 재귀로 인해 스택 오버플로가 항상 발생하는 데이터 유형의 다른 예는 실제로 없습니다 . 따라서이를 테스트하기 위해 특별한 속성이 필요하지 않습니다 ( "실용성이 순도").
__iter__()
파이썬 3의 방법을하지만, 파이썬 2에서 당신은 괄호를 누락하지 is_sequence()
, 그것을 읽어야합니다return (not hasattr(arg, "strip") and (hasattr(arg, "__getitem__") or hasattr(arg, "__iter__")))
H = "Hello"
if type(H) is list or type(H) is tuple:
## Do Something.
else
## Do Something.
if isinstance( H, (list, tuple) ): ...
더 짧고 명확합니다.
if type(H) in [list, tuple]:
파이썬 3의 경우 :
import collections.abc
if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
print("obj is a sequence (list, tuple, etc) but not a string")
버전 3.3으로 변경 : Collections 추상베이스 클래스를 collections.abc 모듈로 이동했습니다. 이전 버전과의 호환성을 위해 버전 3.8까지 작동을 멈출 때까지이 모듈에서 계속 볼 수 있습니다.
파이썬 2의 경우 :
import collections
if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
print "obj is a sequence (list, tuple, etc) but not a string or unicode"
collections.Sequence
테스트 해 보았습니다. 그렇습니다 xrange
. 더 나은,이 테스트 제외 dict
, 모두 갖고 __getitem__
와 __iter__
.
inspect.getmro(list)
포함 Sequence
되지 않습니까? 우리가 모든 것을 보여주지 않을 isinstance
때 우리가 할 수있는 일을 어떻게 알아 내야 getmro
합니까?
Sequence
추상 클래스입니다.
PHP 풍미를 가진 파이썬 :
def is_array(var):
return isinstance(var, (list, tuple))
__getitem__
. 또한 배열 모듈이 있기 때문에 이름이 잘못되었습니다. 그리고 var은 numpy.ndarray 또는 다른 유형일 수도 있습니다 __getitem__
. 정답 은 stackoverflow.com/a/1835259/470560 을 참조하십시오 .
str
또한 __getitem__
귀하의 수표가 제외되지 않습니다str
__getitem__
것은 나쁜 조언입니다.
일반적으로 객체를 반복하는 함수는 튜플 및 목록뿐만 아니라 문자열에서도 작동한다는 사실은 버그보다 더 많은 기능입니다. 당신은 확실히 할 수 사용 isinstance
하거나 입력 오리 인수를 확인하기 위해, 그런데 왜 당신해야?
그것은 수사적인 질문처럼 들리지만 그렇지 않습니다. "왜 인수 유형을 확인해야합니까?" 아마도 인식 된 문제가 아니라 실제 문제에 대한 해결책을 제안 할 것입니다. 문자열이 함수에 전달 될 때 왜 버그입니까? 또한 : 문자열 이이 함수에 전달 될 때 버그 인 경우 목록이 아닌 튜플 iterable이 아닌 다른 것이 전달됩니까? 그 이유는 무엇?
질문에 대한 가장 일반적인 대답은 글을 쓰는 개발자 f("abc")
가 작성한 것처럼 함수가 작동하기를 기대하고 있을 가능성이 있다고 생각합니다 f(["abc"])
. 문자열의 문자를 반복하는 유스 케이스를 지원하는 것보다 개발자를 스스로 보호하는 것이 더 합리적인 상황 일 수 있습니다. 그러나 나는 그것에 대해 먼저 길고 열심히 생각할 것입니다.
가독성과 모범 사례를 위해 다음을 시도하십시오.
파이썬 2
import types
if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType):
# Do something
파이썬 3
import typing
if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple):
# Do something
도움이 되길 바랍니다.
AttributeError: module 'types' has no attribute 'ListType'
from typing import List
-> isinstance([1, 2, 3], List
= True
이고 isinstance("asd", List)
= False
str
객체는없는 __iter__
속성을
>>> hasattr('', '__iter__')
False
그래서 당신은 확인을 할 수 있습니다
assert hasattr(x, '__iter__')
그리고 이것은 AssertionError
반복 불가능한 다른 객체에도 좋을 것 입니다.
편집 : Tim이 주석에서 언급했듯이 이것은 3.x가 아닌 python 2.x에서만 작동합니다.
hasattr('','__iter__')
반환합니다 True
. 물론 문자열을 반복 할 수 있기 때문에 의미가 있습니다.
이것은 OP에 직접 대답하기위한 것이 아니라 관련 아이디어를 공유하고 싶었습니다.
나는 위의 @ steveha 답변에 매우 관심이 있었고 오리 타이핑이 깨지는 것처럼 보이는 예를 보였습니다. 그러나 두 번째 생각으로, 그의 예는 오리 타이핑이 준수하기 어렵다는 것을 제안하지만, 특별한 취급 이 필요 하다는 것은 아닙니다str
.
결국, 비 str
유형 (예를 들어, 복잡한 재귀 구조를 유지하는 사용자 정의 유형)은 @steveha srepr
함수가 무한 재귀를 유발할 수 있습니다 . 이 방법은 다소 드물지만이 가능성을 무시할 수는 없습니다. 따라서, 특별-케이스 대신 str
에 srepr
, 우리는 우리가 원하는 것을 명확히해야 srepr
할 때 무한 재귀 결과 할 수 있습니다.
하나의 합리적인 접근 방식은 간단에서 재귀를 파괴하는 것입니다 것처럼 보일 수 있습니다 srepr
순간 list(arg) == [arg]
. 실제로 이것은로 문제를 완전히 해결할 str
것 isinstance
입니다.
그러나 매우 복잡한 재귀 구조는 list(arg) == [arg]
결코 발생하지 않는 무한 루프를 일으킬 수 있습니다 . 따라서 위의 검사는 유용하지만 충분하지 않습니다. 재귀 깊이에 대한 하드 제한과 같은 것이 필요합니다.
내 요점은 임의의 인수 유형을 처리하려는 경우 str
오리 이론을 통해 처리하는 것이 일반적인 이론 유형보다 더 일반적인 유형을 처리하는 것보다 훨씬 쉽다는 것입니다. 따라서 str
인스턴스 를 제외 해야한다고 생각하면 인수가 명시 적으로 지정하는 몇 가지 유형 중 하나의 인스턴스 여야합니다.
str
합니다. 특수 사례 코드가 처리하는 공통 사례가 정확히 하나 있습니다. 그러나 코드가 검사 할 수있는 새로운 표준 속성 .__atomic__
이있을 수 있습니다. atomic()
파이썬 에 다른 내장 함수를 추가하기에는 너무 늦었을 수도 있지만 추가 from collections import atomic
하거나 무언가를 추가 할 수 있습니다 .
tensorflow에서 is_sequence 라는 함수 를 찾습니다 .
def is_sequence(seq):
"""Returns a true if its input is a collections.Sequence (except strings).
Args:
seq: an input sequence.
Returns:
True if the sequence is a not a string and is a collections.Sequence.
"""
return (isinstance(seq, collections.Sequence)
and not isinstance(seq, six.string_types))
그리고 귀하의 요구를 충족시키는 것으로 확인되었습니다.
내 테스트 케이스 에서이 작업을 수행합니다.
def assertIsIterable(self, item):
#add types here you don't want to mistake as iterables
if isinstance(item, basestring):
raise AssertionError("type %s is not iterable" % type(item))
#Fake an iteration.
try:
for x in item:
break;
except TypeError:
raise AssertionError("type %s is not iterable" % type(item))
발전기에서 테스트하지 않은 상태에서 발전기를 통과하면 다음 '수율'에 남아있어 다운 스트림을 망칠 수 있습니다. 그러나 다시, 이것은 '유니트 테스트'입니다
「오리 타이핑」방식으로 어떻습니까
try:
lst = lst + []
except TypeError:
#it's not a list
또는
try:
lst = lst + ()
except TypeError:
#it's not a tuple
각기. 이것은 isinstance
/ hasattr
내부 검사를 피합니다 .
당신은 또한 그 반대로 확인할 수 있습니다 :
try:
lst = lst + ''
except TypeError:
#it's not (base)string
모든 변형은 실제로 변수의 내용을 변경하지 않지만 재 할당을 암시합니다. 일부 환경에서는 이것이 바람직하지 않을 수 있습니다.
흥미롭게도, "in place"할당 으로 어떤 경우에도 리스트 가 없다면 ( tuple이 아님) 발생 +=
하지 TypeError
않을 것 입니다. 이것이 과제가 이런 식으로 수행되는 이유입니다. 어쩌면 누군가가 왜 그런지 밝힐 수 있습니다.lst
가장 간단한 방법은 ...을 사용 any
하고isinstance
>>> console_routers = 'x'
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
False
>>>
>>> console_routers = ('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
>>> console_routers = list('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
문자열 형 객체를 다른 시퀀스 형 객체와 구별하는 데 도움이되는 다른 오리 타이핑 버전입니다.
문자열 같은 객체의 문자열 표현은 문자열 자체이므로 str
생성자 에서 동일한 객체를 다시 얻을 수 있는지 확인할 수 있습니다 .
# If a string was passed, convert it to a single-element sequence
if var == str(var):
my_list = [var]
# All other iterables
else:
my_list = list(var)
이것은 str
모든 종류의 반복 가능한 객체와 호환되는 모든 객체에 적용됩니다 .
파이썬 3에는 다음이 있습니다.
from typing import List
def isit(value):
return isinstance(value, List)
isit([1, 2, 3]) # True
isit("test") # False
isit({"Hello": "Mars"}) # False
isit((1, 2)) # False
따라서 List와 Tuple을 모두 확인하려면 다음과 같습니다.
from typing import List, Tuple
def isit(value):
return isinstance(value, List) or isinstance(value, Tuple)
assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"
파이썬에서> 3.6
import collections
isinstance(set(),collections.abc.Container)
True
isinstance([],collections.abc.Container)
True
isinstance({},collections.abc.Container)
True
isinstance((),collections.abc.Container)
True
isinstance(str,collections.abc.Container)
False
str
문자열이 아닌 type을 사용 합니다. 시도 isinstance('my_string', collections.abc.Container)
하고 당신은 그것이 반환됩니다 볼 수 있습니다 True
. 이 때문이다 abc.Container
공급한다 __contains__
방법, 문자열 물론, 그것이있다.
나는 이것을하는 경향이 있습니다 (내가 정말로 정말로해야한다면) :
for i in some_var:
if type(i) == type(list()):
#do something with a list
elif type(i) == type(tuple()):
#do something with a tuple
elif type(i) == type(str()):
#here's your string
some_var
하위 클래스 인 클래스의 인스턴스 인 경우 어떻게됩니까 list()
? 코드는 "목록으로 무언가 수행"코드에서 완벽하게 작동하지만 코드로 무엇을해야할지 전혀 모릅니다. 그리고리스트와 튜플의 차이점에 대해 거의 신경 쓸 필요가 없습니다. 죄송합니다 -1
type(tuple())
- tuple
할 수 없습니다. 목록과 동일합니다. 또한 실제 문자열 유형 인 str
및 unicode
extend 모두 basestring
대신 확인하십시오.
type(i) is list
. 또한, type(list())
그냥 list
그 자체 ... 마지막으로,이 서브 클래스와 함께 정상적으로 작동하지 않습니다. 경우 i
사실과 OrderedDict, 또는 namedtuple의 일종이며, 취급이 코드를 문자열로입니다.