Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/342.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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 lambda/fn是否可以代表任意调用方生成?_Python_Lambda_Generator_Yield - Fatal编程技术网

python lambda/fn是否可以代表任意调用方生成?

python lambda/fn是否可以代表任意调用方生成?,python,lambda,generator,yield,Python,Lambda,Generator,Yield,更新:示例现在列出了所需的结果(以下黑体) 我发现自己编写了很多函数来搜索某些数据,我想让调用方在找到匹配项时指定行为:它们可能会打印出某些内容或将其添加到其中一个数据结构中,但也非常希望能够有选择地返回找到的数据以供进一步传输、存储或处理 例子 首次客户端使用: def my_visitor(x): # client visitor functions (also often use lambdas) if x > 3: yield x / 2 #>

更新:示例现在列出了所需的结果(以下黑体)

我发现自己编写了很多函数来搜索某些数据,我想让调用方在找到匹配项时指定行为:它们可能会打印出某些内容或将其添加到其中一个数据结构中,但也非常希望能够有选择地返回找到的数据以供进一步传输、存储或处理

例子 首次客户端使用:

def my_visitor(x):   # client visitor functions (also often use lambdas)
    if x > 3:
        yield x / 2   #>>> WANT TO DO SOMETHING LIKE THIS <<<#

results = find_stuff(my_visitor)   # client usage
def print_repr_visitor(x):
    print repr(x)

find_stuff(print_repr_visitor)     # alternative usage
应打印1 2 3 4 5 6(单独的行),但不产生任何结果

但是,
yield
并没有在“results”中创建生成器(至少在我一直坚持使用的python 2.6.6中)


我试过的 我一直在整理这个,经常是这样

def find_stuff(visitor):
    for x in (1, 2, 3, 4, 5):
        val = visitor(x)
        if val is not None:
             yield val
…或者有时,当访问者参数列表输入太多次会让人感到痛苦时

def find_stuff(visitor):
    for x in (1, 2, 3, 4, 5):
        val = visitor(x)
        if val == 'yield':
            yield x
        elif val is not None:
             yield val
议题/问题 这些“解决方案”不仅笨拙——需要“查找”例程的显式内置支持——它们从访问者可以返回给顶级调用者的结果集中删除了哨兵值

在简洁、直观、灵活、优雅等方面是否有更好的选择


谢谢

在Python 3中,可以使用
yield from
从子生成器中生成项:

def find_stuff(visitor):
    for x in (1, 2, 3, 4, 5):
        yield from visitor(x)
sentinel = object()

def my_scalar_visitor(x):
    if x > 3: 
        return x / 2
    else:
        return sentinel

def find_stuff_scalar(scalar_visitor):
    search_list=(1,2,3,4,5,6)
    return (x for x in (scalar_visitor(y) for y in search_list) if x != sentinel)

list(find_stuff_scalar(my_scalar_visitor))
[0x2, 0x2, 0x3]
在Python 2中,必须循环子生成器。这需要更多的代码,不能处理一些边缘情况,但通常已经足够好了:

def find_stuff(visitor):
    for x in (1, 2, 3, 4, 5):
        for item in visitor(x):
            yield item

边缘情况是尝试
发送
值或
向子生成器抛出
异常。如果您没有使用协同程序功能,您可能不需要担心它们。

如果理解正确,可能您需要这样的功能:

def find_stuff(visitor):
    for x in [1, 2, 3, 4, 5]:
        match, val = visitor(x)
        if match:
            yield val

def my_visitor(x):
    if x > 4:
        return True, x/2
    else:
        return False, None
def my_visitor2(x):
    if x > 3:
        yield x / 2
    elif x > 1:
        yield x
        yield x*2
        yield x-3

In [83]: list(find_stuff(my_visitor2))
[0x2, 0x4, -0x1, 0x3, 0x6, 0x0, 0x2, 0x2, 0x3]
也就是说,让访问者返回两件事:要生成的值(如果有)和指示是否生成该值的布尔值。这样就可以产生任何价值


