Thay thế cho câu lệnh switch trong Python?


1718

Tôi muốn viết một hàm trong Python trả về các giá trị cố định khác nhau dựa trên giá trị của một chỉ mục đầu vào.

Trong các ngôn ngữ khác tôi sẽ sử dụng một câu lệnh switchhoặc case, nhưng Python dường như không có switchcâu lệnh nào. Các giải pháp Python được đề xuất trong kịch bản này là gì?


77
PEP liên quan, được viết bởi chính Guido: PEP 3103
chb

28
@chb Trong PEP đó, Guido không đề cập rằng chuỗi if / elif cũng là một nguồn lỗi cổ điển. Đó là một công trình rất mong manh.
itbruce

15
Thiếu từ tất cả các giải pháp ở đây là phát hiện các giá trị trường hợp trùng lặp . Theo nguyên tắc thất bại nhanh, đây có thể là một mất mát quan trọng hơn hiệu suất hoặc tính năng giảm.
Bob Stein

6
switchthực sự "linh hoạt" hơn một cái gì đó trả về các giá trị cố định khác nhau dựa trên giá trị của một chỉ mục đầu vào. Nó cho phép các đoạn mã khác nhau được thực thi. Nó thực sự thậm chí không cần trả về một giá trị. Tôi tự hỏi nếu một số câu trả lời ở đây là sự thay thế tốt cho một switchtuyên bố chung , hoặc chỉ cho trường hợp trả về các giá trị mà không có khả năng thực thi các đoạn mã chung.
sancho.s RebstateMonicaCellio

3
@ MalikA.Rumi Cấu trúc mong manh, giống như một vòng lặp while là một cấu trúc dễ vỡ nếu bạn cố gắng sử dụng nó để làm những gì cho ... trong .... Bạn sẽ gọi các lập trình viên yếu để sử dụng cho các vòng lặp? Trong khi các vòng lặp là tất cả những gì họ thực sự cần. Nhưng đối với các vòng lặp cho thấy mục đích rõ ràng, hãy tiết kiệm nồi hơi vô nghĩa và tạo cơ hội để tạo ra sự trừu tượng mạnh mẽ.
itbruce

Câu trả lời:


1486

Bạn có thể sử dụng một từ điển:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

100
Điều gì xảy ra nếu x không được tìm thấy?
Nick

46
@nick: bạn có thể sử dụng defaultdict
Eli Bendersky

385
Tôi khuyên bạn nên đặt dict bên ngoài chức năng nếu hiệu suất là một vấn đề, vì vậy nó không xây dựng lại dict trên mỗi lệnh gọi chức năng
Claudiu

56
@EliBendersky, Sử dụng getphương pháp có thể sẽ bình thường hơn so với sử dụng a collections.defaultdicttrong trường hợp này.
Mike Graham

27
@Nick, Một ngoại lệ được ném ra do }.get(x, default)Thay vào đó nếu có mặc định. (Lưu ý: điều này đẹp hơn rất nhiều so với những gì xảy ra nếu bạn để mặc định tắt một câu lệnh chuyển đổi!)
Mike Graham

1375

Nếu bạn muốn mặc định, bạn có thể sử dụng get(key[, default])phương pháp từ điển :

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

11
Điều gì xảy ra nếu 'a' và 'b' khớp 1 và 'c' và 'd' khớp 2?
John Mee

13
@JM: Chà, rõ ràng là tra cứu từ điển không hỗ trợ thông qua. Bạn có thể làm một tra cứu từ điển đôi. Tức là 'a' & 'b' trỏ tới answer1 và 'c' và 'd' trỏ tới answer2, được chứa trong một từ điển thứ hai.
Nick

3
điều này tốt hơn để vượt qua một giá trị mặc định
HaTiMSuM

Có một vấn đề với cách tiếp cận này, lần đầu tiên mỗi lần bạn gọi f bạn sẽ tạo lại dict lần thứ hai nếu bạn có giá trị phức tạp hơn, bạn có thể nhận được một ngoại lệ. if x là một tuple và chúng tôi muốn làm một cái gì đó như thế này x = ('a') def f (x): return {'a': x [0], 'b': x [1]} .get ( x [0], 9) Điều này sẽ nâng IndexError
Idan Haim Shalom

2
@Idan: Câu hỏi là sao chép chuyển đổi. Tôi chắc chắn tôi cũng có thể phá vỡ mã này nếu tôi cố gắng đưa vào các giá trị lẻ. Vâng, nó sẽ tạo lại, nhưng nó rất đơn giản để sửa chữa.
Nick

394

Tôi luôn thích làm theo cách này

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

Từ đây


16
phương pháp tuyệt vời, kết hợp với get () để xử lý mặc định cũng là lựa chọn tốt nhất của tôi
drAlberT

27
Có lẽ không nên sử dụng lambda trong trường hợp này vì lambda thực sự được gọi mỗi khi từ điển được xây dựng.
Asher

13
Đáng buồn thay, đây là người gần nhất sẽ nhận được. Các phương pháp sử dụng .get()(như câu trả lời cao nhất hiện tại) sẽ cần đánh giá một cách háo hức tất cả các khả năng trước khi gửi đi, và do đó, không chỉ (không chỉ rất mà) cực kỳ kém hiệu quả và cũng không thể có tác dụng phụ; câu trả lời này xoay quanh vấn đề đó, nhưng dài dòng hơn. Tôi sẽ chỉ sử dụng if / elif / other, và thậm chí những người đó chỉ mất nhiều thời gian để viết như 'trường hợp'.
ninjagecko 17/03/2016

13
Điều này sẽ không đánh giá tất cả các chức năng / lambdas mọi lúc trong mọi trường hợp, ngay cả khi nó chỉ trả về một trong các kết quả?
slf

