Python 必须有更好的方法来做到这一点

Python 必须有更好的方法来做到这一点,python,Python,这是一个丑陋的,高维护的工厂。我真的需要一种方法来使用字符串实例化一个名称与字符串匹配的对象。我认为元类是答案,但我不知道如何应用它: from commands.shVersionCmd import shVersionCmd from commands.shVRFCmd import shVRFCmd def CommandFactory(commandnode): if commandnode.attrib['name'] == 'shVersionCmd': return shV

这是一个丑陋的,高维护的工厂。我真的需要一种方法来使用字符串实例化一个名称与字符串匹配的对象。我认为元类是答案,但我不知道如何应用它:

from commands.shVersionCmd import shVersionCmd
from commands.shVRFCmd import shVRFCmd
def CommandFactory(commandnode):
    if commandnode.attrib['name'] == 'shVersionCmd': return shVersionCmd(commandnode)        
    if commandnode.attrib['name'] == 'shVRFCmd': return shVRFCmd(commandnode)

eval
是你的朋友:

from commands import *
def CommandFactory(commandnode):
    name=commandnode.attrib['name']
    assert name in ( "shVersionCmd", "shVRFCmd" ), "illegal command"
    return eval(name+"."+name)(commandnode)

请注意,如果您确信
name
永远不会包含任何非法命令,则可以删除
assert
,并将该函数变为无维护功能。如有疑问,请将其保留在列表中,并将其保存在一个位置。

此答案讨论了如何基于键干净地调用代码块。

您可以使用
globals()
函数查找全局名称,该函数返回一个dict:

from commands.shVersionCmd import shVersionCmd
from commands.shVRFCmd import shVRFCmd

# An explicit list of allowed commands to prevent malicious activity.
commands = ['shVersionCmd', 'shVRFCmd']

def CommandFactory(commandnode):
    cmd = commandnode.attrib['name']
    if cmd in commands:
        fn = globals()[cmd]
        fn(commandnode)

我个人的偏好是将工厂和命令实现之间的依赖关系转换过来,以便每个命令都向工厂注册

实施示例:

文件命令/\uuuu init\uuuuu.py:

import pkgutil
import commands

_commands = {}

def command(commandCls):
    _commands[commandCls.__name__] = commandCls
    return commandCls

def CommandFactory(commandnode):
    name = commandnode.attrib['name']
    if name in _commands.keys():
        return _commands[name](commandnode)

# Load all commands
for loader, module_name, is_pkg in  pkgutil.walk_packages(commands.__path__):
    if module_name!=__name__:
        module = loader.find_module(module_name).load_module(module_name)
文件命令/mycommand.py:

from commands import command

@command
class MyCommand(object):    
    def __init__(self, commandnode):
        pass
小型测试:

from commands import CommandFactory

# Stub node implementation
class Node(object):
    def __init__(self, name):
        self.attrib = { "name": name }

if __name__=='__main__':
    cmd = CommandFactory(Node("MyCommand"))
    assert cmd.__class__.__name__=="MyCommand", "New command is instance of MyCommand"
    cmd = CommandFactory(Node("UnknownCommand"))
    assert cmd is None, "Returns None for unknown command type"

也许您想将标题改为“按名称调用函数”?也许你可以尝试用谷歌搜索一下这个我可能有一次研究失败,但我可以自信地说,这不是因为缺乏尝试。谢谢你的关键词提示:)eval很少是个好主意,它会在你的程序中引入漏洞。所以,给我们看看你的解决方案<代码>评估是一项功能,是的,它可能很危险。这并不意味着它是无用的。听起来好像它总是会引入漏洞,但事实并非如此,它取决于
commandnode.attrib['name']
的来源。不,它不是无用的,但它是一个容易过度使用的大钝锤
globals()
在这里就足够了。这个解决方案的一个问题是:如果
cmd
不在
命令中,它只返回而不引发异常。容易修复,但同样容易丢失。您需要在
fn(commandnode)
之前添加一个
return
。我不想为这种情况发明一种行为。只是确认一下:shVersionCmd和shVRFCdm是类(不是函数)并不重要,对吗?谢谢你。我以前没见过使用globals。