这是在复杂应用程序中使用的计数器(文件名:Counter.py)的类定义,
class Counter:
def __init__(self):
self.count = 0
def incr(self):
self.count += 1
def decr(self):
self.count -= 1
事实证明,这个类只会被实例化两次。这两个实例将被多个模块使用。
什么是正确的方法来创建2个实例的计数器类,以便两个实例的状态可以在整个应用程序共享?
下面是我提出的解决方案,
class Counter:
def __init__(self):
self.count = 0
def incr(self):
self.count += 1
def decr(self):
self.count -= 1
fileCounter = Counter()
httpCounter = Counter()
因此,从另一个模块,我将执行以下操作,
from counter import fileCounter, httpCounter
def readMoxyConfig():
# Do read the file here
fileCounter.incr()
def callMoxyAPI():
# Make the HTTP rest call here
httpCounter.incr()
这种方法是否存在漏洞?如果是,实现相同结果的正确方法是什么?
注意:我不想明确地知道全局变量是如何在这个问题中共享的。我想知道的是从同一个类实例化多个对象并从应用程序中的任何位置访问实例的正确方法。
唯一的漏洞是你会改变全局状态,这通常是不赞成的原因有很多。您可以在main
函数中实例化计数器,并将它们传递给需要它们的对象/方法以避免此问题。或者您可能认为全局可变状态适合您的用例,但这至少是您应该考虑的事情。
阅读链接文章,了解与全局可变状态相关的问题以及如何避免。
这个全局可变状态是怎样的?
模块级变量,如fileCounter
,httpCounter
,是全局变量,因为代码的任何部分都可以通过导入模块来访问它们(请注意,这与Python中的global
关键字不同)。它们在中保持状态。计数
可通过调用incr()
或进行变异。decr()
或只分配一个值。
通过将实例设置为函数的本地实例,代码的其他部分就不能再访问它们了,除非您显式地传递它们。
正确的方法
您的解决方案是“正确”的,因为它会起作用。但是它会导致一些你必须意识到的问题。这就是我的答案。
实际上,“从应用程序中的任何地方访问实例”是有问题的。随着对象变得更加复杂,并且从应用程序的更多部分以更多方式访问,它会使复杂性增加。
我会做一点不同的事情。这样,您就可以在需要时向两个不同的计数器类添加代码。在您的counter.py
中:
class Counter():
def incr(self, increment = 1):
self.count += increment
def decr(self, decrement = 1):
self.count -= decrement
class httpCounter(Counter):
def __init__(self, start = 0):
self.count = start
class fileCounter(Counter):
def __init__(self, start = 0):
self.count = start
这样,如果您需要进入其中一个类,可以将其添加到httpCounter
或fileCounter
。或者,如果两个类都有额外的代码,它可以进入计数器
类。
此外,如果您愿意,您可以更改增量
/递减
/start
值。
我认为您可以使用Multiton模式(这里使用了Multiton decorator)来避免全局可变状态。在本例中,类“MyClass”本身的行为与其Multiton相同
多例
def multiton(cls):
instances = {}
def getinstance(name):
if name not in instances:
instances[name] = cls()
return instances[name]
return getinstance
@multiton
class MyClass:
pass
a = MyClass("MyClass0")
b = MyClass("MyClass0")
c = MyClass("MyClass1")
print a is b # True
print a is c # False