代码之家  ›  专栏  ›  技术社区  ›  Nicholas Knight

子类查找

  •  0
  • Nicholas Knight  · 技术社区  · 16 年前

    我有一个类(我们称之为“Packet”),它作为一组子类的父类,这些子类表示遗留客户机-服务器协议中几十种数据包类型中的每一种,而我对此没有控制权(这些数据包的行为常常大不相同,所以我只是给它们各自上了课,让我的生活更轻松。)

    在接收数据包时,我将使用一个简单的“dispatch”函数检查数据包头以确定类型,然后将其交给知道如何处理它的类。

    不 想要手工维护查找表——这很不雅观,只是自找麻烦。相反,我希望在运行时通过检查数据包的所有子类来构建该表,这些子类将具有类变量,指定它们对应的数据包类型,例如:

    class Login(Packet):
        type_id = 0x01
    

    我想,当然,关于迭代 object.__subclasses__() ,但我发现,对于将它用于此类事情的安全性和适当性,存在着一些不同的观点,包括它是特定于实现的,可能在CPython以外的地方不起作用,并且它可能在将来从CPython中消失。我是不是太偏执了?子类现在被认为是语言的“真实”部分吗?

    4 回复  |  直到 16 年前
        1
  •  3
  •   Alex Martelli    16 年前

    __subclasses__ 是Python语言的一部分,由IronPython和Jython以及CPython实现(目前没有pypy可供测试,但如果他们打破了这一点,我会感到惊讶!)。是什么给你的印象是 __子类__ 不是Python语言的关键部分?!

        2
  •  3
  •   S.Lott    16 年前

    这肯定会导致无休止的问题。这种情况对您的子类施加了奇怪的约束。不能使用任何抽象超类来简化事情。

    class MessagePacket( object ):
        """superclass.  Ignore me, I'm abstract."""
    class Type_01( MessagePacket ):
        type_id = 0x01
    class Type_023( MessagePacket ):
        """superclass with common features for type 2 and 3.  Ignore me, I'm abstract."""
    class Type_02( Type_023 ):
        type_id = 0x02
    class Type_03( Type_023 ):
        type_id = 0x03
    class Type_04( MessagePacket ):
        """superclass for subtypes of 4.  Ignore me, I'm abstract."""
        type_id = 0x04
    class Type_04A( Type_04 ):
        discriminator = lambda x: x[23] == 'a' or x[35] == 42
    class Type_04B( Type_04 ):
        discriminator = lambda x: True
    

    这应该足以表明“自动发现”从一开始就注定要失败。

    工厂

    class Factory( object ):
        def __init__( self, *subclass_list ):
            self.subclass = dict( (s.type_id,s) for s in subclass_list )
        def parse( self, packet ):
            if packet.type_id == 04:
                # special subclass logic
            return self.subclass[packet.type_id]( packet )
    

    包括以下内容似乎不是一个沉重的负担:

    factory= Factory( Subclass1, Subclass2, ... SubclassN )
    

    当您添加子类时,添加到 事实上 正在使用中。

        3
  •  2
  •   John La Rooy    16 年前
    
    >>> class PacketMeta(type):
    ...     def __init__(self,*args,**kw):
    ...         if self.type_id is not None:
    ...             self.subclasses[self.type_id]=self
    ...         return type.__init__(self,*args,**kw)
    ... 
    >>> class Packet(object):
    ...     __metaclass__=PacketMeta
    ...     subclasses={}
    ...     type_id = None
    ... 
    >>> class Login(Packet):
    ...     type_id = 0x01
    ... 
    >>> class Logout(Packet):
    ...     type_id = 0x02
    ... 
    >>> 
    >>> Packet.subclasses
    {1: <class '__main__.Login'>, 2: <class '__main__.Logout'>}
    >>> 
    

    __subclasses__() 你可以这样做

    >>> class Packet(object):
    ...     pass
    ... 
    >>> class Login(Packet):
    ...     type_id = 0x01
    ... 
    >>> class Logout(Packet):
    ...     type_id = 0x02
    ... 
    def packetfactory(packet_id):
        for x in Packet.__subclasses__():
            if x.type_id==packet_id:
                return x
    ... 
    >>> packetfactory(0x01)
    <class '__main__.Login'>
    >>> packetfactory(0x02)
    <class '__main__.Logout'>
    
        4
  •  1
  •   Andrey Vlasovskikh    16 年前

    我想您可以使用Python元类(Python2.2)在类之间共享这样的信息,这将是非常类似Python的。看看谷歌的 Protocol Buffers . 这是 the tutorial 在工作中显示元类。顺便说一下,协议缓冲区的域与您的类似。