2013-02-23 109 views
0

這是一個醜陋的高維護工廠。我真的只需要一種方法來使用字符串實例化一個名稱與字符串匹配的對象。我認爲元類是答案,但我無法弄清楚如何使用它:必須有更好的方法來做到這一點

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) 
+2

也許你希望將標題更改爲「通話功能」按名稱「?也許你可以嘗試谷歌呢? ;) – 2013-02-23 13:14:09

+0

我可能有一個研究失敗,但我可以充滿信心地說,這不是因爲缺乏嘗試。感謝關鍵字提示雖然:) – mnate 2013-02-25 13:34:26

回答

2

你可以看一下全球的名字乾淨調用的代碼塊:

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) 
+0

此解決方案的一個問題:如果'cmd'它不*在'commands'中,它只是返回而不會引發異常。易於修復,但容易錯過。你需要在'fn(commandnode)'之前添加'return'。 – 2013-02-23 14:12:43

+0

的確如此,但最初顯示的代碼也是如此。我不想爲這種情況發明一種行爲。 – 2013-02-23 14:16:28

+0

只需確認:shVersionCmd和shVRFCdm是類(不是函數),沒關係?感謝這一點。我以前沒見過全局變量。 – mnate 2013-02-25 13:29:02

0

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並把功能變成一個無需維護的喜悅。如有疑問,請將其保留並保存在一個地方。

+1

eval很少是一個好主意,並將漏洞引入到您的程序中。 – 2013-02-23 13:38:55

+0

因此,向我們展示*您的*解決方案。 'eval'是一個功能,是的,它可能是危險的。這並不意味着它沒用。你聽起來好像它總是引入漏洞,但事實並非如此,它取決於'commandnode.attrib ['name']'的來源。 – 2013-02-23 13:44:22

+0

不,這不是無用的,但它是一個容易過度使用的大鈍頭錘。 'globals()'在這裏就夠了。 – 2013-02-23 13:47:44

0

我個人的偏好會是轉變工廠和命令實現之間的依賴關係,這樣每個命令都會在工廠註冊。

實現示例:

文件命令/ __ init__.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" 
相關問題