Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python `映射类保函数序列类型_Python_List_Python 2.7_Generator - Fatal编程技术网

Python `映射类保函数序列类型

Python `映射类保函数序列类型,python,list,python-2.7,generator,Python,List,Python 2.7,Generator,我想实现一个类似于map的函数,它保留了输入序列的类型映射不保留它: map(str, (8, 9)) # input is a tuple => ['8', '9'] # output is a list 我想到的一个方法是: def map2(f, seq): return type(seq)( f(x) for x in seq ) map2(str, (1,2)) => ('1', '2') map2(str, [3,4]) => ['3', '4'

我想实现一个类似于map的
函数,它保留了输入序列的类型<代码>映射
不保留它:

map(str, (8, 9))  # input is a tuple
=> ['8', '9']     # output is a list
我想到的一个方法是:

def map2(f, seq):
   return type(seq)( f(x) for x in seq )

map2(str, (1,2))
=> ('1', '2')
map2(str, [3,4])
=> ['3', '4']
map2(str, deque([5,6]))
=> deque(['5', '6'])
但是,如果
seq
是迭代器/生成器,则这不起作用<代码>imap在这种情况下起作用

因此,我的问题是:

  • 有没有更好的方法来实现支持列表、元组和其他许多功能的
    map2
  • 是否有一种优雅的方式来扩展
    map2
    以同时支持生成器(比如
    imap
    does)?显然,我希望避免:
    try:returnmap2(…),TypeError:returnimap(…)
  • 我之所以要寻找这样的东西,是因为我正在编写一个函数装饰器,将返回值从类型X转换为Y。如果原始函数返回一个序列(假设序列只能是列表、元组或生成器),我假设它是一个X序列,我想把它转换成相应的Y序列(同时保留序列的类型)


    您可能已经意识到,我使用的是python 2.7,但python 3也很有趣。

    您的形式主义也不适用于
    map(str,'12')

    最终,您不知道iterable类型在构造函数/初始值设定项中实际将采用什么参数,因此通常无法做到这一点。还要注意的是,
    imap
    没有提供与生成器相同的类型:

    >>> type(x for x in range(10))
    <type 'generator'>
    >>> type(imap(str,range(10)))
    <type 'itertools.imap'>
    >>> isinstance((x for x in range(10)),type(imap(str,range(10))))
    False
    
    >>类型(x代表范围(10)内的x)
    >>>类型(imap(str,范围(10)))
    >>>isinstance((x代表范围(10)中的x),类型(imap(str,范围(10)))
    假的
    

    您可能会想,“当然,通过python的内省,我可以检查初始化器的参数”——您是对的!然而,即使您知道有多少参数进入初始值设定项,它们的名称是什么,您仍然无法获得任何关于您实际应该传递给它们的信息。我想你可以写一些机器学习算法,从文档串中找出答案。。。但我认为这远远超出了这个问题的范围(它假设作者表现良好,并从一开始就创建了良好的docstring)。

    您的形式主义也不适用于
    map(str,'12')

    最终,您不知道iterable类型在构造函数/初始值设定项中实际将采用什么参数,因此通常无法做到这一点。还要注意的是,
    imap
    没有提供与生成器相同的类型:

    >>> type(x for x in range(10))
    <type 'generator'>
    >>> type(imap(str,range(10)))
    <type 'itertools.imap'>
    >>> isinstance((x for x in range(10)),type(imap(str,range(10))))
    False
    
    >>类型(x代表范围(10)内的x)
    >>>类型(imap(str,范围(10)))
    >>>isinstance((x代表范围(10)中的x),类型(imap(str,范围(10)))
    假的
    
    您可能会想,“当然,通过python的内省,我可以检查初始化器的参数”——您是对的!然而,即使您知道有多少参数进入初始值设定项,它们的名称是什么,您仍然无法获得任何关于您实际应该传递给它们的信息。我想你可以写一些机器学习算法,从文档串中找出答案。。。但我认为这远远超出了这个问题的范围(它假设作者表现良好,并从一开始就创建了好的docstring)。

    首先,
    类型(seq)(f(x)代表seq中的x)
    实际上就是
    类型(seq)(imap(f,seq))
    。为什么不直接用它呢

    第二,你试图做的事情通常没有意义<代码>映射可以接受任何值,而不仅仅是一个值。基本上,区别在于序列具有
    len
    ,并且可以随机访问

    没有规则可以通过调用
    type(X)(Y_iter)
    从Y类型的值构造X类型的iterable。事实上,虽然它通常适用于序列,但很少有其他例子是正确的

    如果您想专门处理一些特殊类型,可以这样做:

    def map2(f, seq):
        it = imap(f, seq)
        if isinstance(seq, (tuple, list)):
            return type(seq)(it)
        else:
            return it
    

    或者,如果你想假设所有的序列都可以以这种方式构建(对于大多数内置序列来说是正确的,但是考虑一下,例如,代码> xLange——它不是被设计成序列,而是符合协议,当然也不能保证超出所构建的):

    您可以假设任何可以从iterable构造的iterable类型都是一个序列(如您在问题中所建议的)……但这可能会导致更多的误报,而不是好处,所以我不会这么做。同样,请记住,
    len
    是序列定义的一部分,而“可从迭代器构造”不是序列定义的一部分,并且当给定迭代器时,有一些完全合理的iterable类型可以做完全不同的事情

    无论你做什么都将是一次黑客攻击,因为你的意图就是一次黑客攻击,这与Python开发人员明确的设计愿望背道而驰。迭代器/iterable协议的全部要点是,您应该尽可能少地关心iterable的类型。这就是为什么Python3.x更进一步,用基于迭代器的函数取代了基于列表的函数,如
    map
    filter


    那么,我们如何将这些转换之一转化为装饰器呢

    首先,让我们跳过decorator位,只编写一个高阶函数,它接受一个类似于imap的函数,并返回一个应用了此转换的等价函数:

    def sequify(func):
        def wrapped(f, seq):
            it = func(f, seq)
            try:
                len(seq)
            except:
                return it
            else:
                return type(seq)(it)
        return wrapped
    
    因此:

    现在,我们如何把它变成一个装饰师?一个已经返回函数的函数是一个装饰器。您可能希望添加插件(尽管即使在非装饰器的情况下也可能需要),但这是唯一的更改。例如,我可以编写一个类似imap的生成器,或一个返回迭代器的函数,并自动转换为类似seqmap的函数:

    @sequify
    def map_and_discard_none(func, it):
        for elem in imap(func, it):
            if elem is not None:
                yield elem
    
    现在:


    当然,这只适用于具有类似于
    @sequify
    def map_and_discard_none(func, it):
        for elem in imap(func, it):
            if elem is not None:
                yield elem
    
    >>> map_and_discard_none(lambda x: x*2 if x else x, (1, 2, None))
    (2, 4)
    
    def sequify(func, type_arg=1):
        def wrapped(*args, **kwargs):
            it = func(f, seq)
            try:
                len(args[type_arg])
            except:
                return it
            else:
                return type(seq)(it)
        return wrapped
    
    def sequify(type_arg=1):
        def wrapper(func):
            def wrapped(*args, **kwargs):
                it = func(f, seq)
                try:
                    len(args[type_arg])
                except:
                    return it
                else:
                    return type(seq)(it)
            return wrapped
        return wrapper
    
    @sequify(3)
    def my_silly_function(pred, defval, extrastuff, main_iterable, other_iterable):