Python iterables的通用基类?
我正在尝试创建一个只接受iterable参数的方法,例如Python iterables的通用基类?,python,list,python-3.x,iterator,tuples,Python,List,Python 3.x,Iterator,Tuples,我正在尝试创建一个只接受iterable参数的方法,例如列表,元组,集或dict 这是我的密码: class MjmMenuControl(MjmBaseMenu): def __init__(self, items=None): iterables = (dict, list, set, tuple) for iterable in iterables: if isinstance(items, iterable):
列表
,元组
,集
或dict
这是我的密码:
class MjmMenuControl(MjmBaseMenu):
def __init__(self, items=None):
iterables = (dict, list, set, tuple)
for iterable in iterables:
if isinstance(items, iterable):
...
break
但是,我想知道是否有更简单的方法,例如如果是instance(items,):
但我什么也找不到
我已经尝试为列表
等查找基类,但它们似乎都来自对象
:
>>> inspect.getmro(list)
(<class 'list'>, <class 'object'>)
>>> inspect.getmro(tuple)
(<class 'tuple'>, <class 'object'>)
>inspect.getmro(列表)
(, )
>>>inspect.getmro(元组)
(, )
这是可能的还是我必须坚持使用可怕的for
循环?是的,使用:
但是,我会让方法假设它传递了一个iterable,调用者有责任确保传递了正确的类型
在Python3.3中是新的;它的内容以前存在于中,尽管名称即使在Python3.3及更高版本中仍在旧位置可用。collections.abc.Iterable选项的一个缺点是它无法处理像这样的自定义Iterable类
from collections.abc import Iterable
class MyIterable(object):
def __getitem__(self, index):
if index >= 10:
raise IndexError
return index
>>> myiter = MyIterable()
>>> isinstance(myiter, Iterable)
False
>>> [i for i in myiter]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
class MjmMenuControl(MjmBaseMenu):
def __init__(self, items=None):
if isinstance(items, (str, bytes)):
do_something_else()
else:
try:
for item in items:
do_something_with(item)
except TypeError:
# If we get here, 'items' is not iterable
do_something_else()
经常有人声称,实现这一点的“Pythonic”方法是使用,即尝试将对象视为一个iterable,并在其失败时处理异常。例如
class MjmMenuControl(MjmBaseMenu):
def __init__(self, items=None):
try:
for item in items:
do_something_with(item)
except TypeError:
# If we get here, 'items' is not iterable
do_something_else()
…但是,这两种方法都有一个缺点,就是将字符串视为与列表相同的东西,而列表通常不是您想要的。通常,您需要测试一个iterable容器,它与iterable稍有不同,因此通常会看到这样的代码将字符串视为特例
from collections.abc import Iterable
class MyIterable(object):
def __getitem__(self, index):
if index >= 10:
raise IndexError
return index
>>> myiter = MyIterable()
>>> isinstance(myiter, Iterable)
False
>>> [i for i in myiter]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
class MjmMenuControl(MjmBaseMenu):
def __init__(self, items=None):
if isinstance(items, (str, bytes)):
do_something_else()
else:
try:
for item in items:
do_something_with(item)
except TypeError:
# If we get here, 'items' is not iterable
do_something_else()
…这有点混乱,但完成了任务。非常感谢,我会尽快接受:)您能解释一下为什么它没有显示在
inspect.getmro()
中吗,我以为它显示了所有基类?此外,该方法接受任何类型的参数,但对不同的类型执行不同的操作,因此这就是我需要检查其是否可编辑的真正原因。我想举一个例子,让我的程序只接受一个iterable会更容易理解:)list
和tuple
在这里不是子类,它们只是碰巧实现相同协议的不同类型。没有iterable基类。如果需要改变行为,那么测试iterable
是一个不错的选择,是的。@qarma:我注意到Python 3文档中的状态最初是集合的一部分;Python 3版本也有别名。@Dan:如果需要单独处理字符串,当然可以。或者isinstance(foo,abc.Iterable)而不是isinstance(foo,str)
,等等。这取决于你想做什么,真的。“如果有更简单的方法”-是的,完全省略类型检查。顺便说一句,你实际上不需要for
循环,isinstance
可以将元组作为第二个参数,这样,如果第一个参数是元组中任何类的实例,它将返回True
。@volatile Ahh感谢您的提示。:)自从问题被标记为python-3.x之后,我已经将基串
改为(str,bytes)
,在python-3.x中,它们不再有一个公共子类(除了对象
)。你应该使用\uuuuiter\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu iter\uuuuuuuuuuuuuuuuuuuuuuuuu。我记得在这一点上与蒂姆·彼得斯(Tim Peters)进行了长时间的争论。他一直强调Python不是关于“继承”,而是关于“接口”,因为它允许您编写对参数类型更宽容的函数。当时我不同意他的意见,但现在对我来说更有意义了否,\uuuu getitem\uuuu
表示其他类型;例如,请参见序列
ABC,但也可以参见映射
ABC<代码>\uuuu getitem\uuuuuuuuuuuuuuuuuuu
支持旧式类型,而\uuuuuuu iter\uuuuuuuuuuuuuuuuuuuuuuuuuu
是最新添加的,您的新代码确实应该使用它。我没有注意到序列
和可伸缩性
之间的细微区别,尽管它们有点相似。有可能OP真正想要的是前者,而不是后者。TBH,我大约在15年前开始使用Python,但我还没有时间跟上所有新特性。我将不得不进一步调查