【问题标题】:Inner function not accessible to dict comprehensiondict理解无法访问内部功能
【发布时间】:2018-05-09 07:39:53
【问题描述】:

我正在编写一些 Python 2.7.12 代码,并且对此代码执行中出现以下错误感到非常惊讶:

def validate_available_links(self, link_dict, sub_element=None):

    def strip_dirt(key_val):
        #TODO: properly strip HTML encoded characters
        key_val = key_val.replace("\u2039", "<")
        key_val = key_val.replace("\u203a", ">")
        return key_val


    # Scrape all the links from the current webpage and verify
    # it with the provided link dictionary.
    if sub_element is None:
        act_links = self.suiteContext['browser'].webdriver.find_elements_by_tag_name('a')
    else:
        act_links = sub_element.find_elements_by_tag_name('a')
    result = {strip_dirt(lnk.text): lnk.get_attribute('href') for lnk in act_links}
    diff_keys = set(result.keys()) - set(link_dict.keys())
    diff_values = set(result.values()) - set(link_dict.values())
    self.tear_down_hook()
    for l_text, l_url in link_dict.iteritems():
        self.cfg.logger.info("[VALIDATION] Verify Link text [{}] and URL [{}]."
                             .format(l_text, l_url))
    import pdb; pdb.set_trace()

以及在执行代码时

(Pdb) result = {strip_dirt(lnk.text): lnk.get_attribute('href') for lnk in act_links}
*** NameError: global name 'strip_dirt' is not defined
(Pdb) strip_dirt
<function strip_dirt at 0x0651BBB0>
(Pdb) result = {strip_dirt(lnk.text): lnk.get_attribute('href') for lnk in act_links}
*** NameError: global name 'strip_dirt' is not defined
(Pdb) strip_dirt('x')
'x'
(Pdb) {strip_dirt(lnk.text): lnk.get_attribute('href') for lnk in act_links}
*** NameError: global name 'strip_dirt' is not defined

谁能解释为什么字典理解不能访问内部函数strip_dirt,但外部函数的其余部分可以访问?

【问题讨论】:

    标签: python-2.7 dictionary-comprehension


    【解决方案1】:

    我不是pdb 专家,所以如果我错了,请纠正我。

    这是MCVE

    import pdb
    
    def f():
        def g(n): return 2*n
        pdb.set_trace()
    
    f()
    

    现在,pdb,正如预期的那样:

    ipdb> g(5)
    10
    

    但是g 的名字从何而来?

    ipdb> 'g' in globals()
    False
    ipdb> 'g' in locals()
    True
    

    好的,gflocals() 变量中。当你创建一个列表或字典理解时,你有新的locals() 变量:

    ipdb> [locals() for _ in range(1)]
    [{'_': 0, '.0': <range_iterator object at 0x7f1924003d80>}]
    

    因此,在列表/字典理解中,g 既不在 locals() 也不在 globals() 中:

    ipdb> [g(1) for _ in range(1)]
    *** NameError: name 'g' is not defined
    

    现在,最大的问题是:为什么这在正在运行的程序中有效,而不是在 ipdb 中?我希望我有一个解释的开头:

    import pdb
    import inspect
    
    def f():
        def g(n): return 2*n
        print([g(1) for _ in range(1)])
        print([inspect.stack()[1].frame.f_locals for _ in range(1)])
        pdb.set_trace()
    
    f()
    
    # output:
    [2] # it works because...
    [{'g': <function f.<locals>.g at 0x7f1916692488>}] # ...g is in the parent stack frame
    

    ipdb,注意到:

    ipdb> [g(1) for _ in range(1)]
    *** NameError: name 'g' is not defined
    

    但如果你手动从父框架中获取g,它会起作用:

    ipdb> [inspect.stack()[1].frame.f_locals for _ in range(1)]
    [{'g': <function f.<locals>.g at 0x7f1916692488>, '__return__': None}]
    
    ipdb> [inspect.stack()[1].frame.f_locals['g'](1) for _ in range(1)]
    [2]
    

    结论:与正在运行的程序不同,ipdb 似乎无法直接访问存储在父框架中的值。

    请注意,这可能很大程度上取决于 Python 实现。 (我用的是 CPython。)

    【讨论】:

    • 有趣的理论,但对我来说,它似乎在 pdb 中工作:(Pdb) globals() {'f': &lt;function f at 0x05C3CD70&gt;, '__file__': 'dict_poc.py', '__doc__': None, '__name__': '__main__', '__package__': None, 'pdb': &lt;module 'pdb' from 'C:\Python27_32\Lib\pdb.pyc'&gt;, ...} (Pdb) locals() {'__return__': None, 'g': &lt;function g at 0x05C3CDB0&gt;} (Pdb) [locals() for _ in range(1)] [{'__return__': None, '_': 0, 'g': &lt;function g at 0x05C3CDB0&gt;}] (Pdb) [g(1) for _ in range(1)] [2] 但你可能在 dict 理解中重新定义 locals 的正确轨道。
    • @ChukUltima 您是否尝试将(Pdb) result = {strip_dirt(lnk.text): lnk.get_attribute('href') for lnk in act_links} 替换为:(Pdb) result = {lnk.text:locals() for lnk in act_links}(Pdb) result = {lnk.text:globals() for lnk in act_links} 以检查您是否找到strip_dirt
    猜你喜欢
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 2023-03-04
    • 2015-05-18
    • 2020-01-28
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多