为什么不分配在Python的`lambda`表达式允许吗?

问题描述 投票:13回答:7

这不是Assignment inside lambda expression in Python的副本,即,我不问如何欺骗的Python到一个lambda表达分配。

我有一些λ演算背景。考虑下面的代码,它看起来像Python是很愿意在lambda表达式执行的副作用:

#!/usr/bin/python

def applyTo42(f):
    return f(42)

def double(x):
    return x * 2

class ContainsVal:
    def __init__(self, v):
        self.v = v

    def store(self, v):
        self.v = v

def main():

    print('== functional, no side effects')

    print('-- print the double of 42')
    print(applyTo42(double))

    print('-- print 1000 more than 42')
    print(applyTo42(lambda x: x + 1000))

    print('-- print c\'s value instead of 42')
    c = ContainsVal(23)
    print(applyTo42(lambda x: c.v))


    print('== not functional, side effects')

    print('-- perform IO on 42')
    applyTo42(lambda x: print(x))

    print('-- set c\'s value to 42')
    print(c.v)
    applyTo42(lambda x: c.store(x))
    print(c.v)

    #print('== illegal, but why?')
    #print(applyTo42(lambda x: c.v = 99))

if __name__ == '__main__':
    main()

但是,如果我取消注释行

    print('== illegal, but why?')
    print(applyTo42(lambda x: c.v = 99))

我去拿

SyntaxError: lambda cannot contain assignment

为什么不?这背后有什么深层次的原因?

  • 作为代码演示了,它不能是对在功能意义上的“纯度”。
  • 我可以想像,唯一的解释就是assignemts不返回任何东西,甚至不None。但是,这听起来瘸子,会很容易修复(单程使lambda表达式返回None如果身体是一个语句)。

不是一个答案:

  • 因为它的定义方式(我想知道为什么它的定义方式)。
  • 因为它在语法(见上文)。
  • 如果你需要语句(我没有问如何让语句进入一个函数)使用def

“这将改变语法/语言/语义”将确定作为回答,如果你能想出这种变化的一个例子,为什么它会是坏的。

python lambda python-internals side-effects
7个回答
15
投票

lambda存在的整个原因是,如果你想要的东西,就像lambda但声明这是一个expression.1,这只是def

Python表达式不能包含语句。这是,实际上,在语言基础和Python得到了很多的里程了这一决定的。这是缩进流量控制原因,作品而不是笨重的其他许多尝试(如CoffeeScript的)。这是你可以通过在每一行飞掠的第一个对象读出的状态发生变化的原因。它的语言很容易解析的原因,甚至部分,既为编译器和人类readers.2

更改Python中有一些方法来“逃避”的语句表达鸿沟,除了可能在一个非常谨慎和有限的方式,将它变成一个完全不同的语言,一个不再有很多的,导致人们选择的好处蟒蛇摆在首位。

更改Python来使大多数语句表达(如,说,红宝石)将再次把它变成无Python的当前利益完全不同的语言。

如果Python的的确让无论这些变化,那么就会不再是摆在首位lambda一个原因; 2,3-你可以只使用def语句表达中。


怎么样改变Python来代替进行分配表情?那么,它应该是会打破“您可以通过撇在每一行的第一个对象读出状态的变化”明显。虽然圭多通常集中于一个事实,即if spam=eggs是一个错误往往比一个有用的东西。

是Python不给你方法来解决在需要的时候,像setattr甚至显式调用__setitem__globals(),并不意味着它的事实的东西,应该有直接的语法支持。这是非常罕见需要不值得语法糖,更是这样的东西,这就够了不寻常的,它应该提高眉毛和/或红旗时,它实际上是做了什么。


1.我不知道这是否是圭多的理解时,他最初加入lambda回用Python 1.0。但它绝对lambda没有在Python 3.0移除的原因。

2.事实上,圭多了,多次建议,允许LL(1),人类可以在他们的头脑运行解析器充分理由的语言是基于语句的,到如此地步,其他福利甚至都不需要进行讨论。如果任何人的I wrote about this a few years ago感兴趣。

3.如果你想知道为什么这么多的语言确实有,尽管已经有lambda一个def表达:在许多语言中,从C ++到Ruby,功能都不是可以传递的第一类对象,所以他们不得不发明这是一流的,但就像一个功能的第二件事。在其他情况下,从Smalltalk中去渣,功能甚至不存在的,只有方法,如此反复,他们不得不发明,这不是一个方法,但就像一个第二件事。 Python有没有这些问题。

4.几种语言,如C#和JavaScript,实际上有很好的工作内联函数定义,倒是某种lambda语法纯语法糖,使其更加简洁,少boilerplatey。这实际上可能是值得在Python中(虽然在一个良好的语法千方百计至今已经下降持平),但它不会是当前lambda语法,这几乎是一样def为详细。


6
投票

有语法问题:赋值是一个语句,一个lambda的身体只能有表情。 Python的语法设计这个WAY1。瞧瞧吧https://docs.python.org/3/reference/grammar.html

还有一个语义的问题:是什么每个语句返回?

我不认为这是在改变这种兴趣,lambda表达式都是为了很简单,短码。此外,声明将允许语句序列以及,这是不可取的lambda表达式。

