2

我对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__(),在性能方面或其他方面是否有任何缺点?ba

4

4 回答 4

4

You'd normally put constants inside a module instead of a class. If you need to use them for subclasses then inherit from the Base and use them, otherwise, don't instantiate the class as you're just using it as a kind of "namespace".

Name it something better than _Base and access the variables as (for eg:) MyConstants.constant1 instead...

于 2013-02-21T01:02:39.323 回答
3

Jon Clements 给出了你应该如何做的答案。

但是要回答您的实际问题:

与 a 相比,使用 b 方法在性能方面或其他方面有什么缺点吗?

比性能更重要的是可读性。如果您实例化一个对象,读者会认为您出于某种原因这样做了,并在试图弄清楚b正在使用什么以及_Base实例在您的对象模型中代表什么等等时被绕开。很快就会发现它没用,但是“显而易见”总是比“不会花费太长时间才能弄清楚”要好。

但也有性能下降。在您编写的任何程序中,它很可能永远不会以任何可衡量的方式产生影响,但它就在那里。

首先,b是一个新分配的对象,它占用几个字节(可能几十个),而a只是一个已经存在的对象(类本身)的新名称。因此,它会浪费内存。

其次,构建b需要一些时间。除了分配内存之外,您还必须调用__new____init__插槽object

您可以使用 自己测试性能差异timeit,但我不会打扰。你很可能会发现它比它b慢 20 倍a或类似的东西,但是你每次运行一次需要不到一微秒的时间进行 20:1 的改进仍然没有意义。

于 2013-02-21T01:17:30.293 回答
0

我说要注意未来的维护,并将类设置为具有所有@property方法,因为它们与典型的常量无法区分,并允许您的代码增长,因为所有内容都将是 的实例_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

当然,我的下一个问题是……为什么需要实例化一个来做到这一点?为什么不在方法中定义一个常量?

#! /usr/bin/env python
"""this module does stuff"""

CONSTANT_1 = 1
CONSTANT_2 = 2
CONSTANT_3 = 3

您可以在方法和类中引用它们,而无需将它们作为参数提供。它们作为普遍的数据源工作,就像常量一样。这通常是避免幻数的方法。

于 2013-02-21T01:26:43.930 回答
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% 的分数,因为我的参考书目格式不正确。内容完美无缺,对我的老师来说还不够漂亮。我发现人们可以花时间学习规则或解决问题。我更喜欢解决问题。

于 2013-02-21T01:09:43.677 回答