변수가 반복 가능하지만 문자열이 아니라는 것을 알려주는 방법
단일 항목 또는 이중 항목이 될 수있는 인수를받는 함수가 있습니다.
def iterable(arg)
if #arg is an iterable:
print "yes"
else:
print "no"
그래서:
>>> iterable (( "f", "f")) 예 >>> 반복 가능 ([ "f", "f"]) 예 >>> iterable ( "ff") 아니
문제는 문자열이 기술적으로 반복 가능하므로 시도 할 때 ValueError를 잡을 수 없다는 것 arg[1]
입니다. isinstance ()는 좋은 습관이 아니기 때문에 사용하고 싶지 않습니다.
isinstance 사용 (왜 나쁜 습관인지 모르겠습니다)
import types
if not isinstance(arg, types.StringTypes):
StringTypes 사용에 유의하십시오. 모호한 유형의 문자열을 잊지 않도록합니다.
장점은 파생 된 문자열 클래스에서도 작동합니다.
class MyString(str):
pass
isinstance(MyString(" "), types.StringTypes) # true
또한이 이전 질문을 살펴볼 수도 있습니다 .
건배.
NB : 행동이 파이썬 3으로 변경 StringTypes
하고 basestring
더 이상 정의되지 않습니다. 필요에 따라, 당신은에 장착 할 수 isinstance
에 의해 str
, 또는 부분 집합의 튜플 (str, bytes, unicode)
사이 썬 사용자를위한, 예. 으로 @Theron Luhn는 했나요, 당신은 또한 사용할 수 있습니다 six
.
2017 년 현재 모든 버전의 Python에서 작동하는 휴대용 솔루션은 다음과 같습니다.
#!/usr/bin/env python
import collections
import six
def iterable(arg):
return (
isinstance(arg, collections.Iterable)
and not isinstance(arg, six.string_types)
)
# non-string iterables
assert iterable(("f", "f")) # tuple
assert iterable(["f", "f"]) # list
assert iterable(iter("ff")) # iterator
assert iterable(range(44)) # generator
assert iterable(b"ff") # bytes (Python 2 calls this a string)
# strings or non-iterables
assert not iterable(u"ff") # string
assert not iterable(44) # integer
assert not iterable(iterable) # function
추상 기본 클래스가 도입 된 Python 2.6 이후 isinstance
(구체적인 클래스가 아닌 ABC에서 사용됨)는 이제 완벽하게 허용되는 것으로 간주됩니다. 구체적으로 특별히:
from abc import ABCMeta, abstractmethod
class NonStringIterable:
__metaclass__ = ABCMeta
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is NonStringIterable:
if any("__iter__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
This is an exact copy (changing only the class name) of Iterable
as defined in _abcoll.py
(an implementation detail of collections.py
)... the reason this works as you wish, while collections.Iterable
doesn't, is that the latter goes the extra mile to ensure strings are considered iterable, by calling Iterable.register(str)
explicitly just after this class
statement.
Of course it's easy to augment __subclasshook__
by returning False
before the any
call for other classes you want to specifically exclude from your definition.
In any case, after you have imported this new module as myiter
, isinstance('ciao', myiter.NonStringIterable)
will be False
, and isinstance([1,2,3], myiter.NonStringIterable)
will be True
, just as you request -- and in Python 2.6 and later this is considered the proper way to embody such checks... define an abstract base class and check isinstance
on it.
I realise this is an old post but thought it was worth adding my approach for Internet posterity. The function below seems to work for me under most circumstances with both Python 2 and 3:
def is_collection(obj):
""" Returns true for any iterable which is not a string or byte sequence.
"""
try:
if isinstance(obj, unicode):
return False
except NameError:
pass
if isinstance(obj, bytes):
return False
try:
iter(obj)
except TypeError:
return False
try:
hasattr(None, obj)
except TypeError:
return True
return False
This checks for a non-string iterable by (mis)using the built-in hasattr
which will raise a TypeError
when its second argument is not a string or unicode string.
By combining previous replies, I'm using:
import types
import collections
#[...]
if isinstance(var, types.StringTypes ) \
or not isinstance(var, collections.Iterable):
#[Do stuff...]
Not 100% fools proof, but if an object is not an iterable you still can let it pass and fall back to duck typing.
Edit: Python3
types.StringTypes == (str, unicode)
. The Phython3 equivalent is:
if isinstance(var, str ) \
or not isinstance(var, collections.Iterable):
huh, don't get it... what's wrong with going
hasattr( x, '__iter__' )
?
... NB elgehelge puts this in a comment here, saying "look at my more detailed answer" but I couldn't find his/her detailed answer
later
In view of David Charles' comment about Python3, what about:
hasattr(x, '__iter__') and not isinstance(x, (str, bytes))
? Apparently "basestring" is no longer a type in Python3:
https://docs.python.org/3.0/whatsnew/3.0.html
The builtin basestring abstract type was removed. Use str instead. The str and bytes types don’t have functionality enough in common to warrant a shared base class.
As you point out correctly, a single string is a character sequence.
So the thing you really want to do is to find out what kind of sequence arg
is by using isinstance or type(a)==str.
If you want to realize a function that takes a variable amount of parameters, you should do it like this:
def function(*args):
# args is a tuple
for arg in args:
do_something(arg)
function("ff") and function("ff", "ff") will work.
I can't see a scenario where an isiterable() function like yours is needed. It isn't isinstance() that is bad style but situations where you need to use isinstance().
참고URL : https://stackoverflow.com/questions/1055360/how-to-tell-a-variable-is-iterable-but-not-a-string
'IT TIP' 카테고리의 다른 글
String.Substring ()이 코드에 병목 현상이있는 것 같습니다. (0) | 2020.10.24 |
---|---|
CUDA 고정 메모리가 그렇게 빠른 이유는 무엇입니까? (0) | 2020.10.24 |
1000 개의 Entity Framework 개체를 만들 때 SaveChanges ()를 언제 호출해야합니까? (0) | 2020.10.24 |
ASP.NET MVC에서 Error.cshtml은 어떻게 호출됩니까? (0) | 2020.10.24 |
어레이가 동일하게 유지 될 확률은 얼마입니까? (0) | 2020.10.24 |