我构造了我的类来解析一个消息,它是一个字典(可能是从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
'令人惊讶的是,看了一堂课比其他所有人(?!?!?)花费的时间更长,最快的是将“未处理的消息存储在课堂上”。 有人可以解释一下为什么吗?是因为存储未处理的消息实际上是一个浅拷贝而不是副本?
答案 0 :(得分:2)
为什么第一次测试需要更长的时间确实超出了我的压力(但是使用负面测试而不是pass
和else
语句,您的代码会更具可读性。)
但为什么它只是存储未经处理的消息"非常明显:它是一个单一的操作(在实例query_msg
中存储对__dict__
的引用)而不是N次从query_msg
获取值并存储实例中__dict__
的参考值。
这与深拷贝或浅拷贝无关 - Python从来没有"拷贝"任何明确要求的东西 - 在这两种情况下它只存储对象的引用。
如果query_msg
是dict
并且您的课程主要是它的包装,请注意,您可以从{{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
获得了非常不同的结果(使用timeit
和Person
的模拟实现):
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之间的细微差别,但这与人们的期望更加一致 - 代码执行的指令越多,所需的时间就越长;)
我肯定认为你的测试中有些东西......