2015-06-22 18 views
8

Làm thế nào để bạn có một câu lệnh nhiều dòng trong một danh sách hiểu hoặc eval?Đọc hiểu danh sách Python 2 và eval

Tôi đã cố gắng để biến mã này:

def f(x, y, b=''): 
    for i in x: 
     if i in y: 
      y.remove(i) 
      i *= 2 
     b += i 
    return b 

Into một hàm lambda như vậy:

j=lambda x,y:''.join(eval('y.remove(i);i*2')if i in y else i for i in x) 

Trong cả hai x là một chuỗi như 'onomatopoeia'y là một danh sách như ['o','a','o'] .

Nhưng vì lý do nào đó, nó trả về lỗi cú pháp. Bất cứ ai có thể giải thích điều này?

+0

giá trị của 'x' và' y' là gì? –

+0

Tôi tin rằng lambdas được cố tình giới hạn ở một dòng để cải thiện khả năng đọc và rõ ràng. Bạn có thể thử chuyển đổi hàm đó thành lambda, nhưng đó là một chút phản kháng. – J0HN

+0

'eval' yêu cầu một biểu thức, trong khi' y.remove (i); i * 2' là một câu lệnh. 'eval ('1; 1')' cũng tạo ra 'SyntaxError'. – nymk

Trả lời

3

Trước tiên, bạn có lẽ không nên viết lại điều này bằng lambda vì các tác dụng phụ trong vòng lặp. Nếu bạn thực sự muốn anyway, không sử dụng một eval.

tôi muốn đề nghị:

j = lambda x, y: ''.join((y.remove(i) or 2 * i) if i in y else i for i in x) 

Vì kết quả của remove là None đối số thứ hai để or sẽ kết quả. Điều này tránh được eval. Nhưng nó vẫn còn tồi tệ hơn sau đó cho một vòng lặp.


Như đã nêu trong ý kiến ​​về câu hỏi ban đầu, 2 * y.pop(y.index(i)) là dễ đọc hơn so với or xây dựng. Bạn sẽ lặp lại hai lần trên y, nhưng hiệu suất dường như không phải là vấn đề.

2

Tôi sẽ rất thích chức năng của bạn nhưng điều này sẽ làm những gì bạn muốn.

from itertools import chain 
j = lambda x, y: ''.join(filter(None,chain.from_iterable((i * 2,y.remove(i)) if i in y else i for i in x))) 

print(j("'onomatopoeia'",['o','a','o'])) 
'oonoomaatopoeia' 
+1

Tại sao không đơn giản là' '' .join (2 * y.pop (y.index (i)) nếu i trong y i khác cho i trong x) '? – l4mpi

+0

@ l4mpi, vì tôi đang sử dụng mã riêng của OP, việc lập chỉ mục cũng có chi phí nên không thực sự tốt hơn là chỉ lọc. Tôi sẽ không sử dụng phương pháp tiếp cận nếu nó đã được lên đến tôi –

+0

Tôi đồng ý rằng không thực sự là con đường để đi, nhưng biến thể 'pop' là cách dễ đọc hơn IMO. Tôi nghi ngờ rằng tốc độ là một vấn đề, và nếu nó là sau đó loại bỏ các cuộc gọi 'remove' hoàn toàn có lẽ sẽ là hành động tốt nhất (ví dụ như sử dụng một' Counter' và giảm số lượng chữ). – l4mpi

0

Nếu bạn muốn viết biểu thức chức năng tốt (sử dụng lambda s, map, reduce, filter và vv), bạn nên tránh tác dụng phụ.

Tôi rất muốn mã của bạn như một hàm thay vì một lambda có các tác dụng phụ.

Đây là một thực hiện sideeffect miễn phí trong biểu một lambda:

>>> from functools import reduce 
>>> (lambda x, y: reduce(lambda a, b: \ 
...  (a[0]+2*b, a[1][:a[1].index(b)]+a[1][a[1].index(b)+1:]) if b in a[1] \ 
...  else (a[0]+b, a[1]), x, ('',y))[0])('onomatopoeia', ['o','a','o']) 
'oonoomaatopoeia' 

Tôi sợ nó không ngắn cũng không đẹp cũng không dễ hiểu * như người ta sẽ muốn nó được cho một lambda. :/ (hy vọng ai đó có thể đề xuất cải tiến)

Chỉ cần một ví dụ phản biện để ngăn cản việc sử dụng lambda trong ngữ cảnh này.

IMHO vấn đề lớn nhất với lambdas trong python là không có cú pháp where như trong tiêu chuẩn ML để xác định bí danh biến trong cùng một biểu thức. Vì vậy, mọi thứ trở nên xấu xí khá nhanh chóng cho bất kỳ điều gì không tầm thường.


Nếu bạn muốn hiểu ý nghĩa của nó, ý tưởng là sử dụng giảm để chạy một automata, kết quả (ở mỗi bước) là "trạng thái" của tính toán.

"trạng thái" ban đầu là ('', ['o','a','o']) và chức năng giảm sẽ thực hiện thay thế nếu cần, bắt đầu từ 'onomatopoeia'.

Đây là sự tiến hóa của "nhà nước":

('',  ['o','a','o']) 'o' 
('oo',  ['a','o']) 'n' 
('oon',  ['a','o']) 'o' 
('oonoo',  ['a']) 'm' 
('oonoom',  ['a']) 'a' 
('oonoomaa',  []) 't' 
('oonoomaat',  []) 'o' 
('oonoomaato',  []) 'p' 
('oonoomaatop',  []) 'o' 
('oonoomaatopo', []) 'e' 
('oonoomaatopoe', []) 'i' 
('oonoomaatopoei', []) 'a' 
('oonoomaatopoeia', []) 

và chúng tôi chỉ mất yếu tố đầu tiên của nhà nước cuối cùng.

Các vấn đề liên quan