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

时间:2017-07-27 06:51:28

标签: python performance constructor

我构造了我的类来解析一个消息,它是一个字典(可能是从JSON对象派生的),有关详细信息,请参阅pastebin。 因为我会得到很多这样的对象,我不想全部处理它们 我想跳过初始化方法中的一些步骤。所以我写了一个条件初始化类。 我放了一个glance标志,如果激活,将仅处理7个可能成员中的3个。 我希望保留稍后查看参数的选项,因此我还想放一个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()制作的自定义日志记录类,我无论如何多次检查,时间差异似乎稳定)

glance processing took: (glance flag True, opt flag False)
Elapsed time for subprocess: 00:00:01.749

store query, processing took: (glance flag False, opt flag False)
Elapsed time for subprocess: 00:00:00.182

build complete class processing took: (glance flag False, opt flag True
Elapsed time for subprocess: 00:00:01.322

'令人惊讶的是,看了一堂课比其他所有人(?!?!?)花费的时间更长,最快的是将“未处理的消息存储在课堂上”。 有人可以解释一下为什么吗?是因为存储未处理的消息实际上是一个浅拷贝而不是副本?

1 个答案:

答案 0 :(得分:2)

为什么第一次测试需要更长的时间确实超出了我的压力(但是使用负面测试而不是passelse语句,您的代码会更具可读性。)

但为什么它只是存储未经处理的消息"非常明显:它是一个单一的操作(在实例query_msg中存储对__dict__的引用)而不是N次从query_msg获取值并存储实例中__dict__的参考值。

这与深拷贝或浅拷贝无关 - Python从来没有"拷贝"任何明确要求的东西 - 在这两种情况下它只存储对象的引用。

如果query_msgdict并且您的课程主要是它的包装,请注意,您可以从{{1}构建实例__dict__ },即:

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

wrt / your benchmark我使用class CbkQuery(object): def __init__(self, query_msg): self._query_msg = query_msg @property def id(self): return self._query_msg["id"] @property def chat_instance(self): return self._query_msg["chat_instance"] # etc @property def person(self): # here we cache the `Person` instanciation # to avoid repeating it on each and every access if not hasattr(self, "_person"): self._person = Person(self._query_msg["from"]) return self._person # etc 获得了非常不同的结果(使用timeitPerson的模拟实现):

Message

产生以下结果(使用Python 2.7.6和3.4.3):

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")))

2.7.x和3.x之间的细微差别,但这与人们的期望更加一致 - 代码执行的指令越多,所需的时间就越长;)

我肯定认为你的测试中有些东西......