23
@slf Không, khi luồng điều khiển đạt đến đoạn mã đó, nó sẽ xây dựng 3 hàm (thông qua việc sử dụng 3 lambdas) và sau đó xây dựng một từ điển với 3 hàm đó làm giá trị, nhưng chúng vẫn chưa được xử lý ( đánh giá hơi mơ hồ bối cảnh đó) lúc đầu. Sau đó, từ điển được lập chỉ mục thông qua [value], sẽ chỉ trả về một trong 3 chức năng (giả sử valuelà một trong 3 khóa). Hàm chưa được gọi vào thời điểm đó. Sau đó (x)gọi hàm vừa trả về với xlàm đối số (và kết quả sẽ chuyển sang result). Hai chức năng khác sẽ không được gọi.
blubberdiblub

354

Ngoài các phương thức từ điển (mà tôi thực sự thích, BTW), bạn cũng có thể sử dụng if- elif- elseđể có được switch/ case/ defaultchức năng:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

Điều này tất nhiên không giống với chuyển đổi / trường hợp - bạn không thể dễ dàng bỏ qua breakcâu lệnh, nhưng bạn có thể có một bài kiểm tra phức tạp hơn. Định dạng của nó đẹp hơn một loạt các ifs lồng nhau , mặc dù về mặt chức năng đó là những gì nó gần hơn.


51
Tôi thực sự thích điều này, nó sử dụng cấu trúc ngôn ngữ độc lập và không ném KeyError nếu không tìm thấy trường hợp phù hợp nào
martyglaubitz

7
Tôi đã nghĩ về từ điển / getcách, nhưng cách tiêu chuẩn đơn giản là dễ đọc hơn.
Martin Thoma

2
@someuser nhưng thực tế họ có thể "chồng chéo" là một tính năng. Bạn chỉ cần đảm bảo thứ tự là ưu tiên trong đó các trận đấu sẽ xảy ra. Đối với lặp lại x: chỉ cần làm một x = the.other.thingtrước. Thông thường, bạn sẽ có một if, nhiều elif và một cái khác, vì điều đó dễ hiểu hơn.
Matthew Schinckel

7
Thật tuyệt, "Mặc dù không sử dụng elif", tuy nhiên hơi khó hiểu. Điều gì về điều này: quên đi "rơi qua" và chỉ chấp nhận nó là hai if/elif/else?
Alois Mahdal

7
Cũng đáng đề cập, khi sử dụng những thứ như x in 'bc', hãy nhớ rằng đó "" in "bc"True.
Lohmar ASHAR

185

Công thức Python yêu thích của tôi cho switch / case là:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

Ngắn gọn và đơn giản cho các kịch bản đơn giản.

So sánh với hơn 11 dòng mã C:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

Bạn thậm chí có thể gán nhiều biến bằng cách sử dụng bộ dữ liệu:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))

16
Tôi thấy đây là một câu trả lời mạnh mẽ hơn được chấp nhận.
ngũ cốc

3
@some user: C yêu cầu giá trị trả về phải cùng loại cho tất cả các trường hợp. Python thì không. Tôi muốn làm nổi bật tính linh hoạt này của Python chỉ trong trường hợp ai đó có tình huống bảo đảm việc sử dụng như vậy.
ChaimG

3
@some user: Cá nhân tôi thấy {} .get (,) có thể đọc được. Để dễ đọc hơn cho người mới bắt đầu Python, bạn có thể muốn sử dụng default = -1; result = choices.get(key, default).
ChaimG

4
so sánh với 1 dòng của c ++result=key=='a'?1:key==b?2:-1
Jasen

4
@Jasen người ta có thể lập luận rằng bạn cũng có thể làm điều đó trong một dòng Python : result = 1 if key == 'a' else (2 if key == 'b' else 'default'). Nhưng là một lót có thể đọc được?
ChaimG

101
class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

Sử dụng:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

Các xét nghiệm:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

64
Đây không phải là mối đe dọa an toàn. Nếu một vài công tắc được nhấn cùng lúc, tất cả các công tắc sẽ lấy giá trị của công tắc cuối cùng.
francescortiz

48
Mặc dù @francescortiz có nghĩa là an toàn cho luồng, nhưng nó cũng không đe dọa đến an toàn. Nó đe dọa các giá trị của các biến!
Zizouz212

7
Vấn đề an toàn luồng có thể có thể được giải quyết bằng cách sử dụng lưu trữ luồng cục bộ . Hoặc có thể tránh hoàn toàn bằng cách trả về một thể hiện và sử dụng thể hiện đó để so sánh trường hợp.
blubberdiblub

6
@blubberdiblub Nhưng sau đó, nó không hiệu quả hơn khi sử dụng một iftuyên bố tiêu chuẩn ?
wizzwizz4

9
Điều này cũng không an toàn nếu được sử dụng trong nhiều chức năng. Trong ví dụ đã cho, nếu case(2)khối gọi hàm khác sử dụng switch (), thì khi thực hiện case(2, 3, 5, 7)vv để tìm trường hợp tiếp theo thực thi, nó sẽ sử dụng giá trị chuyển đổi được đặt bởi hàm khác chứ không phải do lệnh được đặt bởi câu lệnh chuyển đổi hiện tại .
dùng9876

52

Yêu thích của tôi là một công thức thực sự tốt đẹp . Bạn sẽ thực sự thích nó. Đây là cái gần nhất tôi từng thấy với các báo cáo trường hợp chuyển đổi thực tế, đặc biệt là trong các tính năng.

class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

Đây là một ví dụ:

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"

3
Tôi sẽ thay thế for case in switch()bằng with switch() as case, có ý nghĩa hơn, vì nó chỉ cần chạy một lần.
Trượt tuyết

4
@Skirmantas: Lưu ý rằng withkhông cho phép breakmặc dù vậy, vì vậy tùy chọn dự phòng được lấy đi.
Jonas Schäfer

