dict理解无法获得内在功能

时间:2018-05-09 07:39:53

标签: python-2.7 dictionary-comprehension

我正在编写一些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不能被字典理解所访问,而是用于外部函数的其余部分吗?

1 个答案:

答案 0 :(得分: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

好的,g位于locals()的{​​{1}}个变量中。创建列表或字典理解时,您有新的f变量:

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] 似乎无法直接访问存储在父框架中的值。

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