Toán tử biểu thức gán :=
được thêm vào trong Python 3.8 hỗ trợ gán bên trong biểu thức lambda. Toán tử này chỉ có thể xuất hiện trong một biểu thức dấu ngoặc đơn (...)
, dấu ngoặc [...]
hoặc dấu ngoặc nhọn {...}
vì lý do cú pháp. Ví dụ, chúng ta có thể viết như sau:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Trong Python 2, có thể thực hiện các phép gán cục bộ như một tác dụng phụ của việc hiểu danh sách.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Tuy nhiên, bạn không thể sử dụng một trong hai điều này trong ví dụ của mình vì biến của bạn flag
nằm trong phạm vi bên ngoài, không phải lambda
phạm vi của. Điều này không liên quan lambda
, đó là hành vi chung trong Python 2. Python 3 cho phép bạn giải quyết vấn đề này với nonlocal
từ khóa bên trong của def
s, nhưng nonlocal
không thể sử dụng bên tronglambda
s.
Có một cách giải quyết (xem bên dưới), nhưng trong khi chúng ta đang nói về chủ đề ...
Trong một số trường hợp, bạn có thể sử dụng điều này để thực hiện mọi thứ bên trong lambda
:
(lambda: [
['def'
for sys in [__import__('sys')]
for math in [__import__('math')]
for sub in [lambda *vals: None]
for fun in [lambda *vals: vals[-1]]
for echo in [lambda *vals: sub(
sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]
for Cylinder in [type('Cylinder', (object,), dict(
__init__ = lambda self, radius, height: sub(
setattr(self, 'radius', radius),
setattr(self, 'height', height)),
volume = property(lambda self: fun(
['def' for top_area in [math.pi * self.radius ** 2]],
self.height * top_area))))]
for main in [lambda: sub(
['loop' for factor in [1, 2, 3] if sub(
['def'
for my_radius, my_height in [[10 * factor, 20 * factor]]
for my_cylinder in [Cylinder(my_radius, my_height)]],
echo(u"A cylinder with a radius of %.1fcm and a height "
u"of %.1fcm has a volume of %.1fcm³."
% (my_radius, my_height, my_cylinder.volume)))])]],
main()])()
Một hình trụ có bán kính 10,0cm và cao 20,0cm có thể tích là 6283,2cm³.
Một hình trụ có bán kính 20,0cm và cao 40,0cm có thể tích là 50265,5cm³.
Một hình trụ có bán kính 30,0cm và cao 60,0cm có thể tích là 169646,0cm³.
Xin đừng.
... quay lại ví dụ ban đầu của bạn: mặc dù bạn không thể thực hiện các nhiệm vụ cho flag
biến trong phạm vi bên ngoài, nhưng bạn có thể sử dụng các hàm để sửa đổi giá trị đã được gán trước đó.
Ví dụ: flag
có thể là một đối tượng mà .value
chúng tôi đặt bằng cách sử dụng setattr
:
flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')]
output = filter(lambda o: [
flag.value or bool(o.name),
setattr(flag, 'value', flag.value and bool(o.name))
][0], input)
[Object(name=''), Object(name='fake_name')]
Nếu chúng ta muốn phù hợp với chủ đề trên, chúng ta có thể sử dụng cách hiểu danh sách thay vì setattr
:
[None for flag.value in [bool(o.name)]]
Nhưng thực sự, trong mã nghiêm túc, bạn nên luôn sử dụng định nghĩa hàm thông thường thay vì định nghĩa lambda
nếu bạn sắp thực hiện nhiệm vụ bên ngoài.
flag = Object(value=True)
def not_empty_except_first(o):
result = flag.value or bool(o.name)
flag.value = flag.value and bool(o.name)
return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(not_empty_except_first, input)