문제

입력 인수가 요소 또는 요소 목록이 될 수있는 함수가 있습니다. 이 인수가 단일 요소라면 목록에 넣어 입력을 일관된 방식으로 반복 할 수 있습니다.

현재 나는 이것을 가지고있다 :

def my_func(input):
    if not isinstance(input, list): input = [input]
    for e in input:
        ...

기존 API로 작업 중이므로 입력 매개 변수를 변경할 수 없습니다. isinstance ()를 사용하면 해킹 된 느낌이 듭니다. 적절한 이것을하는 방법?

도움이 되었습니까?

해결책

나는 Andrei Vajna의 제안을 좋아합니다 hasattr(var,'__iter__'). 이 결과는 일반적인 Python 유형에서 다음과 같습니다.

>>> hasattr("abc","__iter__")
False
>>> hasattr((0,),"__iter__")
True
>>> hasattr({},"__iter__")
True
>>> hasattr(set(),"__iter__")
True

이것은 문자열을 문화 불가능한 것으로 취급한다는 이점이 추가됩니다. 문자열은 회색 영역입니다. 때로는 요소로 취급하고 다른 경우에는 일련의 문자로 취급하기를 원합니다.

파이썬 3에서 str 유형 하다 가지고있다 __iter__ 속성과 이것은 작동하지 않습니다.

>>> hasattr("abc", "__iter__")
True

다른 팁

일반적으로 문자열 (일반 및 유니 코드)은 그럼에도 불구하고 "단일 요소"로 간주 할 유일한 반복입니다. basestring 내장은 특별히 다음과 같은 종류의 문자열을 테스트 할 수 있도록 특별히 존재합니다. isinstance, 그래서 그것은 특별한 경우에 매우 거친 일입니다 ;-).

그래서 가장 일반적인 경우에 대한 나의 제안 된 접근법은 다음과 같습니다.

  if isinstance(input, basestring): input = [input]
  else:
    try: iter(input)
    except TypeError: input = [input]
    else: input = list(input)

이것은 문자열을 제외한 모든 반복 가능한 모든 반복적 인 문자열을 직접 목록, 문자열 및 숫자 및 기타 비 문학적 테이블 (단일 항목 목록으로 정규화)으로 취급하는 방법입니다.

나는 모든 종류의 반복 가능한 목록을 명시 적으로 만들고 있으므로 실제 입력을 변경하지 않고도 모든 종류의 목록 트릭을 수행 할 수 있습니다. 분류, 반복, 반복을 추가 또는 제거하는 등의 목록 트릭을 수행 할 수 있습니다. 목록 (실제로 목록이면 ;-). 필요한 모든 것이 단일 평원입니다 for 루프는 마지막 단계가 불필요하다 (그리고 예를 들어 입력이 거대한 파일 인 경우 실제로 도움이되지 않음). 대신 보조 생성기를 제안합니다.

def justLoopOn(input):
  if isinstance(input, basestring):
    yield input
  else:
    try:
      for item in input:
        yield item
    except TypeError:
      yield input

이제 그러한 인수 정규화가 필요한 모든 기능에서 다음과 같이 사용합니다.

 for item in justLoopOn(input):

다른 경우에도 보조 정규화 기능을 사용할 수 있습니다 (추가 사악한 목적을 위해 실제 목록이 필요합니다). 실제로, 그러한 (드문) 사례에서는 다음과 같이 할 수 있습니다.

 thelistforme = list(justLoopOn(input))

(필연적으로) 다소 털이 정규화 로직이 한 곳에있는 것처럼!-)

첫째, 정의에 의해 목록이 다른 목록의 요소가 될 수 있기 때문에 "요소 목록"에서 "단일 요소"를 알 수있는 일반적인 방법은 없습니다.

나는 당신이 가질 수 있도록 어떤 종류의 데이터를 가지고 있는지 정의해야한다고 말합니다.

  • 의 후손 list 다른 것에 대해
    • 테스트 isinstance(input, list) (그래서 당신의 예제는 정확합니다)
  • 문자열을 제외한 모든 서열 유형 (basestring Python 2.X에서 str Python 3.x)
    • 시퀀스 메타 클래스 사용 : isinstance(myvar, collections.Sequence) and not isinstance(myvar, str)
  • 알려진 경우에 대한 일부 서열 유형 int, str, MyClass
    • 테스트 isinstance(input, (int, str, MyClass))
  • 문자열을 제외한 모든 반복 :
    • 테스트

.

    try: 
        input = iter(input) if not isinstance(input, str) else [input]
    except TypeError:
        input = [input]

당신은 * 당신의 논쟁 전에 * 넣을 수 있습니다.이 방법은 항상 튜플을 얻을 수 있습니다.

def a(*p):
  print type(p)
  print p

a(4)
>>> <type 'tuple'>
>>> (4,)

a(4, 5)
>>> <type 'tuple'>
>>> (4,5,)

그러나 변수 매개 변수로 기능을 호출해야합니다.

직접 유형 비교를 수행 할 수 있습니다 type().

def my_func(input):
    if not type(input) is list:
        input = [input]
    for e in input:
        # do something

그러나 당신이 가지고있는 방식은 허용됩니다 어느 파생 된 유형 list 통과 할 유형. 따라서 파생 된 유형이 실수로 래핑되는 것을 방지합니다.

당신의 aproach는 나에게 옳은 것 같습니다.

사용 방법과 비슷합니다 atom? LISP에서 목록을 반복하고 현재 항목을 확인하여 현재 항목이 목록인지 아닌지 확인하십시오. 목록이라면 항목을 처리하려고합니다.

그래, 그래, 그것에 잘못 보지 마세요.

그것은 그것을하는 괜찮은 방법입니다 (튜플을 포함하는 것을 잊지 마십시오).

그러나 논쟁에 __iter__가 있는지 고려할 수도 있습니다. 방법 또는 __getItem__ 방법. (문자열은 __iter__ 대신 __getItem__를 가지고 있습니다.)

hasattr(arg, '__iter__') or hasattr(arg, '__getitem__')

이것은 아마도 유형을 확인하는 것보다 목록과 같은 유형의 가장 일반적인 요구 사항 일 것입니다.

이것은 합리적인 방법처럼 보입니다. 요소가 목록인지 테스트하고 싶을 때 직접 수행합니다. 예를 들어 다른 '목록과 같은'데이터 유형을 지원하려면 더욱 복잡해집니다.

isinstance(input, (list, tuple))

또는 더 일반적으로 질문을 추상화합니다.

def iterable(obj):
  try:
    len(obj)
    return True
  except TypeError:
    return False

그러나 요약하면, 당신의 방법은 간단하고 정확합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top