5
Xin lỗi vì đã không nỗ lực nhiều hơn để tự xác định điều này: một câu trả lời tương tự ở trên không phải là chủ đề an toàn. Có phải đây là?
David Winiecki

1
@DavidWiniecki Các thành phần mã bị thiếu ở trên (và có thể là bản quyền của activestate) dường như là luồng an toàn.
Jasen

phiên bản khác của cái này sẽ như thế if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"nào?
mpag

51
class Switch:
    def __init__(self, value):
        self.value = value

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        return False # Allows a traceback to occur

    def __call__(self, *values):
        return self.value in values


from datetime import datetime

with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4):
        print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes

9
Sử dụng các trình quản lý bối cảnh là một giải pháp sáng tạo tốt. Tôi khuyên bạn nên thêm một chút giải thích và có thể liên kết đến một số thông tin về Trình quản lý bối cảnh để cung cấp cho bài đăng này một số, tốt, bối cảnh;)
Will

2
Tôi không thích if / elif chuỗi nhiều nhưng đây là cả hai giải pháp sáng tạo nhất và thiết thực nhất trong tất cả các giải pháp tôi đã thấy bằng cú pháp hiện có của Python.
itbruce

2
Điều này thực sự tốt đẹp. Một cải tiến được đề xuất là thêm thuộc tính (công khai) valuevào lớp Switch để bạn có thể tham chiếu case.valuetrong câu lệnh.
Peter

48

Có một mô hình mà tôi đã học được từ mã Twisted Python.

class SMTP:
    def lookupMethod(self, command):
        return getattr(self, 'do_' + command.upper(), None)
    def do_HELO(self, rest):
        return 'Howdy ' + rest
    def do_QUIT(self, rest):
        return 'Bye'

SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'

Bạn có thể sử dụng nó bất cứ lúc nào bạn cần gửi mã thông báo và thực thi đoạn mã mở rộng. Trong một máy trạng thái, bạn sẽ có state_các phương thức và gửi đi self.state. Công tắc này có thể được mở rộng một cách sạch sẽ bằng cách kế thừa từ lớp cơ sở và xác định các do_phương thức của riêng bạn . Thường thì bạn sẽ không códo_ các phương thức trong lớp cơ sở.

Chỉnh sửa: chính xác là nó được sử dụng như thế nào

Trong trường hợp của SMTP, bạn sẽ nhận được HELOtừ dây. Mã liên quan (từ twisted/mail/smtp.py, được sửa đổi cho trường hợp của chúng tôi) trông như thế này

class SMTP:
    # ...

    def do_UNKNOWN(self, rest):
        raise NotImplementedError, 'received unknown command'

    def state_COMMAND(self, line):
        line = line.strip()
        parts = line.split(None, 1)
        if parts:
            method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
            if len(parts) == 2:
                return method(parts[1])
            else:
                return method('')
        else:
            raise SyntaxError, 'bad syntax'

SMTP().state_COMMAND('   HELO   foo.bar.com  ') # => Howdy foo.bar.com

Bạn sẽ nhận được ' HELO foo.bar.com '(hoặc bạn có thể nhận được 'QUIT'hoặc 'RCPT TO: foo'). Đây là tokenized vào partsnhư ['HELO', 'foo.bar.com']. Tên tra cứu phương thức thực tế được lấy từparts[0] .

(Phương thức ban đầu cũng được gọi state_COMMAND, bởi vì nó sử dụng cùng một mẫu để triển khai một máy trạng thái, nghĩa là getattr(self, 'state_' + self.mode))


4
Tôi không thấy lợi ích từ mẫu này khi chỉ gọi các phương thức trực tiếp: SMTP (). Do_HELO ('foo.bar.com') OK, có thể có mã chung trong lookupMethod, nhưng vì nó cũng có thể bị ghi đè bởi lớp con tôi không thấy những gì bạn đạt được từ sự gián tiếp.
Mr Shark

1
Bạn sẽ không biết nên gọi phương thức nào trước, nghĩa là 'Helo' xuất phát từ một biến. Tôi đã thêm ví dụ sử dụng vào bài đăng gốc

Tôi có thể đề nghị đơn giản: eval ('SMTP (). Do_' + lệnh) ('foo.bar.com')
jforberg

8
trốn tránh? nghiêm túc? và thay vì khởi tạo một phương thức cho mỗi cuộc gọi, chúng ta có thể khởi tạo rất tốt một lần và sử dụng nó trong tất cả các cuộc gọi miễn là nó không có trạng thái bên trong.
Mahesh

1
IMO khóa thực sự ở đây là việc gửi bằng cách sử dụng getattr để chỉ định một chức năng để chạy. Nếu các phương thức nằm trong một mô-đun, bạn có thể thực hiện getattr (locals (), func_name) để lấy nó. Phần 'do_' tốt cho bảo mật / lỗi nên chỉ có thể gọi funcs với tiền tố. Bản thân SMTP gọi lookupMethod. Lý tưởng nhất là bên ngoài không biết gì về điều này. Nó không thực sự có ý nghĩa để làm SMTP (). LookupMethod (tên) (dữ liệu). Vì lệnh và dữ liệu nằm trong một chuỗi và SMTP phân tích cú pháp, điều đó có ý nghĩa hơn. Cuối cùng, SMTP có thể có trạng thái chia sẻ khác chứng minh rằng nó là một lớp.
ShawnFumo

27

Giả sử bạn không muốn trả về một giá trị mà muốn sử dụng các phương thức thay đổi thứ gì đó trên một đối tượng. Sử dụng phương pháp được nêu ở đây sẽ là:

result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

Điều xảy ra ở đây là python đánh giá tất cả các phương thức trong từ điển. Vì vậy, ngay cả khi giá trị của bạn là 'a', đối tượng sẽ được tăng lên giảm theo x.

