gpt4 book ai didi

Python单例类

转载 作者:太空宇宙 更新时间:2023-11-04 07:24:09 25 4
gpt4 key购买 nike

我正在使用 Python 在 os x 10.6 上为 firefox 5.1 和 selenium webdrive v.2 编写测试套件2.7.

除了创建单例类外,一切正常,这应该保证只有一个 firefox 实例:

def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance

@singleton
class Fire(object):
def __init__(self):
self.driver = webdriver.Firefox()
def getdriver(self):
return self.driver
def close_(self):
self.driver.close()
def get(self, url):
self.driver.get(url)
return self.driver.page_source

f = Fire()
f.close_()

此时,如果我再次调用 f=Fire(),什么也不会发生。不会创建新实例。我的问题是为什么我会看到这种行为?我该怎么做?

我的第二个问题,如果我输入:

isinstance(f, Fire)

我收到这个错误:

TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types

这对我来说很奇怪……根据我的理解,它应该返回 True

最后一个问题:

当我有一个单例类时,我应该能够做到:

f = Fire()
f2 = Fire()
f2.get('http://www.google.com')
up to here works, but if I say
f.close_()//then
URLError: urlopen error [Errno 61] Connection refused

我无法理解这一点。

最佳答案

就创建一个类的单个实例而言,你的装饰器对我来说似乎工作正常,所以我没有看到你的问题#1。它并没有像你想象的那样做:每次你使用装饰器时,都会有一个新的 instances 字典,而且里面只有一个项目,所以实际上没有任何理由使用字典在那里——您需要一个可变容器以便您可以修改它,但我会使用一个列表,或者,在 Python 3 中,可能是一个 nonlocal 变量。但是,它确实执行了其预期功能,即确保装饰类只有一个实例。

如果你问为什么在关闭对象后不能创建对象的新实例,那么,你没有编写任何代码来允许在那种情况下创建另一个实例,Python 无法猜测你希望它发生。单例意味着该类永远只有一个实例。您已经创建了那个实例;你不能再创建一个。

至于#2,您的@singleton 装饰器返回一个函数,该函数实例化(或返回先前创建的实例)该类。因此,Fire 是一个函数,而不是一个类,一旦被装饰,这就是为什么您的 isinstance() 不起作用。

在我看来,最直接的单例方法是将智能放在类中而不是装饰器中,然后从该类继承。这甚至从继承的角度来看也是有意义的,因为单例是一种对象。

class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance

class Fire(Singleton):
pass

f1 = Fire()
f2 = Fire()

f1 is f2 # True
isinstance(f1, Fire) # True

如果你仍然想用装饰器来做,最简单的方法是在装饰器中创建一个中间类并返回它:

def singleton(D):

class C(D):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = D.__new__(cls, *args, **kwargs)
return cls._instance

C.__name__ = D.__name__

return C

@singleton
class Fire(object):
pass

您可以将所需的行为注入(inject)现有的类对象,但在我看来,这是不必要的复杂,因为它需要(在 Python 2.x 中)创建一个方法包装器,而且您还必须处理这种情况其中被装饰的类自己已经有一个 __new__() 方法。

您可能认为您可以编写一个 __del__() 方法来允许在没有对现有实例的引用时创建一个新的单例。这是行不通的,因为始终存在对实例的类内部引用(例如,Fire._instance),因此永远不会调用 __del__()。一旦你有了一个单例,它就会一直存在。如果您在关闭旧的单例后想要一个新的单例,您可能实际上并不想要单例,而是想要别的东西。 context manager有可能。

在某些情况下可以重新实例化的“单例”对我来说是非常奇怪和意外的行为,我建议不要这样做。尽管如此,如果那是您真正想要的,您可以在 close_() 方法中执行 self.__class__._instance = None。或者您可以编写一个单独的方法来执行此操作。它看起来很丑,这很合适,因为它很丑。 :-)

我认为您的第三个问题也源于这样一个事实,即您希望单例在您调用 close_() 之后以某种方式消失,而您还没有对该行为进行编程。

关于Python单例类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8563130/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com