有没有更好的方法在python中编写嵌套的if语句?[关闭]


34

有没有比此方法更Python化的方式来嵌套if语句:

def convert_what(numeral_sys_1, numeral_sys_2):

    if numeral_sys_1 == numeral_sys_2:      
        return 0
    elif numeral_sys_1 == "Hexadecimal":
        if numeral_sys_2 == "Decimal":
            return 1
        elif numeral_sys_2 == "Binary":
            return 2
    elif numeral_sys_1 == "Decimal":
        if numeral_sys_2 == "Hexadecimal":
            return 4
        elif numeral_sys_2 == "Binary":
            return 6
    elif numeral_sys_1 == "Binary":
        if numeral_sys_2 == "Hexadecimal":
            return 5
        elif numeral_sys_2 == "Decimal":
            return 3
    else:
        return 0

该脚本是简单转换器的一部分。


在不使用其他数据结构的情况下,可以将嵌套的if-else语句移到and顶级if-else语句的条件中。这样至少会更具可读性。可悲的是,python没有switch语句。
adamkgray

Python方式。Python故意不支持switch语句。参见python.org/dev/peps/pep-3103
Jongmin Baek

1
不是所有的问题,但如果你想使事情更Python,怎么样定义常量或返回值枚举-更好的为读者不是“幻数” ....
垫Wichmann的

Answers:


13

当@Aryerez和@SencerH。的答案起作用时,numeral_sys_1必须numeral_sys_2在列出值对时为的每个可能值重复写入的每个可能值,从而在可能值数量增加时使数据结构更难维护。您可以改用嵌套的dict代替嵌套的if语句:

mapping = {
    'Hexadecimal': {'Decimal': 1, 'Binary': 2},
    'Binary': {'Decimal': 3, 'Hexadecimal': 5},
    'Decimal': {'Hexadecimal': 4, 'Binary': 6}
}
def convert_what(numeral_sys_1, numeral_sys_2):
    return mapping.get(numeral_sys_1, {}).get(numeral_sys_2, 0)

或者,您可以使用方法生成映射的值对itertools.permutations,其顺序遵循输入序列的顺序:

mapping = dict(zip(permutations(('Hexadecimal', 'Decimal', 'Binary'), r=2), (1, 2, 4, 6, 3, 5)))
def convert_what(numeral_sys_1, numeral_sys_2):
    return mapping.get((numeral_sys_1, numeral_sys_2), 0)

29

插入所有有效组合到dictionarytupleS,如果组合不存在,返回0:

def convert_what(numeral_sys_1, numeral_sys_2):
    numeral_dict = {
        ("Hexadecimal", "Decimal"    ) : 1,
        ("Hexadecimal", "Binary"     ) : 2,
        ("Decimal",     "Hexadecimal") : 4, 
        ("Decimal",     "Binary"     ) : 6,
        ("Binary",      "Hexadecimal") : 5,
        ("Binary",      "Decimal"    ) : 3
    }
    return numeral_dict.get((numeral_sys_1, numeral_sys_2), 0)

如果您打算循环使用该函数,最好在函数外部定义字典,这样就不会在每次调用该函数时都重新创建它。


2
except KeyError:
RomanPerekhrest

@RomanPerekhrest我已经添加了它,尽管在这个特定的问题中,该函数本身没有其他类型的error可以产生与原始函数不同的输出。
Aryerez '19

1
括号在[]中是多余的。除了空的元组,是逗号使它成为一个元组,而不是括号,这在某些情况下仅用于操作顺序。
镀金

4
您可以仅将dict .get()方法与0默认值一起使用,而不是使用try语句。
镀金

@gilch我放了括号。但我确实喜欢这种try:... except:...结构。
Aryerez

17

如果您确定没有其他值可以被设置为numeric_sys_1和numeric_sys_2变量,则这是最简单,最干净的解决方案。

另一方面,如果您具有除“十六进制”,“十进制”和“二进制”之外的其他任何值,则必须使用其与可用值的组合来扩展字典。

这里的逻辑是:如果字典键中的变量元组不等于给定的变量元组,则.get()方法将返回“ 0”。如果给定变量元组匹配字典中的任何键,则返回匹配键的值。

