【问题标题】:Python: How do you call a method when you only have the string name of the method?Python:只有方法的字符串名称时,如何调用方法?
【发布时间】:2011-01-13 06:59:02
【问题描述】:

这是用于 JSON API。 我不想拥有:

if method_str == 'method_1':
    method_1()

if method_str == 'method_2':
    method_2()

由于显而易见的原因,这不是最佳选择。我将如何以可重用的方式将映射字符串用于此类方法(另请注意,我需要将参数传递给被调用的函数)。

这是一个例子:

传入的 JSON:

{
    'method': 'say_something',
    'args': [
        135487,
        'a_465cc1'
    ]
    'kwargs': {
        'message': 'Hello World',
        'volume': 'Loud'
    }
}

# JSON would be turned into Python with Python's built in json module.

结果调用:

# Either this
say_something(135487, 'a_465cc1', message='Hello World', volume='Loud')

# Or this (this is more preferable of course)
say_something(*args, **kwargs)

【问题讨论】:

  • 如果不是在 API 中使用,为什么会提到传入的 JSON 并在 JSON 对象中指定方法名称?你认为这样我就可以在我的 Python 代码中构建一个 JSON 字符串,然后将它传递给调用方法吗?
  • 动态调用它会给你带来注入问题。

标签: python json api serialization


【解决方案1】:

假设函数都是全局变量(除非它们是在另一个函数中定义的),它们可以通过globals() 函数访问。 globals() 返回所有全局变量的字典,包括函数。

例如:

$ python
Python 2.6.2 (r262:71600, Apr 16 2009, 09:17:39) 
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def some_function():
...     print "Hello World!"
... 
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'some_function': <function some_function at 0x6326b0>, '__package__': None}
>>> globals()['some_function']()
Hello World!

【讨论】:

  • 对于给定的示例,这可能非常不安全 - 不能保证 INCOMING_JSON 来自友好的来源。要么合并函数白名单,要么使用 Mike 的解决方案。
【解决方案2】:

对于实例方法,使用getattr

>>> class MyClass(object):
...  def sayhello(self):
...   print "Hello World!"
... 
>>> m=MyClass()
>>> getattr(m,"sayhello")()
Hello World!
>>> 

对于你可以在全局字典中查找的函数

>>> def sayhello():
...  print "Hello World!"
... 
>>> globals().get("sayhello")()
Hello World!

在这种情况下,由于没有名为 prove_riemann_hypothesis 的函数,因此使用默认函数 (sayhello)

>>> globals().get("prove_riemann_hypothesis", sayhello)()
Hello World!

这种方法的问题是您正在与其中的任何其他内容共享名称空间。您可能想要防范不应该使用的 json 调用方法。这样做的一个好方法是像这样装饰你的函数

>>> json_functions={}
>>> def make_available_to_json(f):
...  json_functions[f.__name__]=f
...  return f
...
>>> @make_available_to_json
... def sayhello():
...  print "Hello World!"
...
>>> json_functions.get("sayhello")()
Hello World!
>>> json_functions["sayhello"]()
Hello World!
>>> json_functions.get("prove_riemann_hypothesis", sayhello)()
Hello World!

【讨论】:

  • 您的最终解决方案似乎是神奇地调用该函数。不应该是json_functions.get("sayhello")() 还是更好的json_functions.get["sayhello"]()?这是来自实际的口译会话吗?
  • @gnibbler,为什么仍然更喜欢get 方法而不是[]?后者是自然语法,如果 "sayhello" 无效,则会引发更有意义的异常。
  • @Mike,我发现我使用 get 的频率更高,因为我想提供默认参数。如果您的用例倾向于例外,请务必使用[]
  • @gnibbler,你的也会引发一个异常,只是一个比正常方法有用得多。
  • @Mike,是的,在这种情况下,当没有提供默认函数时,尝试调用 None 确实很愚蠢
【解决方案3】:

使用 getattr。 例如:

class Test(object):
    def say_hello(self):
        print 'Hell no, world!!111'
    def test(self):
        getattr(self, 'say_hello')()

【讨论】:

  • {'method': '__init__',...怎么样
【解决方案4】:

干净、安全的方法是创建一个将名称映射到函数的字典。如果这些实际上是方法,最好的方法仍然是制作这样的字典,尽管getattr 也可用。使用globalseval 是不安全和肮脏的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 2010-09-14
    • 2023-03-15
    相关资源
    最近更新 更多