我有一个只包含字段而没有方法的类,如下所示:
class Request(object):
def __init__(self, environ):
self.environ = environ
self.request_method = environ.get('REQUEST_METHOD', None)
self.url_scheme = environ.get('wsgi.url_scheme', None)
self.request_uri = wsgiref.util.request_uri(environ)
self.path = environ.get('PATH_INFO', None)
# ...
这很容易被翻译成字典。该类对于将来的添加更加灵活,并且可以快速使用__slots__
。那么使用dict会有好处吗?一个dict会比一个班级快吗?并且比带有插槽的课程更快?
答案 0 :(得分:36)
除非您需要类的额外机制,否则请使用字典。您还可以使用namedtuple
进行混合方法:
>>> from collections import namedtuple
>>> request = namedtuple("Request", "environ request_method url_scheme")
>>> request
<class '__main__.Request'>
>>> request.environ = "foo"
>>> request.environ
'foo'
这里的性能差异很小,但如果字典不快,我会感到惊讶。
答案 1 :(得分:34)
python 中的一个类是下面的一个词典。你确实得到了类行为的一些开销,但如果没有分析器,你将无法注意到它。在这种情况下,我相信你会从课堂上受益,因为:
答案 2 :(得分:22)
为什么你要把它变成字典呢?有什么好处?如果您以后想要添加一些代码会发生什么?您的__init__
代码会在哪里?
类用于捆绑相关数据(通常是代码)。
字典用于存储键值关系,其中键通常都是相同类型,并且所有值也是一种类型。有时候,当关键/属性名称并非都是预先知道时,它们对于捆绑数据很有用,但通常这表明你的设计出了问题。
保持这个课程。
答案 3 :(得分:19)
我认为每个人的使用对我来说太主观了,所以我只是坚持数字。
我比较了在dict,new_style类和带插槽的new_style类中创建和更改变量所花费的时间。
这是我用来测试它的代码(它有点乱,但是它可以完成这项工作。)
import timeit
class Foo(object):
def __init__(self):
self.foo1 = 'test'
self.foo2 = 'test'
self.foo3 = 'test'
def create_dict():
foo_dict = {}
foo_dict['foo1'] = 'test'
foo_dict['foo2'] = 'test'
foo_dict['foo3'] = 'test'
return foo_dict
class Bar(object):
__slots__ = ['foo1', 'foo2', 'foo3']
def __init__(self):
self.foo1 = 'test'
self.foo2 = 'test'
self.foo3 = 'test'
tmit = timeit.timeit
print 'Creating...\n'
print 'Dict: ' + str(tmit('create_dict()', 'from __main__ import create_dict'))
print 'Class: ' + str(tmit('Foo()', 'from __main__ import Foo'))
print 'Class with slots: ' + str(tmit('Bar()', 'from __main__ import Bar'))
print '\nChanging a variable...\n'
print 'Dict: ' + str((tmit('create_dict()[\'foo3\'] = "Changed"', 'from __main__ import create_dict') - tmit('create_dict()', 'from __main__ import create_dict')))
print 'Class: ' + str((tmit('Foo().foo3 = "Changed"', 'from __main__ import Foo') - tmit('Foo()', 'from __main__ import Foo')))
print 'Class with slots: ' + str((tmit('Bar().foo3 = "Changed"', 'from __main__ import Bar') - tmit('Bar()', 'from __main__ import Bar')))
这是输出......
Dict: 0.817466186345
Class: 1.60829183597
Class_with_slots: 1.28776730003
Dict: 0.0735140918748
Class: 0.111714198313
Class_with_slots: 0.10618612142
所以,如果你只是存储变量,你需要速度,并且它不会要求你做很多计算,我建议使用dict(你总是可以做一个看起来像一个函数的函数方法)。但是,如果你真的需要课程,请记住 - 始终使用 __ 广告位 __ 。
我测试过&#39; Class&#39;使用两个 new_style和old_style类。事实证明,old_style类创建速度更快但修改速度较慢(如果您在紧密循环中创建大量类(注意:您做错了),则不是很多但很重要)。/ p>
创建和更改变量的时间也可能因计算机的不同而有所不同,因为我的计算机已经过时且速度很慢。确保你自己测试一下,看看真实的&#39;结果
我后来测试了namedtuple:我无法修改它但是要创建10000个样本(或类似的东西),花了1.4秒,所以字典确实是最快的。
如果我更改dict函数以包含键和值并在创建它时返回dict而不是包含dict的变量,它会给我 0.65而不是0.8秒。 强>
class Foo(dict):
pass
创建就像一个带槽的类,更改变量的速度最慢(0.17秒),因此不要使用这些类。寻找一个字典(速度)或从对象派生的类(&#39; syntax candy&#39;)
答案 4 :(得分:10)
我同意@adw。我永远不会用字典表示“对象”(在OO意义上)。字典聚合名称/值对。类表示对象。我已经看到了用字典表示对象的代码,并且不清楚事物的实际形状是什么。当某些名称/值不存在时会发生什么?是什么限制了客户完全放入任何东西。或者试图获得任何东西。应始终明确定义物体的形状。
使用Python时,重要的是建立纪律,因为语言允许作者用很多方式射击他/她自己。
答案 5 :(得分:5)
我会推荐一个课程,因为这是与请求有关的各种信息。如果一个人使用字典,我希望存储的数据本质上更相似。我倾向于遵循的一个指导原则是,如果我想循环遍历整个key-&gt;值对并执行某些操作,我会使用字典。否则,数据显然具有比基本键 - >值映射更多的结构,这意味着类可能是更好的选择。
因此,坚持上课。
答案 6 :(得分:3)
也许可以吃蛋糕并吃掉它。换句话说,您可以创建一些提供类和字典实例功能的东西。请参阅ActiveState的Dɪᴄᴛɪᴏɴᴀʀʏ ᴡɪᴛʜ ᴀᴛᴛʀɪʙᴜᴛᴇ-sᴛʏʟᴇ ᴀᴄᴄᴇss 配方以及对此方法的评论。
如果您决定使用常规类而不是子类,我发现Tʜᴇ sɪᴍᴘʟᴇ ʙᴜᴛ ʜᴀɴᴅʏ "ᴄᴏʟʟᴇᴄᴛᴏʀ ᴏғ ᴀ ʙᴜɴᴄʜ ᴏғ ɴᴀᴍᴇᴅ sᴛᴜғғ" ᴄʟᴀss食谱(由Alex Martelli提供)非常灵活且有用的东西看起来你正在做(即创建一个相对简单的信息聚合器)。由于它是一个类,因此您可以通过添加方法轻松扩展其功能。
最后应该注意的是,类成员的名称必须是合法的Python标识符,但字典键不是 - 因此字典会在这方面提供更大的自由度,因为键可以是任何可以清除的东西(甚至不是字符串的东西)
<强>更新强>
一个类object
(没有__dict__
)子类名为SimpleNamespace
(确实有一个)被添加到Python 3.3中,是另一种选择。
答案 7 :(得分:3)
如果你想要获得的所有内容都是obj.bla = 5
而不是obj['bla'] = 5
的语法糖果,特别是如果你必须重复那么多,你可能想要使用一些普通的容器类,如在martineaus建议中。然而,那里的代码相当臃肿,而且不必要地缓慢。你可以保持简单:
class AttrDict(dict):
""" Syntax candy """
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
切换到namedtuple
或具有__slots__
的类的另一个原因可能是内存使用情况。 Dicts需要比列表类型更多的内存,所以这可能需要考虑。
无论如何,在您的具体情况下,似乎没有任何动机可以摆脱当前的实施。您似乎没有维护数百万这些对象,因此不需要列表派生类型。它实际上包含__init__
中的一些功能逻辑,所以你也不应该使用AttrDict
。
答案 8 :(得分:-1)
$a = Get-Date
$fxtDelimiter="----------------------------FXT Daily Status--------------------------------------------"
$fxtData=(Get-Content -tail 2 G:\EmailActivity\Logs\FXTRekon.log) -split ': '
$fxtDownloaded="No of fxt files downloaded for the day"
$fxtFilesDownloaded="$($fxtDownloaded): $($a.ToShortDateString())- $($fxtData[2])"
$symphonyDelimiter="----------------------------Symphony Daily Status--------------------------------------------"
$symphonyData=(Get-Content -tail 5 G:\EmailActivity\Logs\SymphonyRekon.log) -split ': '
$symphonyZipFilesDownloaded="No of symphony zip files downloaded for the day"
$symphonyZipsDownloaded="$($symphonyZipFilesDownloaded): $($a.ToShortDateString())- $($symphonyData[2])"
$symphonySourceFilesProcessed="No of symphony files processed for the day"
$symphonyFilesProcessed="$($symphonySourceFilesProcessed): $($a.ToShortDateString())- $($symphonyData[5])"
$MailBody = $fxtDelimiter+"`n"+$fxtFilesDownloaded +"`n" + "`n" +$symphonyDelimiter+ "`n" +"`n" +$symphonyZipsDownloaded + "`n"+$symphonyFilesProcessed
ConvertTo-Html -Title "DailyStatus" -Body "<center><H2><u> Daily Feeds Report</u></H2></center>" -PostContent $MailBody > G:\EmailActivity\Test.htm
Invoke-Expression G:\EmailActivity\Test.htm