测试人社区

请教一下使用__new__方法实现driver和配置文件的单例模式应该怎么写

下方的图如何使用__new__写成单例模式,优化成不需要传入driver和每次读取yaml

image

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

class MyClass(Singleton, BaseClass):
  pass
```

单例模式,实现方式有很多,以下介绍两种方式:

  1. 基于__new__方法

python 是通过__new__ 创建对象实例并分配内存空间的;
这种方式的优点在于可以继承

以下是实现方式,如果不考虑多线程,可以将锁部分去掉

class Singleton:

    _lock = threading.Lock() # 多线程的情况下,加锁,保证线程安全

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,"_instance"): # 已有实例,则直接返回对象,提高效率
            with cls._lock: # 加锁,确保多线程安全
                if not hasattr(cls, "_instance"):  
                    cls._instance = super().__new__(cls) # 创建对象实例,分配内存空间
        return cls._instance

    def __init__(self):
        if not hasattr(self,"_first"):  # 只初始化一次
            with self._lock:
                if not hasattr(self,"_first"):
                    # todo 初始化部分
                    self._first = True
  1. 基于模块导入的方式

当模块第一次导入后,会解析模块并将数据加载到内存中;
再遇到导入,就可以直接从内存读取对象;由此可以得出单例对象;
这种模式,编写简单,缺点是不能继承。

class Singelton:
  def __init__(self):
    # todo 初始化部分
    pass
sigelton=Singelton()
# 其他模块通过 from import sigelton 导入
1 Like

单例的实现已经通过百度了解的差不多了 问题是PO中每次实例的类是不同的页面类,今天尝试的时候每个页面打印出来的地址是不同的地址,driver,config打印出来的也都是不同的地址,代码是用公司的手机写的测试用例,明天用校长的试试一下继承两个类看一下,这种方式没试过
谢谢解答
@seveniruby
@1055063760

每个page通常也是不用单例的。一般只有driver才需要用单例

对 我就是想只把driver和config单例出来 但是今天尝试的时候就是返回页面类时候还是会新建一个driver,config也需要重新读取

@seveniruby 校长 今天试了下 使用下面这种方式是没法达到预期的效果的
因为单例是针对当前的类,如果当前类重复调用的话是只分配一个实例
我们的页面类只是继承base,与父类是不同的类,所以我们在调用子类时不是重复调用父类,还是会去新建内存空间,所以还是会新建多个driver与config
image
这是运行的结果 ,可以看到每个页面类的driver与config都不同,父类的new 和 init方法每次都会被调用
image

但是如果使用类属性直接赋值的方式的话是可以实现单例driver和config,如下代码,删除init,保留new,保留类的单例性质,避免多个base出现
image

运行结果如下:
image

这里每个页面类的driver和config的id()都是一样的了

id打印方式代码:
image

那请问一下 这种方式算单例出来了driver和config吗?会有其它的什么影响吗?