您问题的标题似乎暗示您希望
my_visitor
以某种方式决定
find_stuff
是否会在每次迭代中产生一个值,但您实际上并没有在问题中描述这一点。无论如何,这是不可能的。生成器可以调用另一个函数来决定要生成什么,但被调用的函数无法神奇地使其调用者生成或不生成;这个决定必须在调用者内部做出(
find_stuff


但从你的问题来看,我不明白为什么这是个问题。你说你提出的解决方案“笨拙——需要“查找”例程的显式内置支持”,但我看不出这有多笨拙。它只是一个API
find_stuff
显然必须有“内置支持”来完成它应该做的事情,而且访问者必须知道返回什么来与呼叫方进行通信。您不能期望能够编写一个
my_visitor
函数,该函数可以与任何人可能想到的任何查找例程一起工作;整个系统必须定义一个API,描述如何编写
find\u stuff
可以使用的访问者。所以,你只需要拿出一个API,访问者必须遵循。我上面的示例是一个简单的API,但很难从您的问题中看出您在寻找什么。

我通过一些调查,在python 2.6中找到了解决方案。这有点奇怪,但它确实起作用了

from itertools import chain

def my_visitor(x):
    if x > 3:
        yield x / 2

def find_stuff(visitor):
    search_list = (1,2,3,4,5,6)
    return (x for x in chain.from_iterable(visitor(x) for x in search_list))

find_stuff(my_visitor)
<generator object <genexpr> at 0x0000000047825558>

list(find_stuff(my_visitor))
[0x2, 0x2, 0x3]
让每次访问都不返回任何值、单个值或一组值,它们都会进入结果

不过,您也可以将其调整为标量值。最好的方法是使用嵌套生成器:

def find_stuff(visitor):
    for x in (1, 2, 3, 4, 5):
        yield from visitor(x)
sentinel = object()

def my_scalar_visitor(x):
    if x > 3: 
        return x / 2
    else:
        return sentinel

def find_stuff_scalar(scalar_visitor):
    search_list=(1,2,3,4,5,6)
    return (x for x in (scalar_visitor(y) for y in search_list) if x != sentinel)

list(find_stuff_scalar(my_scalar_visitor))
[0x2, 0x2, 0x3]
解决了问题给出的问题,但在我看来,generator-in-a-generator方法在这种特定情况下过于复杂,限制了客户端使用代码的选项

您需要遍历一些结构,应用一些函数,并产生结果。您的代码允许这样做,但是您将Python已经拥有的两个优秀的独立支持(遍历和映射)合并在一起,没有额外的好处

您的遍历函数可以简单地遍历:

def traverse_stuff():
    for x in (1, 2, 3, 4, 5, 6):
        yield x
当我们想要消费时,您或您的客户可以使用列表理解,组合词,如
map
filter
,或者对于
循环使用简单的

[x / 2 for x in traverse_stuff() if x > 3]

map(lambda x: x / 2, filter(lambda x: x > 3, traverse_stuff())

for value in traverse_stuff():
    print(value)

以这种方式拆分代码使其更具可组合性(您的客户端不限于访问者模式/生成器),对于其他Python开发人员更直观,对于只需要使用部分结构的情况,性能更高(例如,当您只需要从树中查找n个节点时,当您只想查找结构中满足条件的第一个值时,&c)。

我不太明白您的要求。您能举一个示例说明如何使用该函数吗你想要的结果是什么?我想我不明白为什么你不总是在你的
find\u stuff
函数中产生
visitor(x)
的结果。你可以使用
object()
创建一个唯一的哨兵值,如果这是问题的话。生成器函数返回的生成器对象不是
None
,因此,我不确定如果val不是None
,那么
有什么意义。是的,更多的信息会很有帮助……考虑到您的限制,我看不到任何方法可以绕过您发布的内容。我阅读这篇文章是想了解的ate在generator/iterable上运行,其中一些调用更改状态但不返回值,其他调用返回值,有时这是查找元素,有时是后处理数据?似乎任何更优雅的解决方案都将是非常特定于域的……简化的一种方法是,如果
my_visitor
想要返回查找值(即
if val=='yield'
术语),而不是返回哨兵,它应该只返回
x
@BrenBarn:我添加了一个示例/结果