在 Python 中切换

发布于 2024-12-27 08:40:33 字数 480 浏览 0 评论 0原文

我尝试在 python 中创建类似 switch 的语句,而不是使用大量 if 语句。

代码如下所示:

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

我的问题是,这不起作用。 (适用于 if 语句,但在我看来这会更漂亮)。

我在Python中找到了一些开关的例子,它们遵循这个结构。谁能帮助我吗?

I have tried making a switch like statement in python, instead of having a lot of if statements.

The code looks like this:

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

My problem is, that this does not work. (Works with if statements, but this would in my opinion be more pretty).

I have found some examples of switches in Python, and they follow this structure. Can anyone help me?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

思念绕指尖 2025-01-03 08:40:33

(a) 我看不出 if...elif...else 有什么问题

(b) 我认为 python 没有 switch 语句,原因与 Smalltalk 没有一样:它几乎完全是多余的,并且在如果您想切换类型,您可以向您的类添加适当的方法;同样,打开值应该在很大程度上是多余的。

注意:我在评论中获悉,无论 Guido 最初没有创建开关的原因是什么,添加该开关的 PEP 都被拒绝了,因为对添加此类声明的支持极其有限。请参阅:http://www.python.org/dev/peps/pep-3103/

( c) 如果您确实需要切换行为,请使用哈希表 (dict) 来存储可调用项。结构是:

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

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

(a) I fail to see what is wrong with if...elif...else

(b) I assume that python does not have a switch statement for the same reason that Smalltalk doesn't: it's almost completely redundant, and in the case where you want to switch on types, you can add an appropriate method to your classes; and likewise switching on values should be largely redundant.

Note: I am informed in the comments that whatever Guido's reason for not creating a switch in the first place, PEPs to have it added were rejected on the basis that support for adding such a statement is extremely limited. See: http://www.python.org/dev/peps/pep-3103/

(c) If you really need switching behaviour, use a hashtable (dict) to store callables. The structure is:

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

func = switch_dict[switch_var]
result = func() # or if they take args, pass args
逆流 2025-01-03 08:40:33

if 没有什么问题:

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

如果太冗长,或者如果你有很多情况,请将它们放入字典中:

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

如果你的条件有点复杂,你需要考虑一个关于你的数据结构的知识很少。例如:

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.items():
    if key[0] <= case_var < key[1]:
        print(value)

There's nothing wrong with a long if:

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

If that's too long winded, or if you have a lot of cases, put them in a dictionary:

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

If your conditions are a bit more complex, you need to think a little about your data structures. e.g.:

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.items():
    if key[0] <= case_var < key[1]:
        print(value)
┾廆蒐ゝ 2025-01-03 08:40:33

其他 ans 适用于旧版本的 python。对于python v3.10+,您可以使用match/case 比一般的 switch/case 结构更强大。

def something(val):
    match val:
        case "A":
            return "A"
        case "B":
            return "B"
        case "C":
            return "C"
        case _:
            return "Default"

something("A")

Other ans are suitable for older version of python. For python v3.10+ you can use match/case which is more powerful than general switch/case construct.

def something(val):
    match val:
        case "A":
            return "A"
        case "B":
            return "B"
        case "C":
            return "C"
        case _:
            return "Default"

something("A")
白色秋天 2025-01-03 08:40:33

Python 中的赋值是一个语句,不能是表达式的一部分。此外,以这种方式使用文字会立即评估所有内容,这可能不是您想要的。仅使用 if ,您不会通过使用它获得任何可读性。

Assignment in Python is a statement, and cannot be a part of expression. Also, using literal in this way evaluates everything at once, which is probably not what you want. Just use ifs, you won't gain any readability by using this.

天煞孤星 2025-01-03 08:40:33

我不知道你发现哪篇文章做了这样的事情,但这真的很混乱:将始终评估整个结果字典,而不是只做部分工作(作为 switch / if do),每次你都会完成全部工作。 (即使您只使用结果的一部分)。

实际上,Python 中的快速 switch 语句正在使用“if”:

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

I don't know which article you've found to do something like this, but this is really messy: the whole result diction will be always evaluated, and instead of doing only part of the work (as a switch / if do), you'll do the whole work everytime. (even if you use only a part of the result).

Really, a fast switch statement in Python is using "if":

if case == 1:
  pass
elif case == 2:
  pass
elif case == 3:
  pass
else:
  # default case
  pass
