加载一个充满解码器模块的目录

时间:2015-03-18 03:24:00

标签: python class classloader

[TL; DR]感谢Alexi - 我有一个工作解决方案

我试图弄清楚Python类和继承,以便我可以创建一个协议解码器包。

包需要按如下方式工作:

  • 我得到一个充满数据文件的目录。
  • 我的python代码检查每个文件,并确定协议ID号。
  • 根据protocol_id,我可以计算(是,计算)特定解码器的文件名。
  • 如果解码器文件名不存在,我选择一些默认名称
  • 这里需要帮助:我在变量中有文件名如何加载它?

我之前在C代码中完成了这项工作,使用共享对象,我尝试使用python创建类似的东西。

第1部分伪代码是这样的:

def GetDecoderViaId( idnumber ):
    filename = "all_decoders/protocol_%04x.py" % idnumber

    # Pseudo code use default if special is not found
    if (! os.access(filename,os.R_OK)):
        filename = "all_decoders/protocol_DEFAULT.py"

    # Question #1 How do I do this
    # Where each "filename" is a python class.
    theclass = import_by_filename( filename )
    return theclass

第2部分 - 解码器需要来自一个公共基类。我已经完成了简单的课程,但是当我尝试使用我通过谷歌找到的各种技术加载它们时,什么不起作用。我可以加载一些东西,我似乎无法调用解码器。

问题#2我该怎么做?

My Decoder Base Class如下所示:

 # Simple base class
 def DecoderBase(object):
    def __init__(id,name,compatlist):
       self.id = id
       self.name = name
       self.compatiblelist = compatlist

    def Decode( bytes, byte0, byteN ):
       """ Default is just a hex dump """
       HexDump( bytes, byte0, byteN )

    def GetName(self):
      return self.name

    def GetId(self):
       return self.id

    def IsCompatible(id):
       return id in self.compatiblelist

以下是两个示例派生类,它们将位于单独的文件中。

# example: "all_decoders/protocol_1234.py"
class DogDecoder( DecoderBase ):
    def __init__():
        # pass important things to base constructor
        super( DecoderBase, self ).__init__("dog","Snoopy", ["beagle", "peanuts" ])

    def Decode( self, byte0, byteN ):
        Snoopy specific code goes here

# Example: "all_decoders/protocol_4321.py"
class CatDecoder( DecoderBase ):
    def __init__():
        # pass important things to base constructor
        super( DecoderBase, self ).__init__("cat","Garfield", ["fat-cat", "cartoon-cat" ])

    def Decode( self, byte0, byteN ):
        Garfield specific code goes here

有人能指出一些如何(1)如上所述加载模块的例子,(2)它们需要是派生类,(3)我如何称呼这些东西?

[注意:有些编辑,点击提交后注意到错别字]

2 个答案:

答案 0 :(得分:2)

  1. 要根据路径导入模块,请参阅https://docs.python.org/2/library/importlib.html
  2. 然而

    1a. a module's path is not ``foo/bar.py'`: it's `foo.bar`.  So:
          1aX first, drop the trailing `.py`
          1aY then, change slashes into dots
        both before passing the resulting string to 
       `importlib.import_module`
    
    1b. when you import this way, you get a **module**, **not** a class!
        I recommend you just name each class `Decoder` within its module
        so you can just access it that way
    
    1c. to make directory `foo` into a Python package, the directory
        **must** contain a file `__init__.py` (which can be empty).
    

    不需要从同一个基类派生每个Decoder类;如果您想要它,为了您的方便,将基类放在例如foo/base.py中,让每个特定的解码器模块以import .base开头,并派生每个Decoder类来自base.DecoderBase

    所以你的代码应该是这样的:

    import importlib
    
    def GetDecoderViaId( idnumber ):
        filename = "all_decoders/protocol_%04x.py" % idnumber
    
        # Pseudo code use default if special is not found
        if (!os.access(filename, os.R_OK)):
            filename = "all_decoders/protocol_DEFAULT.py"
    
        module_path = filename[:-3].replace('/', '.')
        themodule = importlib.import_module(module_path)
        theclass = themodule.Decoder
        return theclass
    

    请记得有一个空的all_decoders/__init__.pyall_decoders.base.py定义class DecoderBase,例如

    # in file: "all_decoders/protocol_1234.py"
    import .base
    class Decoder( base.DecoderBase ):
        def __init__():
            # pass important things to base constructor
            super( DecoderBase, self ).__init__("dog","Snoopy", ["beagle", "peanuts" ]
    
        def Decode( self, byte0, byteN ):
            Snoopy specific code goes here
    
    # in file: "all_decoders/protocol_4321.py"
    import .base
    class Decoder( DecoderBase ):
        def __init__():
            # pass important things to base constructor
            super( DecoderBase, self ).__init__("cat","Garfield", ["fat-cat", "cartoon-cat" ]
    
        def Decode( self, byte0, byteN ):
            Garfield specific code goes here
    

    “如何调用”现在是微不足道的,例如在与GetDecoderViaId相同的Python模块中...:

    theclass = GetDecoderViaId(theid)
    aninstance = theclass(whatever, init, args, are, needed)
    decoded = aninstance.Decode(byte0, byteN)
    

答案 1 :(得分:0)

工作解决方案:Grazie非常Alexi

文件1:example / test.py

import importlib

def GetDecoder(name,xtra):
    theclass = importlib.import_module( 'Decoders.' + name )
    return theclass.Decoder(xtra)

sh = GetDecoder('snoopy', 'hockey');
sp = GetDecoder('snoopy', 'pilot');
g = GetDecoder('garfield', None );

print( "Snoopy Hocky says: %s" % sh.Decode( 3, 4 ) )
# This has an extra method
sh.Bark()

print( "SnoopyPilot says: %s" % sp.Decode( 5, 9 ) )
# And so does this one
sh.Bark()

print("Garfield says: %s " % g.Decode( 1,3 ))
# A different method
g.Purr()

文件2:示例/解码器/ init .py

#
# This file is empty
#

文件3:example / Decoders / base.py

class DecoderBase(object):
    def __init__( self, n, idval ):
         self.name = n
         self.idcode = idval
         print( "Base created: %s %d " % (self.name, self.idcode));

    def GetName(self):
        return self.name

    def GetId(self):
        return self.idcode

    def Decode(self,b0,bn):
        msg = ("Decode from byte %d to %d" % (b0, bn ))
        return msg

文件4:example / Decoders / snoopy.py

from base import DecoderBase

class Decoder( DecoderBase ):
    def __init__( self, varient ):
        self.costume = varient
        super( Decoder, self ).__init__( "Snoopy-" + varient, 0x444f47 );

    # Override the decoder
    def Decode( self, b0, b1 ):
        # but only if snoopy is playing hockey
        if self.costume == 'hockey':
            return ("Hockey decode: %d to %d" % (b0, b1))
        else:
            return super(Decoder,self).Decode( b0, b1 )

    def Bark(self):
        print "Barking(%s) ..." % self.costume 

文件5:example / Decoders / garfield.py

from  base import DecoderBase

class Decoder( DecoderBase ):
    def __init__(self, varient ):
        # Unlike snoopy decoder, garfield does not have any varients
        super( Decoder, self ).__init__( "Garfield", 0x434154 );

    # Override the decoder
    def Decode( self, b0, b1 ):
        return ("Garfield lasagna %d to %d" % (b0, b1))

    def Purr( self ):
        print "Purring like a cat.."

<强> END