当前位置:  开发笔记 > 编程语言 > 正文

检测序列参数的正确方法?

如何解决《检测序列参数的正确方法?》经验,为你挑选了2个好方法。

我想编写一个接受参数的函数,该参数可以是序列也可以是单个值.值的类型是str,int等,但我希望它被限制为硬编码列表.换句话说,我想知道参数X是否是一个序列或我必须转换为序列以避免以后的特殊套管.我可以

type(X) in (list, tuple)

但是可能还有其他我不知道的序列类型,也没有共同的基类.

-N.

编辑:请参阅下面的"答案",了解为何大多数答案对我没有帮助.也许你有更好的建议.



1> A. Coady..:

从2.6开始,使用抽象基类.

>>> import collections
>>> isinstance([], collections.Sequence)
True
>>> isinstance(0, collections.Sequence)
False

此外,ABC可以定制以解释异常,例如不将字符串视为序列.这是一个例子:

import abc
import collections

class Atomic(object):
    __metaclass__ = abc.ABCMeta
    @classmethod
    def __subclasshook__(cls, other):
        return not issubclass(other, collections.Sequence) or NotImplemented

Atomic.register(basestring)

注册后,Atomic类可以与isinstanceissubclass一起使用:

assert isinstance("hello", Atomic) == True

这仍然比硬编码列表好得多,因为您只需要在规则中注册例外,并且代码的外部用户可以注册自己的.

请注意,在Python 3中,指定元类的语法已更改,并且basestring删除了抽象超类,这需要使用以下内容:

class Atomic(metaclass=abc.ABCMeta):
    @classmethod
    def __subclasshook__(cls, other):
        return not issubclass(other, collections.Sequence) or NotImplemented

Atomic.register(str)

如果需要,可以编写兼容Python 2.6+ 3.x的代码,但这样做需要使用稍微复杂的技术来动态创建所需的抽象基类,从而避免由于元类语法差异导致的语法错误.这与Benjamin Peterson的六个模块的with_metaclass()功能基本相同.

class _AtomicBase(object):
    @classmethod
    def __subclasshook__(cls, other):
        return not issubclass(other, collections.Sequence) or NotImplemented

class Atomic(abc.ABCMeta("NewMeta", (_AtomicBase,), {})):
    pass

try:
    unicode = unicode
except NameError:  # 'unicode' is undefined, assume Python >= 3
    Atomic.register(str)  # str includes unicode in Py3, make both Atomic
    Atomic.register(bytes)  # bytes will also be considered Atomic (optional)
else:
    # basestring is the abstract superclass of both str and unicode types
    Atomic.register(basestring)  # make both types of strings Atomic

在2.6之前的版本中,operator模块中有类型检查器.

>>> import operator
>>> operator.isSequenceType([])
True
>>> operator.isSequenceType(0)
False


>>>断言operator.isSequenceType("hello")== True(正如其他地方指出的那样,字符串是后遗症,而Coady我很清楚......原来的问题是不合适的.

2> Gregg Lind..:

所有上述方法的问题在于str被认为是一个序列(它是可迭代的,有getitem等),但它通常被视为单个项目.

例如,函数可以接受可以是文件名或文件名列表的参数.函数从后者检测第一个函数的最Pythonic方法是什么?

根据修改后的问题,听起来你想要的更像是:

def to_sequence(arg):
    ''' 
    determine whether an arg should be treated as a "unit" or a "sequence"
    if it's a unit, return a 1-tuple with the arg
    '''
    def _multiple(x):  
        return hasattr(x,"__iter__")
    if _multiple(arg):  
        return arg
    else:
        return (arg,)

>>> to_sequence("a string")
('a string',)
>>> to_sequence( (1,2,3) )
(1, 2, 3)
>>> to_sequence( xrange(5) )
xrange(5)

这并不能保证处理所有类型,但它会处理你提到的案例,并且应该为大多数内置类型做正确的事情.

使用它时,请确保接收到的输出可以处理迭代.


正如@Jim Brissom在关于[这个答案]的评论中指出的那样(http://stackoverflow.com/questions/4237434/pythonic-way-to-verify-parameter-is-a-sequence-but-not-string/4237502 #4237502)对于一个相关的问题,没有`__iter__`属性的字符串是一个在Python 3中修复的差异,这使得这种方法转发 - 不兼容.
推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有