酒儿 2025-01-03 08:40:33

中的“switch..case”相同的效果:

使用“get”方法,可以达到与 C. Marcin 示例

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

With "get" method, you can have the same effect as "switch..case" in C.

Marcin example :

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
时光暖心i 2025-01-03 08:40:33

可以做您想做的事情,但您不应该这样做。也就是说,方法如下:你可以看到它并没有改善事情。

这种方式的最大问题是,Python 将在您声明字典时对您的测试和结果进行一次评估。相反,您必须做的是使所有条件和结果语句发挥作用;这样,评估就会推迟到您致电他们为止。幸运的是,有一种方法可以使用 lambda 关键字对简单函数进行内联操作。其次,赋值语句不能用作Python中的值,因此我们的动作函数(如果相应的条件函数返回真值则执行)必须返回一个用于递增c<的值/代码>;他们不能自己分配给c

此外,字典中的项目没有排序,因此您的测试不一定按照您定义的顺序执行,这意味着您可能应该使用保留顺序的字典以外的其他内容,例如元组或列表。我假设您只想执行一个案例。

那么,我们开始吧:

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

这比一系列 if/elif 语句更具可读性吗?不呜呜呜。特别是,第四种情况远不如应有的那样容易理解,因为我们必须依赖一个返回 c 增量的函数来修改一个完全不同的变量,然后我们必须弄清楚如何让它返回 0 以便 c 实际上不会被修改。丑陋。

不要这样做。事实上,这段代码甚至可能无法按原样运行,因为我认为它太丑陋而无法测试。

You can do something like what you want, but you shouldn't. That said, here's how; you can see how it does not improve things.

The biggest problem with the way you have it is that Python will evaluate your tests and results once, at the time you declare the dictionary. What you'd have to do instead is make all conditions and the resulting statements functions; this way, evaluation is deferred until you call them. Fortunately there is a way to do this inline for simple functions using the lambda keyword. Secondly, the assignment statement can't be used as a value in Python, so our action functions (which are executed if the corresponding condition function returns a truthy value) have to return a value that will be used to increment c; they can't assign to c themselves.

Also, the items in a dictionary aren't ordered, so your tests won't necessarily be performed in the order you define them, meaning you probably should use something other than a dictionary that preserves order, such as a tuple or a list. I am assuming you want only ever one case to execute.

So, here we go:

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

Is this more readable than a sequence of if/elif statements? Nooooooooooooo. In particular, the fourth case is far less comprehensible than it should be because we are having to rely on a function that returns the increment for c to modify a completely different variable, and then we have to figure out how to get it to return a 0 so that c won't actually be modified. Uuuuuugly.

Don't do this. In fact this code probably won't even run as-is, as I deemed it too ugly to test.

花期渐远 2025-01-03 08:40:33

虽然 if..else 没有任何问题,但我发现“Python 中的 switch”仍然是一个有趣的问题陈述。对此,我认为 Marcin 的(已弃用的)选项 (c) 和/或 Snim2 的第二个变体可以以更易读的方式编写。

为此,我们可以声明一个 switch 类,并利用 __init__() 来声明我们想要切换的 case,而 __call__ () 有助于移交一个列出(案例,函数)对的字典:

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.')

或者,分别地,因为只有两个方法的类,其中一个是 __init__(),是'不是一个真正的类:(

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

注意:选择比Exception

例如,

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

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

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

您可以调用

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

which,对于这个特定的示例将打印

最后的手段

这不像 C 开关,因为不同情况下没有 break,因为每种情况仅执行为特定情况声明的函数(即 break > 总是隐式调用)。其次,每个案例只能列出一个将在找到的案例上执行的函数。

While there is nothing wrong with if..else, I find "switch in Python" still an intriguing problem statement. On that, I think Marcin's (deprecated) option (c) and/or Snim2's second variant can be written in a more readable way.

For this we can declare a switch class, and exploit the __init__() to declare the case we want to switch, while __call__() helps to hand over a dict listing the (case, function) pairs:

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.')

Or, respectively, since a class with only two methods, of which one is __init__(), isn't really a class:

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

(note: choose something smarter than Exception)

With for example

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

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

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

you can call

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

which, for this particular example would print

last resort

This doesn't behave like a C switch in that there is no break for the different cases, because each case executes only the function declared for the particular case (i.e. break is implicitly always called). Secondly, each case can list exactly only one function that will be executed upon a found case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文