Giải pháp:

func, args = {
  'a' : (obj.increment, (x,)),
  'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))

result = func(*args)

Vì vậy, bạn nhận được một danh sách có chứa một hàm và các đối số của nó. Bằng cách này, chỉ con trỏ hàm và danh sách đối số được trả về, không được đánh giá. 'kết quả' sau đó đánh giá cuộc gọi hàm trả về.


23

Tôi sẽ thả hai xu của tôi ở đây. Lý do không có câu lệnh case / switch trong Python là vì Python tuân theo nguyên tắc 'Chỉ có một cách đúng để làm điều gì đó'. Vì vậy, rõ ràng bạn có thể đưa ra nhiều cách khác nhau để tái tạo chức năng chuyển đổi / trường hợp, nhưng cách Pythonic để thực hiện điều này là cấu trúc if / elif. I E

if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"

Tôi chỉ cảm thấy PEP 8 xứng đáng nhận được một cái gật đầu ở đây. Một trong những điều hay về Python là sự đơn giản và thanh lịch của nó. Điều đó phần lớn xuất phát từ các nguyên tắc được đặt trong PEP 8 của chúng tôi, bao gồm "Chỉ có một cách đúng để làm điều gì đó"


6
Vậy tại sao Python có các vòng lặp và trong khi các vòng lặp? Mọi thứ bạn có thể làm với vòng lặp for bạn có thể thực hiện với vòng lặp while.
itbruce

1
Thật. Switch / case quá thường xuyên bị lạm dụng bởi các lập trình viên mới bắt đầu. Những gì họ thực sự muốn là mô hình chiến lược .
dùng228395

Âm thanh như Python mong muốn đó là Clojure
TWR Cole

1
@TWRCole Tôi không nghĩ vậy, Python đã làm điều đó trước tiên. Python đã xuất hiện từ năm 1990 và Clojure từ năm 2007
Taylor

Chỉ có một cách đúng để làm một cái gì đó. Python 2.7 hay Python 3? Cười lớn.
TWR Cole

17

mở rộng trên ý tưởng "dict as switch". nếu bạn muốn sử dụng một giá trị mặc định cho công tắc của mình:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'

14
Tôi nghĩ việc sử dụng .get () trên dict với mặc định được chỉ định rõ ràng hơn. Tôi thích để lại Ngoại lệ cho các trường hợp đặc biệt và nó cắt ba dòng mã và mức độ thụt mà không bị che khuất.
Chris B.

10
Đây một trường hợp đặc biệt. Nó có thể hoặc không phải là một trường hợp hiếm gặp tùy thuộc vào hữu ích, nhưng nó chắc chắn là một ngoại lệ (dựa vào lại 'default') từ quy tắc (nhận được một cái gì đó từ lệnh này). Theo thiết kế, các chương trình Python sử dụng các ngoại lệ khi thả mũ. Điều đó đang được nói, việc sử dụng getcó khả năng làm cho mã đẹp hơn một chút.
Mike Graham

16

Nếu bạn có một khối trường hợp phức tạp, bạn có thể xem xét sử dụng bảng tra cứu từ điển chức năng ...

Nếu bạn chưa làm điều này trước khi bạn nên bước vào trình gỡ lỗi của mình và xem chính xác cách từ điển tìm kiếm từng chức năng.

LƯU Ý: Đỗ không sử dụng "()" trong trường hợp / tra cứu từ điển hoặc nó sẽ gọi mỗi người trong số các chức năng của bạn như là khối từ điển / trường hợp được tạo ra. Hãy nhớ điều này bởi vì bạn chỉ muốn gọi mỗi hàm một lần bằng cách sử dụng tra cứu kiểu băm.

def first_case():
    print "first"

def second_case():
    print "second"

def third_case():
    print "third"

mycase = {
'first': first_case, #do not use ()
'second': second_case, #do not use ()
'third': third_case #do not use ()
}
myfunc = mycase['first']
myfunc()

Tôi thích giải pháp của bạn. Nhưng, nếu tôi chỉ cần truyền một số biến hoặc đối tượng thì sao?
Tedo Vrbanec

Điều này sẽ không hoạt động nếu phương thức đang mong đợi các tham số.
Kicesangar

16

Nếu bạn đang tìm kiếm câu lệnh phụ, dưới dạng "switch", tôi đã xây dựng một mô-đun python mở rộng Python. Nó được gọi là ESPY là "Cấu trúc nâng cao cho Python" và nó có sẵn cho cả Python 2.x và Python 3.x.

Ví dụ, trong trường hợp này, một câu lệnh chuyển đổi có thể được thực hiện theo đoạn mã sau:

macro switch(arg1):
    while True:
        cont=False
        val=%arg1%
        socket case(arg2):
            if val==%arg2% or cont:
                cont=True
                socket
        socket else:
            socket
        break

có thể được sử dụng như thế này:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")

Vì vậy, espy dịch nó trong Python là:

a=3
while True:
    cont=False
    if a==0 or cont:
        cont=True
        print ("Zero")
    if a==1 or cont:
        cont=True
        print ("Smaller than 2")
        break
    print ("greater than 1")
    break

Rất tuyệt, nhưng quan điểm của while True: ở đầu mã Python được tạo? Nó chắc chắn sẽ chạm breakvào phần dưới cùng của mã Python được tạo, do đó, dường như cả tôi while True:breakcó thể bị xóa. Hơn nữa, liệu ESPY có đủ thông minh để thay đổi tên contnếu người dùng sử dụng cùng tên đó trong mã của họ không? Trong mọi trường hợp, tôi muốn sử dụng Python vani vì vậy tôi sẽ không sử dụng nó, nhưng nó cũng tuyệt vời không kém. +1 cho sự mát mẻ tuyệt đối.
ArtOfWarfare

@ArtOfWarfare Lý do cho while True:breaks là cho phép nhưng không yêu cầu thông qua.
Solomon Ucko

Mô-đun này vẫn còn có sẵn?
Solomon Ucko

15

Tôi thấy rằng một cấu trúc chuyển đổi phổ biến:

switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;

có thể được biểu thị bằng Python như sau:

(lambda x: v1 if p1(x) else v2 if p2(x) else v3)

hoặc được định dạng một cách rõ ràng hơn:

(lambda x:
     v1 if p1(x) else
     v2 if p2(x) else
     v3)

Thay vì là một tuyên bố, phiên bản python là một biểu thức, đánh giá một giá trị.


Ngoài ra, thay vì ... tham số ... và p1 (x) thì thế nào parameterp1==parameter
Bob Stein

@ BobStein-VisiBone hi, đây là một ví dụ chạy trong phiên python của tôi : f = lambda x: 'a' if x==0 else 'b' if x==1 else 'c'. Khi tôi gọi sau f(2), tôi đã nhận 'c'; f(1), 'b'; và f(0), 'a'. Đối với p1 (x), nó biểu thị một vị ngữ; miễn là nó trả về Truehoặc False, bất kể đó là lời gọi hàm hay biểu thức, đều ổn cả.
leo

@ BobStein-VisiBone Vâng, bạn đã đúng! Cảm ơn :) Để biểu thức nhiều dòng hoạt động, nên đặt dấu ngoặc đơn, như trong đề xuất của bạn hoặc như trong ví dụ đã sửa đổi của tôi.
leo