它可以被固定也通过选择性地允许在lambda身体某些陈述,并指定语义(例如分配返回None,或返回所分配的值;后者更有意义我)。但是,什么是好处?

lambda表达式和功能是可以互换的。如果你真的有一个用例在拉姆达的身体特定的语句,可以定义执行它,您的具体问题解决的功能。


也许你可以创建一个语法宏允许与MacroPy3(我只是猜测,因为我是这个项目的粉丝,但我仍然还没有在它潜水的时间)。

例如MacroPy将允许您定义转换成f[_ * _]一个lambda a, b: a * b宏,所以它不应该是无法界定的语法调用你定义的函数的λ。


1一个很好的理由不改变它,它会削弱语法,因为lambda可以在地方表达式即可。和语句不应该。但是,这是我自己的一个很主观的评论。


2
投票

我的答案是基于上述chepner's comment并没有从任何其他可信的或官方源画画,但我认为,这将是有益的。

如果分配在lambda表达式允许,那么混乱==(平等的测试)与=(分配)的误差将有逃逸到野外的更多的机会。

例:

>>> # Correct use of equality test
... list(filter(lambda x: x==1, [0, 1, 0.0, 1.0, 0+0j, 1+0j]))
[1, 1.0, (1+0j)]

>>> # Suppose that assignment is used by mistake instead of equality testing
... # and the return value of an assignment expression is always None
... list(filter(lambda x: None, [0, 1, 0.0, 1.0, 0+0j, 1+0j]))
[]

>>> # Suppose that assignment is used by mistake instead of equality testing
... # and the return value of an assignment expression is the assigned value
... list(filter(lambda x: 1, [0, 1, 0.0, 1.0, 0+0j, 1+0j]))
[0, 1, 0.0, 1.0, 0j, (1+0j)]

2
投票

只要exec()(和eval())允许内部lambda,你可以做内部lambda分配:

q = 3

def assign(var_str, val_str):
    exec("global " + var_str + "; " + 
    var_str + " = " + val_str)

lambda_assign = lambda var_str, val_str: assign(var_str, val_str)

q ## gives: 3

lambda_assign("q", "100")

q ## gives: 100

## what would such expression be a win over the direct:

q = 100

## ? `lambda_assign("q", "100")` will be for sure slower than
##   `q = 100` isn't it?

q_assign = lambda v: assign("q", v)

q_assign("33")

q ## 33

## but do I need lambda for q_assign?

def q_assign(v): assign("q", v) 

## would do it, too, isn't it?

但由于lambda表达式让自己的身体(至少在Python ...)中进行定义只有1的表达,这将是该点的允许拉姆达内部的分配?其净效应将直接分配(不使用任何拉姆达)q = 100,不是吗?

它甚至会快于做在一个确定的拉姆达,因为至少有一个功能查找和执行较少的执行...


1
投票

有没有真正的任何更深层次的原因,它没有任何关系的λ或功能性语言的设计,它只是避免混合编程=和==操作符,这是在其他语言中非常常见的错误

如果有更多的这个故事,我想喜欢,也许是因为蟒蛇BDFL GVR表示,他没有爱心双方Lambda和其他功能特征,并试图(和承认),他们从蟒蛇3完全https://www.artima.com/weblogs/viewpost.jsp?thread=98196删除

在写本文的核心开发者的时候,看到有最近关于是否包括在有限的名字绑定表达式分配的热烈讨论,辩论仍在继续这样也许有一天,我们可以看到它在拉姆达(不太可能)

正如你自己说过它绝对不是副作用或纯度,他们只是不想拉姆达比单一的表达更... ... ...

随着中说,这里的东西有关在lambda表达式的多任务,阅读如果你有兴趣

这不是在蟒蛇在所有不可能的,事实上,它有时需要使用kwargs(关键字参数)来捕获变量和回避由(AB)后期绑定

编辑:

code example

f = lambda x,a=1: (lambda c = a+2, b = a+1: (lambda e = x,d = c+1: print(a,b,c,d,e))())()

f("w")

# output 1 2 3 4 w

# expression assignment through an object's method call

if let(a=1) .a > 0 and let(b=let.a+1) .b != 1 and let(c=let.b+let.a) .c:
    print(let.a, let.b, let.c)

# output 1 2 3

0
投票

因为它的立场,巨蟒被设计成一个基于语句的语言。因此,分配等名称绑定语句,也没有任何结果。

Python的核心开发人员目前正在讨论PEP 572,这将引入name-binding expression


0
投票

我认为所有的研究员已经回答了这个。我们大多使用lambda表达式功能时,我们只是想:

-create一些简单函数做的工作完全在一个特定的地方(大部分隐藏在其他一些大功能-The lambda函数没有名字的时候 - 能与其他一些内置插件功能,如地图中使用,列表等等...

>>> Celsius = [39.2, 36.5, 37.3, 37.8] 
>>> Fahrenheit = map(lambda x: (float(9)/5)*x + 32, Celsius) # mapping the list here  
>>> print Fahrenheit
[102.56, 97.700000000000003, 99.140000000000001, 100.03999999999999]

请访问此网页,这可能是useful.Keep起来! https://www.python-course.eu/lambda.php

© www.soinside.com 2019 - 2024. All rights reserved.