dictionary get()方法的Python 3X求值行为

dictionary get()方法的Python 3X求值行为,python,dictionary,data-structures,Python,Dictionary,Data Structures,我最近想到了下面的代码,想知道它到底出了什么问题。以前我成功地使用了Dictionary的.get方法,但现在我也想传递参数,这就是我注意到的一个有点奇怪的行为: def string_encoder(nmstr): return nmstr.encode('UTF-8') def int_adder(nr_int): return int(nr_int) + int(nr_int) def selector(fun, val): return {'str_en':

我最近想到了下面的代码,想知道它到底出了什么问题。以前我成功地使用了Dictionary的.get方法,但现在我也想传递参数,这就是我注意到的一个有点奇怪的行为:

def string_encoder(nmstr):
    return nmstr.encode('UTF-8')

def int_adder(nr_int):
    return int(nr_int) + int(nr_int)

def selector(fun, val):
    return {'str_en': string_encoder(val), 
            'nr_add': int_adder(val)}.get(fun, string_encoder(val))
selector('str_en', 'Test') -> ValueError
selector('str_en', 1) -> AttributeError
上面的代码永远不会运行。 为了检查问题,我提供了一小段代码:

def p1(pstr):
    print('p1: ', pstr)
    return pstr

def p2(pstr):
    print('p2: ', pstr)
    return pstr

def selector_2(fun, val):
    return {'p1': p1(val), 
            'p2': p2(val)}.get(fun, p2(val))
selector_2('p1', 'Test')
Out[]: p1:  Test
       p2:  Test
       p2:  Test
       'Test'
我希望下面的.get('p1','test')输出'p1:test'test。
但在我看来,每个参数都会被计算,即使它没有被选中。所以我的问题是:为什么每个参数都使用.get方法进行计算,或者如何解释这种行为

如果要避免对函数求值而只选择函数,请对第二个块执行此操作(语法也适用于第一个块):


如果要避免对函数求值,而只选择函数,请对第二个块执行此操作(语法也适用于第一个块):


dict
与参数求值一样,创建也是迫在眉睫的。因此,在运行
get
之前,您已经调用了
string\u encoder
两次,调用了
int\u adder
一次(由于行为基本上是正交的,因此除了像
“123”
这样的数字
str
之外,您将得到一个错误)

在知道调用哪个函数之前,需要避免调用该函数(理想情况下,只调用该函数一次)

最简单的解决方案是让
dict
get
调用包含函数本身,而不是调用它们的结果;无论哪个函数获胜,您都可以调用该函数。例如:

def selector(fun, val):
    # Removed (val) from all mentions of functions
    return {'str_en': string_encoder, 
            'nr_add': int_adder}.get(fun, string_encoder)(val) # <- But used it to call resulting function
这会让你意识到你并没有从
dict
中得到任何东西
dict
s具有廉价的查找功能,但每次调用都要重建
dict
,因此您没有保存任何内容。考虑到您实际上只有两种行为:

  • 如果
    fun
    'nr\u add'
  • 否则,调用
    string\u编码器
  • 正确的解决方案只是一个
    if
    检查,它更有效,更容易阅读:

    def selector(fun, val):
        if fun == 'nr_add':
            return int_adder(val)
        return string_encoder(val)
    
        # Or if you love one-liners:
        return int_adder(val) if fun == 'nr_add' else string_encoder(val)
    

    如果您的实际代码在
    dict
    中有很多条目,而不仅仅是两个条目,其中一个是不必要的,那么您可以使用
    dict
    来提高性能,但可以在全局范围内构建一次,并在函数中引用它,这样您就不会每次调用都重新构建它(这会失去
    dict
    的所有性能优势),例如:


    dict
    与参数求值一样,创建也是迫在眉睫的。因此,在运行
    get
    之前,您已经调用了
    string\u encoder
    两次,调用了
    int\u adder
    一次(由于行为基本上是正交的,因此除了像
    “123”
    这样的数字
    str
    之外,您将得到一个错误)

    在知道调用哪个函数之前,需要避免调用该函数(理想情况下,只调用该函数一次)

    最简单的解决方案是让
    dict
    get
    调用包含函数本身,而不是调用它们的结果;无论哪个函数获胜,您都可以调用该函数。例如:

    def selector(fun, val):
        # Removed (val) from all mentions of functions
        return {'str_en': string_encoder, 
                'nr_add': int_adder}.get(fun, string_encoder)(val) # <- But used it to call resulting function
    
    这会让你意识到你并没有从
    dict
    中得到任何东西
    dict
    s具有廉价的查找功能,但每次调用都要重建
    dict
    ,因此您没有保存任何内容。考虑到您实际上只有两种行为:

  • 如果
    fun
    'nr\u add'
  • 否则,调用
    string\u编码器
  • 正确的解决方案只是一个
    if
    检查,它更有效,更容易阅读:

    def selector(fun, val):
        if fun == 'nr_add':
            return int_adder(val)
        return string_encoder(val)
    
        # Or if you love one-liners:
        return int_adder(val) if fun == 'nr_add' else string_encoder(val)
    

    如果您的实际代码在
    dict
    中有很多条目,而不仅仅是两个条目,其中一个是不必要的,那么您可以使用
    dict
    来提高性能,但可以在全局范围内构建一次,并在函数中引用它,这样您就不会每次调用都重新构建它(这会失去
    dict
    的所有性能优势),例如:


    所有函数都是这样工作的。参数总是在传递给函数之前进行求值<代码>获取在这方面并不特别。是的,现在我不知怎么地看到了这个愚蠢的问题。由于dict值是一个函数调用,get函数始终会调用它……这就是所有函数的工作方式。参数总是在传递给函数之前进行求值<代码>获取在这方面并不特别。是的,现在我不知怎么地看到了这个愚蠢的问题。由于dict值是一个函数调用,get函数将始终调用该函数…duh“如果您的实际代码在dict中有很多条目,而不仅仅是两个条目,其中一个是不必要的,那么您可以使用dict来提高性能”->是的,这是我的应用程序场景。因为我想做一个类似“select”的操作符。感谢您总是通过调用选择器函数来创建字典,从而提示性能问题。“如果您的实际代码在dict中有很多条目,而不仅仅是两个条目,其中一个是不必要的,那么您可以使用dict提高性能”->是的,这是我的应用程序场景。因为我想做一个类似“select”的操作符。感谢您通过调用选择器函数创建字典来提示性能问题。
    # Built only once at global scope
    _selector_lookup_table = {
        'str_en': string_encoder, 
        'nr_add': int_adder,
        'foo': some_other_func,
        ...
        'baz': yet_another_func,
        }
    
    def selector(fun, val):
        # Reused in function for each call
        return _selector_lookup_table.get(fun, default_func)(val)