Thông minh. Bây giờ tôi sẽ xóa tất cả các ý kiến ​​của tôi về parens.
Bob Stein

15

Hầu hết các câu trả lời ở đây đều khá cũ và đặc biệt là những câu được chấp nhận, vì vậy nó có vẻ đáng để cập nhật.

Đầu tiên, Câu hỏi thường gặp về Python chính thức bao gồm điều này và khuyến nghị elifchuỗi cho các trường hợp đơn giản và cho các trường hợp dictlớn hơn hoặc phức tạp hơn. Nó cũng gợi ý một bộvisit_ phương thức (một kiểu được sử dụng bởi nhiều khung máy chủ) cho một số trường hợp:

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

Câu hỏi thường gặp cũng đề cập đến PEP 275 , được viết để có được quyết định chính thức một lần và tất cả về việc thêm các câu lệnh chuyển đổi kiểu C. Nhưng PEP đó thực sự đã được hoãn lại với Python 3 và nó chỉ bị từ chối chính thức dưới dạng một đề xuất riêng, PEP 3103 . Tất nhiên, câu trả lời là không có phần mềm nhưng hai PEP có liên kết đến thông tin bổ sung nếu bạn quan tâm đến lý do hoặc lịch sử.


Một điều xuất hiện nhiều lần (và có thể thấy trong PEP 275, mặc dù nó đã bị cắt ra như một đề xuất thực tế) là nếu bạn thực sự bận tâm khi có 8 dòng mã để xử lý 4 trường hợp, so với 6 trường hợp các dòng bạn có trong C hoặc Bash, bạn luôn có thể viết này:

if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')

Điều này không được PEP 8 khuyến khích chính xác, nhưng nó có thể đọc được và không quá khác thường.


Trong hơn một thập kỷ kể từ khi PEP 3103 bị từ chối, vấn đề về các tuyên bố trường hợp kiểu C, hoặc thậm chí phiên bản mạnh hơn một chút trong Go, đã bị coi là đã chết; Bất cứ khi nào bất cứ ai đưa ra ý tưởng về python hoặc -dev, họ đều đề cập đến quyết định cũ.

Tuy nhiên, ý tưởng về việc khớp mẫu theo kiểu ML đầy đủ xuất hiện cứ sau vài năm, đặc biệt là khi các ngôn ngữ như Swift và Rust đã áp dụng nó. Vấn đề là thật khó để sử dụng nhiều từ khớp mẫu mà không có các kiểu dữ liệu đại số. Trong khi Guido tỏ ra thông cảm với ý tưởng này, không ai đưa ra một đề xuất phù hợp với Python lắm. (Bạn có thể đọc 2014 strawman của tôi cho một ví dụ.) Điều này có thể thay đổi theo dataclasstrong 3,7 và một số đề xuất lẻ tẻ cho một mạnh hơn enumđể xử lý các loại Tóm lại, hoặc với các đề xuất khác nhau cho các loại khác nhau của các ràng buộc tuyên bố địa phương (như PEP 3150 , hoặc tập hợp các đề xuất hiện đang được thảo luận trên -ideas). Nhưng cho đến nay, nó đã không.

Thỉnh thoảng cũng có những đề xuất cho kết hợp kiểu Perl 6, về cơ bản là một sự nhầm lẫn của tất cả mọi thứ, từ elifregex đến chuyển đổi loại một lần gửi.


15

Giải pháp để chạy các chức năng:

result = {
    'case1':     foo1, 
    'case2':     foo2,
    'case3':     foo3,
    'default':   default,
}.get(option)()

trong đó foo1 (), foo2 (), foo3 () và default () là các hàm


1
Có, ví dụ: nếu tùy chọn biến của bạn == "case2" kết quả của bạn = foo2 ()
Alejandro Quintanar

và cứ thế.
Alejandro Quintanar

Vâng, tôi hiểu mục đích. Nhưng mối quan tâm của tôi là nếu bạn chỉ muốn foo2(), các foo1(), foo3()default()các chức năng đều cũng sẽ chạy, có nghĩa là mọi thứ có thể mất một thời gian dài
Brian Underwood

1
bỏ qua () bên trong từ điển sử dụng get(option)(). Vấn đề được giải quyết.
hồ bấm giờ

