我对python很新,所以如果这个问题听起来很愚蠢我会道歉。这不仅仅是普通的好奇心,我必须使用具有类似类的代码。
考虑以下python代码片段:
class _Base(object):
constant1 = 1
constant2 = 2
constant3 = 3
def main():
a = _Base # Referencing a class
b = _Base() # Instantiating
if __name__ == '__main__':
main()
在这个特定示例中,当_Base类没有__init__()
方法时,与b
相比,使用a
方法是否有任何缺点,性能方面或其他方面?< / p>
答案 0 :(得分:4)
通常将常量放在模块中而不是类中。如果你需要将它们用于子类,那么继承Base并使用它们,否则,不要实例化class
,因为你只是将它用作一种“命名空间”。
将其命名为优于_Base
并将变量视为(例如:) MyConstants.constant1
而不是......
答案 1 :(得分:3)
Jon Clements给出了如何做到这一点的答案。
但要回答你的实际问题:
与p 相比,使用b方法是否有任何缺点,性能方面或其他方面
比性能更重要的是可读性。如果你实例化一个对象,读者会认为你已经出于某种原因这样做了,并且试图找出正在使用b
的内容以及_Base
实例在你的对象中代表的内容模型等。要弄清楚它是没用的,不会花太长时间,但“显而易见”总是好于“不会花太长时间才弄明白”。
但也存在性能下降。在您编写的任何程序中,它很可能永远不会以任何可测量的方式发生,但它就在那里。
首先,b
是一个新分配的对象,需要几个字节(可能是几十个),而a
只是已存在对象的新名称(类本身) 。所以,它浪费了记忆。
其次,构建b
需要一些时间。除了分配内存外,您还必须拨打__new__
上的__init__
和object
位置。
您可以使用timeit
测试自己的性能差异,但我不会打扰。你很可能会发现b
比a
或类似的东西慢20倍,但是你每次运行一次,在一微秒内完成一次20:1的改进仍然没有意义
答案 2 :(得分:0)
@Jon Clements的答案非常好,但如果你愿意,你可以继续使用该类,但将所有常量转换为静态方法。
class MyConstants(object):
@staticmethod
def constant1():
return 1
然后你可以打电话给它:
some_variable = MyConstants.constant1()
我认为处理这样的事情在可维护性方面更好 - 如果你想做除了返回常量以外的任何事情,Jon的解决方案将不起作用,你将不得不重构你的代码。例如,您可能希望在某个时刻更改constant1
的定义:
def constant1():
import time
import math
current_time = time.time()
return math.ceil(current_time)
将当前时间返回到最接近的秒。
无论如何,对于这篇文章感到抱歉:)
所以,鉴于这里的评论,我认为我会看到实际开销是什么(使用工厂)而不是声明静态常量与使用类中的属性。
time_test.py
:
import time
CONSTANT_1 = 1000
CONSTANT_2 = 54
CONSTANT_3 = 42
CONSTANT_4 = 3.14
class Constants(object):
constant_1 = 1000
constant_2 = 54
constant_3 = 42
constant_4 = 3.14
class Factory(object):
@staticmethod
def constant_1():
return 1000
@staticmethod
def constant_2():
return 54
@staticmethod
def constant_3():
return 42
@staticmethod
def constant_4():
return 3.14
if __name__ == '__main__':
loops = 10000000
# static const
start = time.time()
for i in range(loops):
sum = CONSTANT_1
sum += CONSTANT_2
sum += CONSTANT_3
sum += CONSTANT_4
static_const_time = time.time() - start
# as attributes
start = time.time()
for i in range(loops):
sum = Constants.constant_1
sum += Constants.constant_2
sum += Constants.constant_3
sum += Constants.constant_4
attributes_time = time.time() - start
# Factory
start = time.time()
for i in range(loops):
sum = Factory.constant_1()
sum += Factory.constant_2()
sum += Factory.constant_3()
sum += Factory.constant_4()
factory_time = time.time() - start
print static_const_time / loops
print attributes_time / loops
print factory_time / loops
import pdb
pdb.set_trace()
结果:
Bens-MacBook-Pro:~ ben$ python time_test.py
4.64897489548e-07
7.57454514503e-07
1.09821901321e-06
--Return--
> /Users/ben/time_test.py(71)<module>()->None
-> pdb.set_trace()
(Pdb)
所以你有它:效率的边际收益(每千万个循环几秒钟),可能会被代码中其他地方的东西所淹没。所以我们已经确定所有三种解决方案都具有相似的性能,除非你关心这样的微优化。 (如果是这种情况,你可能最好在C中工作。)所有这三种解决方案都是可读的,可维护的,并且可能在任何使用Python的软件公司的版本控制中都可以找到。所以区别在于美学。
无论如何,由于我的参考书目格式不正确,我曾在高中的研究论文中丢失了15%的积分。内容完美无瑕,对我的老师来说还不够。我发现人们可以花时间学习规则或解决问题。我更喜欢解决问题。
答案 3 :(得分:0)
我说要注意将来的维护,并将类设置为具有所有@property
方法,因为它们与典型常量无法区分,并且允许代码增长,因为所有内容都是{的实例{1}},并包含在方便的_Base
装饰器中。
property
当然,我的下一个问题是......为什么你需要实例化类才能做到这一点?为什么不在方法中定义常量?
class Base(object):
"""for now, just holds constants"""
def __init__(self):
pass
@property
def constant1(self):
return 1
@property
def constant2(self):
return 2
@property
def constant3(self):
return 3
您可以在方法和类中引用它们,而不将它们作为参数提供。它们作为普遍的数据源工作,就像常数应该一样。这通常是避免magic numbers的方法。