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的答案