1
Tuyệt vời việc sử dụng () là một giải pháp ghi, tôi đã thực hiện một ý chính để kiểm tra nó gist.github.com/aquintanar/01e9920d8341c5c6252d507669758fe5
Alejandro Quintanar

13

Tôi đã không tìm thấy câu trả lời đơn giản mà tôi đang tìm kiếm ở bất cứ đâu trên tìm kiếm của Google. Nhưng dù sao thì tôi cũng đã hiểu ra rồi. Nó thực sự khá đơn giản. Quyết định đăng nó, và có thể ngăn một vài vết trầy xước trên đầu người khác. Chìa khóa chỉ đơn giản là "trong" và bộ dữ liệu. Dưới đây là hành vi câu lệnh chuyển đổi với thông qua, bao gồm cả thông qua RANDOM.

l = ['Dog', 'Cat', 'Bird', 'Bigfoot',
     'Dragonfly', 'Snake', 'Bat', 'Loch Ness Monster']

for x in l:
    if x in ('Dog', 'Cat'):
        x += " has four legs"
    elif x in ('Bat', 'Bird', 'Dragonfly'):
        x += " has wings."
    elif x in ('Snake',):
        x += " has a forked tongue."
    else:
        x += " is a big mystery by default."
    print(x)

print()

for x in range(10):
    if x in (0, 1):
        x = "Values 0 and 1 caught here."
    elif x in (2,):
        x = "Value 2 caught here."
    elif x in (3, 7, 8):
        x = "Values 3, 7, 8 caught here."
    elif x in (4, 6):
        x = "Values 4 and 6 caught here"
    else:
        x = "Values 5 and 9 caught in default."
    print(x)

Cung cấp:

Dog has four legs
Cat has four legs
Bird has wings.
Bigfoot is a big mystery by default.
Dragonfly has wings.
Snake has a forked tongue.
Bat has wings.
Loch Ness Monster is a big mystery by default.

Values 0 and 1 caught here.
Values 0 and 1 caught here.
Value 2 caught here.
Values 3, 7, 8 caught here.
Values 4 and 6 caught here
Values 5 and 9 caught in default.
Values 4 and 6 caught here
Values 3, 7, 8 caught here.
Values 3, 7, 8 caught here.
Values 5 and 9 caught in default.

Đâu là chính xác ở đây?
Jonas Schäfer

Giáo sư! Có sự sụp đổ ở đó, nhưng tôi không đóng góp cho Stack Overflow nữa. Đừng thích THEM chút nào. Tôi thích sự đóng góp của người khác, nhưng không phải là Stackoverflow. Nếu bạn đang sử dụng thông qua FUNCTIONALITY thì bạn muốn CATCH một số điều kiện nhất định trong tất cả một trường hợp trong một công tắc (bắt tất cả), cho đến khi bạn đạt được một tuyên bố ngắt trong một công tắc.
JD Graham

2
Ở đây cả hai giá trị "Dog" và "Cat" FALL QUA và được xử lý bởi chức năng CÙNG, chúng được định nghĩa là có "bốn chân". Đó là một TÓM TẮT tương đương với rơi vào và các giá trị khác nhau được xử lý bởi câu lệnh SAME trong trường hợp xảy ra ngắt.
JD Graham

@JDGraham Tôi nghĩ Jonas có nghĩa là một khía cạnh khác của sự sụp đổ, xảy ra khi lập trình viên thỉnh thoảng quên viết breakvào cuối mã cho a case. Nhưng tôi nghĩ chúng ta không cần "thất bại" như vậy :)
Mikhail Batcer

12

Các giải pháp tôi sử dụng:

Một sự kết hợp của 2 trong số các giải pháp được đăng ở đây, tương đối dễ đọc và hỗ trợ mặc định.

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)

Ở đâu

.get('c', lambda x: x - 22)(23)

tra cứu "lambda x: x - 2"trong dict và sử dụng nó vớix=23

.get('xxx', lambda x: x - 22)(44)

không tìm thấy nó trong dict và sử dụng mặc định "lambda x: x - 22"với x=44.


10
# simple case alternative

some_value = 5.0

# this while loop block simulates a case block

# case
while True:

    # case 1
    if some_value > 5:
        print ('Greater than five')
        break

    # case 2
    if some_value == 5:
        print ('Equal to five')
        break

    # else case 3
    print ( 'Must be less than 5')
    break

10
def f(x):
    dictionary = {'a':1, 'b':2, 'c':3}
    return dictionary.get(x,'Not Found') 
##Returns the value for the letter x;returns 'Not Found' if x isn't a key in the dictionary

Xem xét bao gồm một mô tả ngắn về mã của bạn và cách giải quyết câu hỏi được đăng
Henry Woody

Được rồi, tôi đã thêm một bình luận cho điều đó bây giờ.
Vikhyat Agarwal

8

tôi thích câu trả lời của Mark Bies

Kể từ khi x biến phải sử dụng hai lần, tôi đã sửa đổi các hàm lambda thành không tham số.

Tôi phải chạy với results[value](value)

In [2]: result = {
    ...:   'a': lambda x: 'A',
    ...:   'b': lambda x: 'B',
    ...:   'c': lambda x: 'C'
    ...: }
    ...: result['a']('a')
    ...: 
Out[2]: 'A'

In [3]: result = {
    ...:   'a': lambda : 'A',
    ...:   'b': lambda : 'B',
    ...:   'c': lambda : 'C',
    ...:   None: lambda : 'Nothing else matters'

    ...: }
    ...: result['a']()
    ...: 
Out[3]: 'A'

Chỉnh sửa: Tôi nhận thấy rằng tôi có thể sử dụng Noneloại với từ điển. Vì vậy, điều này sẽ thi đuaswitch ; case else


