python – 使用单例作为计数器

我有一个自动化测试,它使用为文件夹创建屏幕截图的功能.此功能由多个屏幕截图实例调用.在每次测试运行时,都会创建一个新文件夹,所以我不关心计数器重置.为了反映这些屏幕截图的顺序,我必须提出可以按顺序排序的名称.这是我的解决方案:

def make_screenshot_file(file_name):
    order = Counter().count
    test_suites_path = _make_job_directory()
    return make_writable_file(os.path.join(test_suites_path,'screenshot',file_name % order))


class Counter():
    __counter_instance = None

    def __init__(self):
        if Counter.__counter_instance is None:
            self.count = 1
            Counter.__counter_instance = self
        else: 
            Counter.__counter_instance.count += 1
            self.count =  Counter.__counter_instance.count

这对我来说可以.但我一直认为应该有一种更简单的方法来解决这个问题.在那儿?如果单身是唯一的方式,我的代码可以以任何方式进行优化吗?

最佳答案 你在这里要做的是模拟一个全局变量.

没有充分的理由这样做.如果您真的想要一个全局变量,请将其显式化为全局变量.

您可以创建一个简单的Counter类,每次访问它时计数增加1,然后创建它的全局实例.但正如DSM在评论中解释的那样,标准库已经在itertools.count年免费提供了类似的东西.

所以:

import itertools

_counter = itertools.count()
def make_screenshot_file(file_name):
    order = next(_counter)
    test_suites_path = _make_job_directory()
    return make_writable_file(os.path.join(test_suites_path,'screenshot',file_name % order))

我不确定为什么你会担心这会占用多少存储空间或时间,因为我无法设想任何可能无关紧要的程序,无论你是使用8个字节还是800个单个对象当你只做几次时,有多个或者,或者是否需要3ns或3us才能访问它.

但是如果你担心,正如你在the source中看到的那样,count是用C实现的,它的内存效率相当高,如果你不做任何花哨的事情,那么基本上只需要一个PyNumber_Add来生成每个数字,这比解释几行代码要少得多.

既然你问过,这里是如何通过使用_count类属性而不是__counter_instance类属性从根本上简化现有代码:

class Counter():
    _count = 0
    def count(self):
        Counter._count += 1
        return Counter.count

当然现在你必须使用Counter().count()而不仅仅是Counter().count – 但如果重要的话你可以用@property来解决这个问题.

值得指出的是,使用经典类而不是新式类(通过在parens中传递任何内容)是一个非常糟糕的主意,如果你想要一个经典类,你应该抛弃parens,大多数Python程序员将名称Counter与类collections.Counter相关联,并且没有理由计数不能是@classmethod或@ staticmethod ……此时这正是Andrew T.的答案.正如他所指出的那样,这比你正在做的更简单,而且不会更多或更少的Pythonic.

但实际上,所有这些并不比仅仅使_count成为模块级全局并添加模块级count()函数更好并且返回它更好.

点赞