有效地内省Python对象IP地址实例所有权

时间:2011-11-20 02:05:16

标签: object python introspection

在下面的代码中,我试图找到一种方法来消除self.owner类中的L3Address() ...我的想法是,我想知道谁在给定的Vlan上拥有IP地址或接口,而无需明确地将其调出。

是否有更好的方法来获取IPv4地址的所有者(可能通过内省)?

import ipaddr

class SomethingOwned(object):
    def __init__(self, owner=None):
        self._owner = owner
        # Build self.owner (the object instance that owns the subclass object)
        self._create_owner()

    def _create_owner(self):
        """
        create self.owner and ensure the subclass was called correctly
        """
        if not (self._owner is None):
            self.owner = self._owner
        else:
            raise ValueError, "%s() must be called with an 'owner' arg, which cannot be None" % self.__class__.__name__

class L3Address(SomethingOwned):
    """
    A Layer3 IP PDU address that has an owning object
    """
    def __init__(self, version=None, owner=None, addr=None, masklen=None):
        # Call SomethingOwned.__init__(owner=owner) to add an owner attribute
        super(L3Address, self).__init__(owner=owner)
        self._addr = addr
        self._masklen = masklen
        self._version = version

        # Build self._obj
        self._create_ip_object()

        self.addr = self._obj.ip
        self.netmask = self._obj.netmask
        self.masklen = self._obj.prefixlen

    def __repr__(self):
        return "<IPv%i %s/%s>" % (self._version, self.addr, self.masklen)


    def _create_ip_object(self):
        """
        create self._obj and ensure the subclass was called with the correct version
        """
        if self._version==4:
            if (self._masklen is None):
                self._obj = ipaddr.IPv4Network(self._addr)
            else:
                self._obj = ipaddr.IPv4Network("%s/%s" % (self._addr, self._masklen))
        elif version==6:
            if (self._masklen is None):
                self._obj = ipaddr.IPv6Network(self._addr)
            else:
                self._obj = ipaddr.IPv6Network("%s/%s" % (self._addr, self._masklen))
        else:
            raise ValueError, "Version must be 4 or 6"


class IPv4(L3Address):
    def __init__(self, **kwargs):
        ## Initialize the IPv4 network object instance
        # Call L3Protocol.__init__(version=4 **kwargs)
        super(IPv4, self).__init__(version=4, **kwargs)

class IPv6(L3Address):
    def __init__(self, **kwargs):
        ## Initialize the IPv6 network object instance
        # Call L3Protocol.__init__(version=6 **kwargs)
        super(IPv4, self).__init__(version=6, **kwargs)

class Vlan(object):
    def __init__(self, name=None, id=None, ipv4=None):
        self.id = id
        self.name = name
        if not (ipv4 is None):
            ### NOTE: I am trying to eliminate the need for the owner arg here
            self.ipv4 = IPv4(owner=self, addr=ipv4)
    def __repr__(self):
        return "Vlan %s (name: %s)" % (self.id, self.name)

class Interface(object):
    def __init__(self, id=None, ipv4=None):
        self.id = id
        self.ipv4 = None
        if not (ipv4 is None):
            ### NOTE: I am trying to eliminate the need for the owner arg here
            self.ipv4 = IPv4(owner=self, addr=ipv4)
    def __repr__(self):
        return "Interface %s" % self.id



if __name__=='__main__':
    def find_owner(ip_instance):
        print "Owner of '%s' is '%s'" % (ip_instance, ip_instance.owner)

    find_owner(Interface(id='ge-0/0/0', ipv4='1.1.1.1').ipv4)
    find_owner(Vlan(id='25', name='accounting', ipv4='1.1.1.2/25').ipv4)

执行结果

[mpenning@hotcoffee ~]$ python cisco.py 
Owner of <IPv4 1.1.1.1/32> is 'Interface ge-0/0/0'
Owner of <IPv4 1.1.1.2/25> is 'Vlan 25 (name: accounting)'
[mpenning@hotcoffee ~]$

2 个答案:

答案 0 :(得分:4)

使用所有者的当前方法可能是最干净的解决方案。

话虽如此,如果您需要找出谁拥有IP地址,那么gc.get_referrers()可能会有所帮助。

答案 1 :(得分:2)

无法从owner中删除L3Protocol字段,只是在运行时神奇地确定它。你基本上要问的是“哪个对象引用了这个?”。在一般情况下,当然甚至没有意义,因为可能有任意数量的对象包含对L3Protocol实例的引用(并且它们中的每一个甚至可以包含对{{1}的任意数量的引用实例)。

因此,要么您必须以某种方式记录每个L3Protocol的所有者,要么您只需要在上下文中请求L3Protocol的所有者哪些信息更多;从理论上讲,L3Protocol可以是一个函数,它会占用owner和一群潜在的所有者,并返回拥有L3Protocol(或L3Protocol)的所有者。如果您有一个记录所有NoneInterface的对象,那么将其作为该对象的方法就可以了。

但看起来你正在这样做的方式几乎是我能想到的最直接的方式,只要你确保你保持双向链接(所有者 - &gt;拥有和拥有 - &gt ;所有者)如果他们改变了一致。