def convert_what(numeral_sys_1, numeral_sys_2):
    return {
        ("Hexadecimal", "Decimal") : 1, 
        ("Hexadecimal", "Binary") : 2, 
        ("Binary", "Decimal") : 3,
        ("Decimal", "Hexadecimal") : 4,
        ("Binary", "Hexadecimal") : 5, 
        ("Decimal", "Binary") : 6, 
     }.get((numeral_sys_1, numeral_sys_2), 0)

还有使用发电机可能是一种解决方案。看起来更聪明,但是对于这个简单的要求,硬编码字典比使用生成器要快。


我对最后一个'else:return 0'的解释是,参数不匹配,并且可能是列表中的参数之外的其他内容(即dict键)。

@tocode是的,您是对的。但是该方法也提供相同的功能。如果给方法提供了任何一个或两个参数,则说不是字符串,甚至是None类型值;由于字典中缺少关键字,.get()方法返回“ 0”。这简单吗?
Sencer H.

您不是只是复制了Aryerez的答案吗?
马丁

@马丁不,我没有。您显然错过了要点。有很多方法可以做某事,但我愿意在这里教正确的方法。实际上,下面有更好的答案。看看furkanayd的解决方案。它是完美无缺的,必须得到赏金。
Sencer H.

@SencerH。唯一的区别是您使用了dict的get()方法,这从根本上来说就是原始答案的try / except所做的事情。您不能否认这样的事实,即您复制了想法并且非常轻微地(没有改进)进行了修改和发布
Martin

3

使用嵌套列表的另一种方法。希望能帮助到你!!

def convert_what(numeral_sys_1, numeral_sys_2):

    l1 = [["Hexadecimal","Decimal"],["Hexadecimal","Binary"],
            ["Decimal","Hexadecimal"],["Decimal","Binary"],
            ["Binary","Hexadecimal"],["Binary","Decimal"]]

    return l1.index([numeral_sys_1, numeral_sys_2]) + 1 if [numeral_sys_1,numeral_sys_2] in l1 else 0

2

在我看来,此convert_what函数本身并不是很pythonic。我猜调用此代码的代码也有很多if语句,并根据的返回值进行转换convert_what()。我建议是这样的:

第一步,为每个组合创建一个函数:

def hex_dec(inp):
    return 1234  # todo implement
# do the same for hex_bin, bin_dec, dec_hex, bin_hex, dec_bin

第二步,将函数对象放入字典中。请注意,函数名称后没有(),因为我们要存储函数对象而不是调用它:

converter_funcs = {
    ("Hexadecimal", "Decimal"): hex_dec,
    ("Hexadecimal", "Binary"): hex_bin,
    ("Binary", "Decimal"): bin_dec,
    ("Decimal", "Hexadecimal"): dec_hex,
    ("Binary", "Hexadecimal"): bin_hex,
    ("Decimal", "Binary"): dec_bin,
}

第三步,也是最后一步,实现转换功能。if语句检查两个系统是否相同。然后,我们从字典中获得正确的函数并调用它:

def convert(input_number, from_sys, to_sys):
    if from_sys == to_sys:
        return input_number
    func = converter_funcs[(from_sys, to_sys)]
    return func(input_number)

2

这是通过大多数其他语言的switch-case语句完成的。在python中,我使用带有表达式字典的简单函数。

码:

def convert_what(numeral_sys_1, numeral_sys_2):
    myExpressions = {"Hexadecimal" : {"Decimal" : 1, "Binary" : 2},
                    "Decimal" : {"Hexadecimal" : 4, "Binary" : 6}, 
                    "Binary" : {"Hexadecimal" : 5, "Decimal" : 3}}
    return (myExpressions.get(numeral_sys_1, {})).get(numeral_sys_2, 0)

输出:

> convert_what("Hexadecimal", "Decimal")
> 1
> convert_what("Binary", "Binary")
> 0
> convert_what("Invalid", "Hexadecimal")
> 0

这是最佳答案的一个很好的选择,并且更容易扩展到更多的价值。
gkhnavarro

这与先前的答案非常相似:stackoverflow.com/a/58985114/1895261。另外,我认为在numerical_sys_1不在外部字典中的情况下,最后一行应该返回空字典而不是0:return(myExpressions.get(numeral_sys_1,{}))。get(numeral_sys_2,0)
棕褐色

问题Module_art中的@Sepia在else语句处给出0,这意味着返回0表示与给定表达式和相等情况不符的任何内容。
furkanayd19年

