一个函数,它创建以

时间:2016-09-05 01:00:07

标签: python xml automated-tests

有没有办法创建一个函数,使得稍后以传入的变量命名的其他函数被调用?

这个示例让我们假装https://example.com/engine_list返回此xml文件,当我在get_search_engine_xml中调用它时

<engines>
    <engine address="https://www.google.com/">Google</engine>
    <engine address="https://www.bing.com/">Bing</engine>
    <engine address="https://duckduckgo.com/">DuckDuckGo</engine>
</engines>

这是我的代码:

import re
import requests
import xml.etree.ElementTree as ET
base_url = 'https://example.com'

def make_safe(s):
    s = re.sub(r"[^\w\s]", '', s)
    s = re.sub(r"\s+", '_', s)
    s = str(s)
    return s

# This is what I'm trying to figure out how to do correctly, create a function
# named after the engine returned in get_search_engine_xml(), to be called later
def create_get_engine_function(function_name, address):
    def function_name():
        r = requests.get(address)
    return function_name

def get_search_engine_xml():
    url = base_url + '/engine_list'
    r = requests.get(url)
    engines_list = str(r.content)
    engines_root = ET.fromstring(engines_list)
    for child in engines_root:
        engine_name = child.text.lower()
        engine_name = make_safe(engine_name)
        engine_address = child.attrib['address']
        create_get_engine_function(engine_name, engine_address)

## Runs without error.
get_search_engine_xml()

## But if I try to call one of the functions.
google()

我收到以下错误。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'google' is not defined

当我将其注销时,定义engine_name和engine_address似乎正在工作。所以我很确定问题在于create_get_engine_function,我承认我不知道自己在做什么,而且我试图从类似的问题拼凑起来。

您是否可以使用传入的参数命名由另一个函数创建的函数?有更好的方法吗?

1 个答案:

答案 0 :(得分:2)

您可以将它们分配到globals()

def create_get_engine_function(function_name, address):
    def function():
        r = requests.get(address)

    function.__name__ = function_name
    function.__qualname__ = function_name  # for Python 3.3+ 
    globals()[function_name] = function

虽然,根据您实际想要完成的任务,更好的设计是将所有引擎名称/地址存储在字典中并根据需要访问它们:

# You should probably should rename this to 'parse_engines_from_xml'
def get_search_engine_xml(): 
    ...
    search_engines = {} # maps names to addresses
    for child in engines_root:
        ...
        search_engines[engine_name] = engine_address
    return search_engines

engines = get_search_engine_xml()

e = requests.get(engines['google'])
<do whatever>
e = requests.get(engines['bing'])
<do whatever>