Không phải trường hợp Không có giả lập đơn giản result[None]()?
Bob Stein

Đúng chính xác. Ý tôi làresult = {'a': 100, None:5000}; result[None]
guneysus

4
Chỉ cần kiểm tra rằng không ai đang suy nghĩ None:hành xử như thế nào default:.
Bob Stein

7
def f(x):
     return 1 if x == 'a' else\
            2 if x in 'bcd' else\
            0 #default

Ngắn gọn và dễ đọc, có giá trị mặc định và hỗ trợ các biểu thức trong cả hai điều kiện và giá trị trả về.

Tuy nhiên, nó kém hiệu quả hơn so với giải pháp với một từ điển. Ví dụ, Python phải quét qua tất cả các điều kiện trước khi trả về giá trị mặc định.


7

bạn có thể sử dụng một lệnh được gửi đi:

#!/usr/bin/env python


def case1():
    print("This is case 1")

def case2():
    print("This is case 2")

def case3():
    print("This is case 3")


token_dict = {
    "case1" : case1,
    "case2" : case2,
    "case3" : case3,
}


def main():
    cases = ("case1", "case3", "case2", "case1")
    for case in cases:
        token_dict[case]()


if __name__ == '__main__':
    main()

Đầu ra:

This is case 1
This is case 3
This is case 2
This is case 1

6

Đơn giản, không thử nghiệm; mỗi điều kiện được đánh giá độc lập: không có thông qua, nhưng tất cả các trường hợp được đánh giá (mặc dù biểu thức để bật chỉ được đánh giá một lần), trừ khi có tuyên bố ngắt. Ví dụ,

for case in [expression]:
    if case == 1:
        print(end='Was 1. ')

    if case == 2:
        print(end='Was 2. ')
        break

    if case in (1, 2):
        print(end='Was 1 or 2. ')

    print(end='Was something. ')

in Was 1. Was 1 or 2. Was something. (Chết tiệt! Tại sao tôi không thể có khoảng trắng theo sau trong các khối mã nội tuyến?) nếu expressionđánh giá 1, Was 2.nếu expressionđánh giá 2hoặc Was something.nếu expressionđánh giá với thứ khác.


1
Vâng, mùa thu thông qua các công trình, nhưng chỉ để đi đến do_default.
syockit

5

Xác định:

def switch1(value, options):
  if value in options:
    options[value]()

cho phép bạn sử dụng cú pháp khá đơn giản, với các trường hợp được gói vào bản đồ:

def sample1(x):
  local = 'betty'
  switch1(x, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye," + local),
      print("!")),
    })

Tôi tiếp tục cố gắng xác định lại công tắc theo cách cho phép tôi thoát khỏi "lambda:", nhưng đã từ bỏ. Tinh chỉnh định nghĩa:

def switch(value, *maps):
  options = {}
  for m in maps:
    options.update(m)
  if value in options:
    options[value]()
  elif None in options:
    options[None]()

Cho phép tôi ánh xạ nhiều trường hợp vào cùng một mã và cung cấp tùy chọn mặc định:

def sample(x):
  switch(x, {
    _: lambda: print("other") 
    for _ in 'cdef'
    }, {
    'a': lambda: print("hello"),
    'b': lambda: (
      print("goodbye,"),
      print("!")),
    None: lambda: print("I dunno")
    })

Mỗi trường hợp sao chép phải có trong từ điển riêng của mình; switch () hợp nhất các từ điển trước khi tra cứu giá trị. Nó vẫn xấu hơn tôi muốn, nhưng nó có hiệu quả cơ bản là sử dụng tra cứu băm trên biểu thức, thay vì lặp qua tất cả các phím.


5

Tôi nghĩ cách tốt nhất là sử dụng các thành ngữ ngôn ngữ python để giữ cho mã của bạn có thể kiểm tra được . Như đã trình bày trong các câu trả lời trước, tôi sử dụng từ điển để tận dụng các cấu trúc và ngôn ngữ python và giữ mã "trường hợp" được phân lập trong các phương thức khác nhau. Bên dưới có một lớp, nhưng bạn có thể sử dụng trực tiếp một mô-đun, toàn cầu và các chức năng. Lớp này có các phương thức có thể được kiểm tra với sự cô lập . Tùy thuộc vào nhu cầu của bạn, bạn cũng có thể chơi với các phương thức và thuộc tính tĩnh.

class ChoiceManager:

    def __init__(self):
        self.__choice_table = \
        {
            "CHOICE1" : self.my_func1,
            "CHOICE2" : self.my_func2,
        }

    def my_func1(self, data):
        pass

    def my_func2(self, data):
        pass

    def process(self, case, data):
        return self.__choice_table[case](data)

ChoiceManager().process("CHOICE1", my_data)

Có thể tận dụng phương thức này bằng cách sử dụng các lớp làm khóa của "__choice_table". Bằng cách này, bạn có thể tránh lạm dụng isinstance và giữ tất cả sạch sẽ và có thể kiểm tra.

Giả sử bạn phải xử lý rất nhiều tin nhắn hoặc gói từ mạng hoặc MQ của bạn. Mỗi gói có cấu trúc riêng và mã quản lý của nó (theo cách chung). Với đoạn mã trên, có thể làm một cái gì đó như thế này:

class PacketManager:

    def __init__(self):
        self.__choice_table = \
        {
            ControlMessage : self.my_func1,
            DiagnosticMessage : self.my_func2,
        }

    def my_func1(self, data):
        # process the control message here
        pass

    def my_func2(self, data):
        # process the diagnostic message here
        pass

    def process(self, pkt):
        return self.__choice_table[pkt.__class__](pkt)

pkt = GetMyPacketFromNet()
PacketManager().process(pkt)


