部分构造函数初始化的性能

2024-06-01 00:42:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我构造了我的类来解析一个消息,它是一个字典(可能是从JSON对象派生的),有关更多信息,请参见pastebin。 因为我会得到很多这样的对象,我不想处理它们 我想跳过初始化方法中的一些步骤。所以我写了一个条件初始化类。 我设置了一个glance标志,如果激活,它将只处理7个可能成员中的3个。 我希望tho保留稍后查看参数的选项,因此我还想设置一个opt标志,它将简单地存储消息以供进一步处理。在

class CbkQuery:

    def __init__(self, query_msg, glance = False, opt = True):          
        #required arguments
        self.id = query_msg['id']
        self.person = Person(query_msg['from'])
        self.chat_instance = query_msg['chat_instance']

        if glance:
            pass
        else:
            self.query_msg = query_msg
            if opt:
                # optional arguments
                self.data = self.query_msg.get('data')
                self.message = self.query_msg.get('message')
                if self.message is not None:
                    self.message = Message(self.message)
                self.inline_message_id = self.query_msg.get('inline_message_id')
                self.game_short_name = self.query_msg.get('game_short_name')

现在,由于我为实际获得性能提高而做了这个噱头,我决定记录性能(这是我创建的一个使用perf_counter()的自定义日志类,无论如何,我检查了多次,时间上的差异似乎是稳定的)

^{pr2}$

“那就让另一个班惊喜一下吧!”,最快的是将“未处理的消息”存储在类中。 有人能解释一下为什么吗?是不是因为存储未处理的消息实际上会生成一个浅拷贝而不是一个拷贝?在


Tags: 对象instanceselfid消息messagegetif
1条回答
网友
1楼 · 发布于 2024-06-01 00:42:53

为什么第一个测试需要更长的时间确实超出了我的理解范围(但是如果使用负测试,而不是使用passelse语句,代码的可读性会更好)。在

但是,为什么“存储未处理的消息”最快的原因是显而易见的:这是一个单独的操作(在实例的__dict__中存储对query_msg的引用),而不是N次从query_msg中获取一个值,并在实例的__dict__中存储对该值的引用。在

这与深拷贝或浅拷贝无关——Python从不“拷贝”任何东西,而是明确要求的——在这两种情况下,它只存储对对象的引用。在

另外,如果query_msgdict,而您的类主要是它的包装器,那么您只需从query_msg构建实例的{},即:

def __init__(self, query_msg):
    self.__dict__.update(query_msg)
    self.person = Person(query_msg["from"])
    self.message = Message(self.message)

或者,如果可以将属性访问时间与实例化时间进行交换,只需保留对query_msg的引用并添加属性以访问其值作为属性:

^{pr2}$

wrt/您的基准测试使用timeit(使用PersonMessage的模拟实现)得到非常不同的结果:

class Person(object):
    def __init__(self, data):
        self.data = data

class Message(object):
    def __init__(self, data):
        self.data = data

class CbkQuery(object):
    def __init__(self, query_msg, glance=False, opt=True):          
        self.id = query_msg['id']
        self.person = Person(query_msg['from'])
        self.chat_instance = query_msg['chat_instance']

        if glance:
            pass
        else:
            self.query_msg = query_msg
            if opt:
                self.data = self.query_msg.get('data')
                self.message = self.query_msg.get('message')
                if self.message is not None:
                    self.message = Message(self.message)
                self.inline_message_id = self.query_msg.get('inline_message_id')
                self.game_short_name = self.query_msg.get('game_short_name')


qmsg = {
    "id":"id",
    "from":"test@example.com",
    "chat_instance":"chat_instance",
    "data":"data",
    "message":"message",
    'inline_message_id':'inline_message_id',
    "game_short_name":"game_short_name"
    }


if __name__ == "__main__":
    import timeit

    print("True, False: {}".format(timeit.timeit("CbkQuery(qmsg, True, False)", "from __main__ import CbkQuery, qmsg")))
    print("False, False: {}".format(timeit.timeit("CbkQuery(qmsg, False, False)", "from __main__ import CbkQuery, qmsg")))
    print("False, True: {}".format(timeit.timeit("CbkQuery(qmsg, False, True)", "from __main__ import CbkQuery, qmsg")))

结果如下(使用Python 2.7.6和3.4.3):

^{4}$

2.7.x和3.x之间的差别很小,但这与人们预期的一致得多——代码执行的指令越多,所需的时间就越长;)

我确实认为你的测试出了问题。。。在

相关问题 更多 >