2012-01-17 34 views
11

Tôi đã thử thực hiện chuyển đổi như câu lệnh trong python, thay vì có nhiều câu lệnh if.Chuyển đổi bằng Python

Mã này trông như thế này:

def findStuff(cds): 
    L=[] 
    c=0 
    for i in range(0, len(cds), 3): 
     a=differencesTo(cds[i:i+3]) 
     result = { 
      a[2][0]==1: c=i+1, 
      a[2][1]==1: c=i+2, 
      a[2][2]==1: c=i+3, 
      a[1]==1: L.append((cds[i:i+3], a[0], c)) 
     } 
    return L 

Vấn đề của tôi là, điều này không hoạt động. (Làm việc với các câu lệnh if, nhưng điều này theo ý tôi sẽ đẹp hơn).

Tôi đã tìm thấy một số ví dụ về các công tắc bằng Python và chúng tuân theo cấu trúc này. Ai giúp tôi với?

+7

gì trên trái đất này là có nghĩa là để làm gì?!?! (Nó có thể thất bại vì 'list.append' trả về' None' và sửa đổi danh sách gốc tại chỗ.) – katrielalex

+7

Hãy cho tôi biết bạn đang đùa khi bạn gọi nó là "đẹp hơn" ... – NPE

+0

Mã có thể đọc được là mã khá. Đừng lo lắng về điều này, sử dụng nếu phát biểu ... –

Trả lời

18

(a) Tôi không thấy gì là sai với if ... elif ... else

(b) Tôi cho rằng trăn không có một câu lệnh switch với lý do tương tự mà Smalltalk không : nó gần như hoàn toàn dư thừa, và trong trường hợp bạn muốn bật các kiểu, bạn có thể thêm một phương thức thích hợp vào các lớp của bạn; và tương tự như vậy chuyển đổi trên các giá trị nên được phần lớn dư thừa.

Lưu ý: Tôi được thông báo rằng bất kỳ lý do nào của Guido không tạo ra chuyển đổi ngay từ đầu, PEP sẽ bị từ chối thêm trên cơ sở hỗ trợ thêm tuyên bố như vậy là vô cùng hạn chế. Xem: http://www.python.org/dev/peps/pep-3103/

(c) Nếu bạn thực sự cần chuyển đổi hành vi, hãy sử dụng thẻ bắt đầu bằng số (dict) để lưu trữ các cuộc gọi. Cấu trúc là:

switch_dict = { 
    Foo: self.doFoo, 
    Bar: self.doBar, 
    } 

func = switch_dict[switch_var] 
result = func() # or if they take args, pass args 
+0

cho (c), tôi nghĩ rằng đây là những gì algo muốn làm ... nhưng không thành công để làm điều đó. – tito

+7

Điều này. Python không có câu lệnh switch * theo thiết kế *. – Doches

+0

@Doches: Có bất kỳ nơi nào ghi lại lý do tại sao lựa chọn đó được thực hiện không? Tôi muốn được quan tâm để biết nếu nó là một cái gì đó khác hơn là đoán của tôi. – Marcin

0

Tôi không biết mà bài viết bạn đã tìm thấy để làm một cái gì đó như thế này, nhưng đây là thực sự lộn xộn: toàn bộ kết quả diction sẽ luôn được đánh giá, và thay vì làm chỉ là một phần của công việc (như một chuyển đổi/nếu làm), bạn sẽ làm toàn bộ công việc mọi lúc. (ngay cả khi bạn chỉ sử dụng một phần của kết quả).

Thực sự, một câu lệnh switch nhanh bằng Python đang sử dụng "nếu":

if case == 1: 
    pass 
elif case == 2: 
    pass 
elif case == 3: 
    pass 
else: 
    # default case 
    pass 
+1

Công tắc dict là một kỹ thuật hợp pháp, nhưng nó được sử dụng cho một thứ khác. –

1

Chuyển nhượng bằng Python là một tuyên bố, và không thể trở thành một phần của biểu thức. Ngoài ra, bằng cách sử dụng chữ theo cách này sẽ đánh giá mọi thứ cùng một lúc, điều này có lẽ không phải là điều bạn muốn. Chỉ cần sử dụng if giây, bạn sẽ không nhận được bất kỳ khả năng đọc nào bằng cách sử dụng tính năng này.

5

Không có gì sai với một dài if là:

if switch == 'case0': 
    do_case0() 
elif switch == 'case1': 
    do_case1() 
elif switch == 'case2': 
    do_case2() 
... 

Nếu đó là quá dài hơi, hoặc nếu bạn có rất nhiều trường hợp, đặt chúng trong một cuốn từ điển:

switch = {'case0': do_case0, 'case1': do_case1, 'case2': do_case2, ...} 
switch[case_variable]() 
// Alternative: 
(switch[case_variable]).__call__() 

Nếu điều kiện của bạn phức tạp hơn một chút, bạn cần suy nghĩ một chút về cấu trúc dữ liệu của mình. ví dụ:

switch = {(0,21): 'never have a pension', 
      (21,50): 'might have a pension', 
      (50,65): 'definitely have a pension', 
      (65, 200): 'already collecting pension'} 
for key, value in switch: 
    if key[0] < case_var < key[1]: 
     print(value) 
0

Với phương pháp "nhận được", bạn có thể có tác dụng tương tự như "switch..case" trong C.

Marcin dụ:

switch_dict = { 
    Foo: self.doFoo, 
    Bar: self.doBar, 
} 

func = switch_dict.get(switch_var, self.dodefault) 
result = func() # or if they take args, pass args 
0

Bạn thể làm một cái gì đó như những gì bạn muốn, nhưng bạn không nên. Điều đó nói rằng, đây là cách thực hiện; bạn có thể thấy nó không cải thiện mọi thứ như thế nào.

Vấn đề lớn nhất với cách bạn có nó là Python sẽ đánh giá các thử nghiệm và kết quả của bạn một lần, tại thời điểm bạn khai báo từ điển. Thay vào đó, những gì bạn phải làm là thực hiện tất cả các điều kiện và các hàm báo cáo kết quả; bằng cách này, đánh giá được hoãn lại cho đến khi bạn gọi cho họ. May mắn thay có một cách để làm điều này nội tuyến cho các chức năng đơn giản bằng cách sử dụng từ khóa lambda. Thứ hai, câu lệnh gán không thể được sử dụng như một giá trị trong Python, vì vậy các hàm hành động của chúng ta (được thực thi nếu hàm điều kiện tương ứng trả về một giá trị trung thực) phải trả về một giá trị sẽ được sử dụng để tăng c; họ không thể chỉ định cho số c.

Ngoài ra, các mục trong từ điển không được đặt hàng, vì vậy các bài kiểm tra của bạn sẽ không nhất thiết phải được thực hiện theo thứ tự bạn xác định, có nghĩa là bạn nên sử dụng thứ gì đó khác với từ điển giữ gìn trật tự. hoặc một danh sách. Tôi giả sử bạn chỉ muốn một trường hợp để thực thi.

Vì vậy, ở đây chúng tôi đi:

def findStuff(cds): 

    cases = [ (lambda: a[2][0] == 1, lambda: i + 1), 
       (lambda: a[2][1] == 1, lambda: i + 2), 
       (lambda: a[2][2] == 1, lambda: i + 3), 
       (lambda: a[1] == 1, lambda: L.append(cds[i:i+3], a[0], c) or 0) 
      ] 

    L=[] 
    c=0 
    for i in range(0, len(cds), 3): 
     a=differencesTo(cds[i:i+3]) 
     for condition, action in cases: 
      if condition(): 
       c += action() 
       break 
    return L 

Đây có phải là dễ đọc hơn so một chuỗi các if/elif báo cáo? Nooooooooooooo. Cụ thể, trường hợp thứ tư kém dễ hiểu hơn là vì chúng ta phải dựa vào một hàm trả về số tăng cho c để sửa đổi một biến hoàn toàn khác, và sau đó chúng ta phải tìm ra cách để trả về 0 để c sẽ không thực sự được sửa đổi. Uuuuuugly.

Đừng làm điều này. Trong thực tế, mã này có lẽ thậm chí sẽ không chạy như-là, như tôi coi nó quá xấu xí để kiểm tra.

-1

Trong khi không có gì sai với if..else, tôi thấy "chuyển đổi bằng Python" vẫn là một tuyên bố vấn đề hấp dẫn. Về điều đó, tôi nghĩ rằng tùy chọn thứ hai của Marcin (không được chấp nhận) (c) và/hoặc Snim2 có thể được viết theo một cách dễ đọc hơn.

Đối với điều này chúng ta có thể khai báo một lớp switch, và khai thác __init__() tuyên bố case chúng tôi muốn chuyển sang, trong khi __call__() giúp bàn giao một dict niêm yết (trường hợp, chức năng) cặp:

class switch(object): 
    def __init__(self, case): 
     self._case = case 

    def __call__(self, dict_): 
     try: 
      return dict_[self._case]() 
     except KeyError: 
      if 'else' in dict_: 
       return dict_['else']() 
      raise Exception('Given case wasn\'t found.') 

hoặc, tương ứng, vì một lớp học với chỉ có hai phương pháp, trong đó một là __init__(), không phải là thực sự là một lớp:

def switch(case): 
    def cases(dict_): 
     try: 
      return dict_[case]() 
     except KeyError: 
      if 'else' in dict_: 
       return dict_['else']() 
      raise Exception('Given case wasn\'t found.') 
    return cases 

(lưu ý: chọn một cái gì đó thông minh hơn Exception)

Với ví dụ

def case_a(): 
    print('hello world') 

def case_b(): 
    print('sth other than hello') 

def default(): 
    print('last resort') 

bạn có thể gọi

switch('c') ({ 
    'a': case_a, 
    'b': case_b, 
    'else': default 
}) 

đó, ví dụ đặc biệt này sẽ in

phương sách cuối cùng

Điều này không hoạt động giống như một chuyển đổi C trong đó không có break cho các trường hợp khác nhau, bởi vì mỗi trường hợp chỉ thực hiện hàm được khai báo cho trường hợp cụ thể (tức là break hoàn toàn luôn được gọi). Thứ hai, mỗi trường hợp có thể liệt kê chính xác chỉ một hàm sẽ được thực thi khi một trường hợp tìm thấy.

0

Đây là một cách khác để làm một câu lệnh switch với một hàm lambda và một từ điển

for caseVar in range(0,3): 
    answer=(lambda switch: ({ 
      0:'a', 
      1:'b', 
      2:'c', 
      }[switch]))(caseVar) 
    print("switch",answer) 
Các vấn đề liên quan