# isolated test or isolated usage example
def test_control_packet():
    p = ControlMessage()
    PacketManager().my_func1(p)

Vì vậy, độ phức tạp không được lan truyền trong dòng mã nhưng nó được biểu hiện trong cấu trúc mã .


Thực sự xấu xí ... trường hợp chuyển đổi là rất sạch sẽ khi đọc. Không thể hiểu tại sao nó không được thực hiện trong Python.
jmcollin92

@AndyClifton: Tôi xin lỗi ... một ví dụ? Hãy nghĩ về mỗi khi bạn cần có nhiều mã phân nhánh quyết định và bạn có thể áp dụng phương pháp này.
J_Zar

@ jmcollin92: tuyên bố chuyển đổi là dễ hiểu, tôi đồng ý. Tuy nhiên, lập trình viên có xu hướng viết các câu lệnh và mã rất dài không thể tái sử dụng. Cách tôi mô tả là sạch hơn để kiểm tra và tái sử dụng nhiều hơn, IMHO.
J_Zar

@J_Zar: tái. Yêu cầu của tôi về một ví dụ: có, tôi hiểu điều đó, nhưng tôi đang vật lộn để đưa nó vào bối cảnh của một đoạn mã lớn hơn. Bạn có thể chỉ ra làm thế nào tôi có thể sử dụng điều này trong một tình huống thực tế?
Andy Clifton

1
@AndyClifton: Tôi xin lỗi, tôi đến trễ nhưng tôi đã đăng một số trường hợp ví dụ.
J_Zar

5

Mở rộng câu trả lời của Greg Hewgill - Chúng tôi có thể gói gọn giải pháp từ điển bằng cách sử dụng trang trí:

def case(callable):
    """switch-case decorator"""
    class case_class(object):
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

        def do_call(self):
            return callable(*self.args, **self.kwargs)

return case_class

def switch(key, cases, default=None):
    """switch-statement"""
    ret = None
    try:
        ret = case[key].do_call()
    except KeyError:
        if default:
            ret = default.do_call()
    finally:
        return ret

Điều này sau đó có thể được sử dụng với @case-decorator

@case
def case_1(arg1):
    print 'case_1: ', arg1

@case
def case_2(arg1, arg2):
    print 'case_2'
    return arg1, arg2

@case
def default_case(arg1, arg2, arg3):
    print 'default_case: ', arg1, arg2, arg3

ret = switch(somearg, {
    1: case_1('somestring'),
    2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))

print ret

Tin tốt là điều này đã được thực hiện trong NeoPySwitch -module. Đơn giản chỉ cần cài đặt bằng pip:

pip install NeoPySwitch

5

Một giải pháp tôi có xu hướng sử dụng cũng sử dụng từ điển là:

def decision_time( key, *args, **kwargs):
    def action1()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action2()
        """This function is a closure - and has access to all the arguments"""
        pass
    def action3()
        """This function is a closure - and has access to all the arguments"""
        pass

   return {1:action1, 2:action2, 3:action3}.get(key,default)()

Điều này có lợi thế là nó không cố gắng đánh giá các chức năng mọi lúc và bạn chỉ cần đảm bảo rằng chức năng bên ngoài có được tất cả thông tin mà các chức năng bên trong cần.


5

Cho đến nay đã có rất nhiều câu trả lời cho biết: "chúng tôi không có công tắc trong Python, hãy làm theo cách này". Tuy nhiên, tôi muốn chỉ ra rằng chính câu lệnh chuyển đổi là một cấu trúc dễ bị lạm dụng có thể và nên tránh trong hầu hết các trường hợp vì chúng thúc đẩy lập trình lười biếng. Trường hợp tại điểm:

def ToUpper(lcChar):
    if (lcChar == 'a' or lcChar == 'A'):
        return 'A'
    elif (lcChar == 'b' or lcChar == 'B'):
        return 'B'
    ...
    elif (lcChar == 'z' or lcChar == 'Z'):
        return 'Z'
    else:
        return None        # or something

Bây giờ, bạn có thể làm điều này với một câu lệnh chuyển đổi (nếu Python cung cấp một) nhưng bạn sẽ lãng phí thời gian của mình vì có những phương pháp làm tốt điều này. Hoặc có thể, bạn có một cái gì đó ít rõ ràng hơn:

def ConvertToReason(code):
    if (code == 200):
        return 'Okay'
    elif (code == 400):
        return 'Bad Request'
    elif (code == 404):
        return 'Not Found'
    else:
        return None

Tuy nhiên, loại hoạt động này có thể và nên được xử lý bằng từ điển vì nó sẽ nhanh hơn, ít phức tạp hơn, ít bị lỗi hơn và gọn hơn.

Và phần lớn "trường hợp sử dụng" cho các câu lệnh chuyển đổi sẽ thuộc một trong hai trường hợp này; chỉ có rất ít lý do để sử dụng một lý do nếu bạn nghĩ kỹ về vấn đề của mình.

Vì vậy, thay vì hỏi "làm thế nào để tôi chuyển đổi trong Python?", Có lẽ chúng ta nên hỏi, "tại sao tôi muốn chuyển đổi trong Python?" bởi vì đó thường là câu hỏi thú vị hơn và thường sẽ phơi bày những lỗ hổng trong thiết kế của bất cứ thứ gì bạn đang xây dựng.

Bây giờ, điều đó không có nghĩa là các công tắc cũng không bao giờ được sử dụng. Các máy trạng thái, từ vựng, trình phân tích cú pháp và automata đều sử dụng chúng ở một mức độ nào đó và nói chung, khi bạn bắt đầu từ một đầu vào đối xứng và đi đến một đầu ra không đối xứng, chúng có thể hữu ích; bạn chỉ cần đảm bảo rằng bạn không sử dụng công tắc như một cái búa vì bạn thấy một loạt các đinh trong mã của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.