Python对象的__new__和__init__

需求

给一个类,生成该类对象时会传一些参数,若这些满足参数的对象已经存在,则直接返回已有对象,否则构造新对象。

解决

import copy
import time

class ObjID():
    insn_node_details = {}

class OriInsnNode(object):  
    def __init__(self, ea, mnem, byte_data, prev_insn_node, flags, layer=0):
        print '__init'
        self.ea = ea
        self.insn_data = byte_data 
        self.layer = layer
        self.mnem = mnem
        self.len = len(byte_data)
        self.prev_insn_node = prev_insn_node
        self.next_insn_node = None
        self.flags = flags
        self.is_call = False 
        self.xref = []
        self.hash = 0
        self.is_useless = False
        if ea not in ObjID.insn_node_details:
            ObjID.insn_node_details[ea] = []
        ObjID.insn_node_details[ea].append(self)

    def set_type(self,type1):
        self.type = type1      

class InsnNode(OriInsnNode):
    flag = False
    def __new__(cls, ea, mnem, byte_data, prev_insn_node, flags, layer=0):
        print '__new___'
        if ea in ObjID.insn_node_details:
            for insn_node in ObjID.insn_node_details[ea]:
                if insn_node.ea== ea and insn_node.mnem==mnem and insn_node.flags==flags and insn_node.prev_insn_node==prev_insn_node and insn_node.insn_data==byte_data:
                    print ('use existing insn_node %x' % insn_node.ea)
                    return insn_node
        else:
            InsnNode.flag = True
            return super(InsnNode, cls).__new__(cls, ea, mnem, byte_data, prev_insn_node, flags, layer)

    def __init__(self, ea, mnem, byte_data, prev_insn_node, flags, layer=0):
        print '__init___'
        if InsnNode.flag:
            InsnNode.flag = False
            super(InsnNode, self).__init__(ea, mnem, byte_data, prev_insn_node, flags, layer)

    def __copy__(self):
        return self

    def __deepcopy__(self, memo):
        return self


x = InsnNode(0x401091, 'jmp' , '435434', None, 0, 0)
y = InsnNode(0x401091, 'jmp' , '435434', None, 0, 0) 
print y
print '-------------'
time.sleep(1)
copy.deepcopy(x)

首先,需要有一个存已知对象的地方,这里用ObjID的类成员insn_node_details保存。

之后,需要在构造对象前检查是否有已知对象存在。这里需要了解python的内置函数__new__和__init__。

构造新对象时,首先要调用__new__,之后才会调用__init__。类似于在new是分配空间的,init是把内容填到空间中,当然这个理解并不准确、

由于多继承条件下,并不知道new’里面的super怎么写,因为继承了好几个啊,这个super到底是哪个呢,我觉得python解释器应该也不知道,并没有做实验测试,直接定义了一个子类,就是代码里的InsnNode,在__new__里判断目标对象是不是已经存在了,dict的value是list的原因是一个地址上可能存在多条指令,所以有了判断逻辑,如果存在直接返回insn_node,如果不存在,则构造新对象,调用OriInsnNode的__new__方法。因为InsnNode的__new__之后还会调用__init__,所以需要一个变量来控制到底init还要不要执行,所以用了flag,并保证flag一直是False。当需要构造新对象时,调用OriInsnNode的__init__方法。

本以为就结束了,然而发现使用copy.deepcopy来copy InsnNode类的对象时会出错,为啥?因为deepcopy不知道该给new哪些参数。于是做了一个特别简陋的copy和deepcopy,其实就是重载了内建方法,特别是deepcopy,这种实现在大多数场景下是错的,实际应该return一个新构造的对象(因为我们知道要传哪些参数),但是我的需求这样就够了。so much。

下面是上述代码的运行结果。

__new___
__init___
__init
__new___
use existing insn_node 401091
__init___
<__main__.InsnNode object at 0x025D35D0>
-------------
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值