1
尝试使用您的代码运行print(convert_what(“ invalid”,“ Hexadecimal”))。它将引发错误:“ AttributeError:'int'对象没有属性'get'”。在数字_sys_1无效的情况下,用空的字典({})替换第一个0将使函数正确返回0。
棕褐色

1

通常,我会使用字典解决方案来处理if嵌套任务。一些特殊情况可能会带来另一种方法。像这个:

def convert_what(numeral_sys_1, numeral_sys_2):

    num = ['Hexadecimal','Decimal','Binary']
    tbl = [[0,1,2],
           [4,0,6],
           [5,3,0]]
    try:
        return tbl[num.index(numeral_sys_1)][num.index(numeral_sys_2)]
    except ValueError:
        return 0

1

怎么样:

def convert_what(numeral_sys_1, numeral_sys_2):
    src = numeral_sys_1, numeral_sys_2
    if src == "Hexadecimal", "Decimal":
        return 1
    if src == "Hexadecimal", "Binary"
        return 2
    # You get the gist.... 
    if src == "Decimal", "Binary":
        return 6
    return 0 

1

一个想法正在使用一个列表并获取结果的索引,即

def convert_what(numeral_sys_1, numeral_sys_2):
    if numeral_sys_1 == numeral_sys_2:      
        return 0
    return ["HexadecimalDecimal", "HexadecimalBinary", "BinaryDecimal", "DecimalHexadecimal", "BinaryHexadecimal", "DecimalBinary" ].index(numeral_sys_1 + numeral_sys_2) + 1

有趣的建议,但这在参数为(“ Decimal”,“ Not”)时不起作用,这导致ValueError:'DecimalNot'不在列表中
编码

1

正如@Sadap所说,

在我看来,此convert_what函数本身并不是很pythonic。我猜调用此代码的代码也有很多if语句,并根据的返回值进行转换convert_what()。我建议是这样的:

如果您要实现整数的基本转换,那么无论如何都可能要经过一个通用表示形式:int。无需为每对碱基分别设置一个函数,并且所涉及的两个碱基甚至不需要相互了解。

输入项

创建一个从数字系统名称到其基数的映射:

BINARY = "Binary"
DECIMAL = "Decimal"
HEXADECIMAL = "Hexadecimal"

BASES = {
    BINARY: 2,
    DECIMAL: 10,
    HEXADECIMAL: 16,
}

允许您使用读取输入int(text, BASES[numeral_sys_1])

输出量

创建一个从数字系统名称到格式说明符的映射:

FORMATTERS = {
    BINARY: "b",
    DECIMAL: "d",
    HEXADECIMAL: "x",
}

允许您使用编写输出format(n, FORMATTERS[numeral_sys_2])

使用范例

def convert(text, numeral_sys_1, numeral_sys_2):
    n = int(text, BASES[numeral_sys_1])
    return format(n, FORMATTERS[numeral_sys_2])

如果您需要支持一组不同于的格式int(x, base),或者可以提供比内置整数格式支持更多的输出基数,则可以通过使这些值成为函数来使dict更通用。


0

我喜欢保持代码干燥:

def convert_what_2(numeral_sys_1, numeral_sys_2):
    num_sys = ["Hexadecimal", "Decimal", "Binary"]
    r_value = {0: {1: 1, 2: 2},
               1: {0: 4, 2: 6},
               2: {0: 5, 1: 3} }
    try:
        value = r_value[num_sys.index(numeral_sys_1)][num_sys.index(numeral_sys_2)]
    except KeyError: # Catches when they are equal or undefined
        value = 0
    return value

0

使用其他答案提供的一些技术并将其结合起来:

def convert(key1, key2):
    keys = ["Hexadecimal", "Decimal", "Binary"]
    combinations = {(0, 1): 1, (0, 2): 2, (1, 0): 4, (1, 2): 6, (2, 0): 5, (2, 1): 3} # use keys indexes to map to combinations
    try:
        return combinations[(keys.index(key1), keys.index(key2))]
    except (KeyError, ValueError): # if value is not in list, return as 0
        return 0

-1

尽管不确定这种方法是否更快,但是也可以使用numpy来完成:

conditions = [
    ("Hexadecimal", "Decimal"), ("Hexadecimal", "Binary"),
    ("Binary", "Decimal"), ("Decimal", "Hexadecimal"), ("Binary", "Hexadecimal"), ("Decimal", "Binary")]
choices = [1,2,3,4,5,6]

可以用作:

 np.select(conditions, choices, default=0)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.