这是一个计数器的类定义(文件名:counter.py),它将在复杂的应用程序中使用,
class Counter:
def __init__(self):
self.count = 0
def incr(self):
self.count += 1
def decr(self):
self.count -= 1
事实证明,这个类只会被实例化两次。这两个实例将由多个模块使用。
创建Counter类的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()
这种方法有漏洞吗?如果是,获得相同结果的正确方法是什么?
注意:我并不清楚如何在this question中了解全局变量的共享方式。我想知道的是从同一个类实例化多个对象并从应用程序中的任何位置访问实例的正确方法。
答案 0 :(得分:2)
唯一的漏洞是你会mutating global state,由于种种原因通常不赞成。您可以在main
函数中实例化计数器,并将它们传递给需要它们的对象/方法以避免此问题。或者您可能认为全局可变状态对于您的用例是好的,但这至少是您应该考虑的事情。
阅读链接的artcle以了解与全局可变状态相关的问题以及如何避免它。
这种全球可变状态如何?
像fileCounter
,httpCounter
这样的模块级变量是全局的,因为代码的任何部分都可以通过导入模块来访问它们(请注意,这与{{}不同Python中的1}}关键字)。他们在global
中保持状态,可以通过调用.count
或incr()
或仅指定值来进行变异。
通过使函数的本地实例不再能够访问它们,除非你明确地传递它们。
正确方法
您的解决方案是"正确"从某种意义上说它会起作用。但它可能会导致您必须注意的一些问题。这就是我的答案。
实际上非常"从应用程序的任何位置访问实例"事情是有问题的。当您的对象变得更复杂并且可以从应用程序的更多部分以更多方式访问时,它可以使复杂性增加。
答案 1 :(得分:1)
我会这样做有点不同。这样您就可以在需要时向两个不同的计数器类添加代码。在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
。或者,如果您有两个类的其他代码,它可以进入Counter
类。
此外,如果您愿意,可以更改increment
/ decrement
/ start
值。
答案 2 :(得分:0)
我认为你可以使用Multiton模式(这里使用多重装饰器)来避免全局可变状态。在这个例子中,类#34; 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