Python 如何判断变量是可编辑的而不是字符串

Python 如何判断变量是可编辑的而不是字符串,python,Python,我有一个函数,它接受的参数可以是单个项,也可以是双项: def iterable(arg) if #arg is an iterable: print "yes" else: print "no" 以便: >>> iterable( ("f","f") ) yes >>> iterable( ["f","f"] ) yes >>> iterable("ff") no >>>iterable((“f”,“f”)) 对 >>>iterable([

我有一个函数,它接受的参数可以是单个项,也可以是双项:

def iterable(arg)
    if #arg is an iterable:
        print "yes"
    else:
        print "no"
以便:

>>> iterable( ("f","f") ) yes >>> iterable( ["f","f"] ) yes >>> iterable("ff") no >>>iterable((“f”,“f”)) 对 >>>iterable([“f”,“f”]) 对 >>>可编辑(“ff”) 不 问题是字符串在技术上是可编辑的,所以在尝试
arg[1]
时,我无法捕获ValueError。我不想使用isinstance(),因为这不是好的做法(或者我被告知是这样)。

使用isinstance(我不明白为什么它是坏做法)

请注意StringType的使用。它确保了我们不会忘记一些晦涩难懂的字符串类型

从正面来看,这也适用于派生字符串类

class MyString(str):
    pass

isinstance(MyString("  "), types.StringTypes) # true
另外,你可能想看看这个

干杯


NB:由于不再定义
StringTypes
basestring
而改变了Python 3中的行为。根据您的需要,您可以使用
str
(str,bytes,unicode)
的子集元组来替换
isinstance
中的它们,例如用于Cython用户。
如前所述,您还可以使用
six

正如您正确指出的,单个字符串是一个字符序列

因此,您真正想要做的是通过使用isinstance或type(a)==str找出序列的类型
arg

如果您想实现一个接受可变数量参数的函数,您应该这样做:

def function(*args):
    # args is a tuple
    for arg in args:
        do_something(arg)
功能(“ff”)和功能(“ff”、“ff”)将起作用


我看不到需要像您这样的isiterable()函数的场景。不是isinstance()风格不好,而是在需要使用isinstance()的情况下。

由于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
这是
\u abcoll.py
中定义的
Iterable
(collections.py
的实现细节)的精确副本(仅更改类名)。。。这是因为
collections.Iterable
不能满足您的要求,而
collections.Iterable
不能满足您的要求,因为后者在该
class
语句之后显式调用
Iterable.register(str)
以确保字符串被视为Iterable

当然,在
调用要明确从定义中排除的其他类之前,通过返回
False
可以很容易地扩充
\uuuu子类hook\uuuuu


在任何情况下,当您将此新模块作为
myiter
导入后,
isinstance('ciao',myiter.NonStringIterable)
将为
False
isinstance([1,2,3],myiter.NonStringIterable)
将为
True
,正如您所要求的——在Python2.6和更高版本中,这被认为是体现此类检查的正确方式。。。定义一个抽象基类,并检查它是否存在。

我意识到这是一篇老文章,但我认为值得为互联网后代添加我的方法。在Python 2和Python 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

这将通过(mis)使用内置的
hasattr
检查不可输入的字符串,当其第二个参数不是字符串或unicode字符串时,将引发
TypeError

结合前面的答复,我使用:

import types
import collections

#[...]

if isinstance(var, types.StringTypes ) \
    or not isinstance(var, collections.Iterable):

#[Do stuff...]
不是100%万无一失的,但如果一个对象不是一个可移植对象,你仍然可以让它通过,然后退回到duck类型


编辑:Python3

types.StringTypes==(str,unicode)
。Phython3等效物为:

if isinstance(var, str ) \
    or not isinstance(var, collections.Iterable):
if isinstance(var, str ) \
    or not isinstance(var, collections.abc.Iterable):

编辑:Python3.3

types.StringTypes==(str,unicode)
。Phython3等效物为:

if isinstance(var, str ) \
    or not isinstance(var, collections.Iterable):
if isinstance(var, str ) \
    or not isinstance(var, collections.abc.Iterable):
2.x 我会建议:

hasattr(x, '__iter__')
或者鉴于David Charles对Python3的评论,那么:

hasattr(x, '__iter__') and not isinstance(x, (str, bytes))
3.x
内置的
basestring
抽象类型。改用
str
str
bytes
类型没有足够的共同功能来保证共享基类。

从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

要明确地扩展Alex Martelli的优秀技巧并解决一些相关问题:python 3.6+中当前的工作解决方案是

import collections
import _collections_abc as cabc
import abc


class NonStringIterable(metaclass=abc.ABCMeta):

    __slots__ = ()

    @abc.abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, c):
        if cls is NonStringIterable:
            if issubclass(c, str):
                return False
            return cabc._check_methods(c, "__iter__")
        return NotImplemented
并证明

>>> typs = ['string', iter(''), list(), dict(), tuple(), set()]
>>> [isinstance(o, NonStringIterable) for o in typs]
[False, True, True, True, True, True]
例如,如果要在排除项中添加
iter(“”)
,请修改行

            if issubclass(c, str):
                return False
将来

得到

[False, False, True, True, True, True]

Python的哪个版本?我相信答案在2.*和3之间是不同的。你被错误地告知,isinstance不是坏做法。哦,等等,也许他指的是检查对象类型不好的原则,这表明程序被破坏了?这在原则上是正确的(但在实践中并不总是如此)。这种情况可能是,也可能不是。但问题不是函数是否存在,而是检查类型的习惯。@Lennart:可能已经过时了though@up不过,这并没有提到基于类型的函数重载,而在动态类型语言中,
isinstance
是实现这一点的方法。不是每天都用的东西,但在合理的情况下也可以。很好,scvalex。我现在正在删除我的-1,并将其改为+1:-)。我认为这种不好的练习想法是因为这个原则。作为特定类的成员并不意味着它是唯一可以使用的对象,也不意味着预期的方法可用。但我认为有时即使存在该方法,也无法推断该方法的作用,因此
isinstance
可能是唯一的方法。注意:types.StringTypes在Python 3中不可用。由于py3k中只有一种字符串类型,我认为
执行isinstance(arg,str)
是安全的。对于向后兼容的版本,请考虑使用i严格使用Python 3并注意<代码>类型。StringTypes < /COD>在Python 3中不可用。Python2中的值是什么?2017:这个答案不再有效,请参阅适用于所有v的答案