我有一个函数接受一个参数,可以是单个项目或双项目:
def iterable(arg) if #arg is an iterable: print "yes" else: print "no"
以便:
>>> iterable( ("f","f") ) yes >>> iterable( ["f","f"] ) yes >>> iterable("ff") no
问题是字符串在技术上是可迭代的,所以我不能在尝试时捕获ValueError arg[1]
.我不想使用isinstance(),因为这不是很好的做法(或者我被告知).
使用isinstance(我不明白为什么这是不好的做法)
import types if not isinstance(arg, types.StringTypes):
请注意StringTypes的使用.它确保我们不会忘记一些不起眼的字符串.
从好的方面来说,这也适用于派生的字符串类.
class MyString(str): pass isinstance(MyString(" "), types.StringTypes) # true
此外,您可能想看看上一个问题.
干杯.
注:行为在Python 3的改变StringTypes
和basestring
不再定义.根据您的需求,您可以取代他们isinstance
的str
,或子集元组(str, bytes, unicode)
,例如用于用Cython用户.正如@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
(用于ABCs,而不是具体类)现在被认为是完全可以接受的.特别:
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
这是完全相同的副本(只改变类名)Iterable
中定义_abcoll.py
(的实现细节collections.py
)...的原因,这可以作为你想,虽然collections.Iterable
不,是,后者更是不辞辛劳,以确保字符串通过Iterable.register(str)
在此class
语句之后显式调用,可以认为是可迭代的.
当然,__subclasshook__
通过False
在any
调用其他类之前返回来扩展很容易,这些类要从定义中明确排除.
在任何情况下,导入这个新模块之后myiter
,isinstance('ciao', myiter.NonStringIterable)
将会False
,并且isinstance([1,2,3], myiter.NonStringIterable)
将会True
像您要求的那样 - 在Python 2.6及更高版本中,这被认为是体现此类检查的正确方法...定义一个抽象基类并检查isinstance
它.