python 单例 模块之间调用 失败记录和总结

单例模式在模块内调用时,内存地址是相同的。但是我在模块之间调用时,发现了地址不同的情况,从而导致代码逻辑混乱。将自己踩过的坑记录在次,供以后查阅,也希望能让同级别的初学者少走点弯路。不想费时间看过程的,可以直接看最后的总结。

1.只用1个模块,正常

先记下模块内调用,以证明代码没问题。过程是 实例化Singleton,然后通过instantiation方法第2次实例化,验证两次实例化的地址是否相同。

#!python3
# coding:utf-8

class Singleton:
    obj = None

    def __new__(cls, *args, **kwargs):
        if Singleton.obj is None:
            Singleton.obj = super().__new__(cls)
        return Singleton.obj


def instantiation():
    s2 = Singleton()
    print(f'第2次调用地址:{s2}')


if __name__ == '__main__':
    s1 = Singleton()
    print(f'第1次调用地址:{s1}')
    instantiation()

第1次调用地址:<__main__.Singleton object at 0x00000215047388B0>
第2次调用地址:<__main__.Singleton object at 0x00000215047388B0>

2_1.用2个模块,从单例模块运行,出问题

做成两个模块进行互相导入后再调用,从module1运行。注意,这会出现不同的地址。

#!python3
# coding:utf-8
# FileName: module1
import module2


class Singleton:
    obj = None

    def __new__(cls, *args, **kwargs):
        if Singleton.obj is None:
            Singleton.obj = super().__new__(cls)
        return Singleton.obj


if __name__ == '__main__':
    s1 = Singleton()
    print(f'第1次调用地址:{s1}')
    module2.instantiation()
#!python3
# coding:utf-8
# FileName: module2
import module1


def instantiation():
    s2 = module1.Singleton()
    print(f'第2次调用地址:{s2}')


if __name__ == '__main__':
    pass

第1次调用地址:<__main__.Singleton object at 0x00000158350A98B0>
第2次调用地址:<module1.Singleton object at 0x00000158350EB6D0>

我不知道为什么会这样,琢磨了很久,感觉代码逻辑没问题,就是会出现2个内存地址。

2_2.用2个模块,从非单例模块运行,正常

尝试从module2运行。地址相同。

#!python3
# coding:utf-8
# FileName: module1

class Singleton:
    obj = None

    def __new__(cls, *args, **kwargs):
        if Singleton.obj is None:
            Singleton.obj = super().__new__(cls)
        return Singleton.obj


if __name__ == '__main__':
    pass

#!python3
# coding:utf-8
# FileName: module2
import module1


def instantiation():
    s2 = module1.Singleton()
    print(f'第2次调用地址:{s2}')


if __name__ == '__main__':
    s1 = module1.Singleton()
    print(f'第1次调用地址:{s1}')
    instantiation()

第1次调用地址:<module1.Singleton object at 0x000001C9E2199670>
第2次调用地址:<module1.Singleton object at 0x000001C9E2199670> 

3.用3个模块,正常

尝试创建第3个模块,导入前2个模块,从第3个模块运行,发现地址是一样的,真是百思不得姐。

#!python3
# coding:utf-8
# FileName: module3
import module1
import module2

if __name__ == '__main__':
    s1 = module1.Singleton()
    print(f'第1次调用地址:{s1}')
    module2.instantiation()

第1次调用地址:<module1.Singleton object at 0x000002C55BE69670>
第2次调用地址:<module1.Singleton object at 0x000002C55BE69670>

4.分析

 对比后发现确实有区别,正常的结果中,要么全部是“__main__.Singleton...”,要么全部是“module1.Singleton...”。但2_1却各占一样。

我的理解是“__main__.Singleton”是本模块内运行,既if __name__ == '__main__':之后的运行,是本模块内部的类实例化的。而“module1.Singleton”是导入模块运行,是从外部模块导入之后实例化的。

感觉:class 从本模块实例化用的"是一个内存空间(自己瞎猜的)",而被别的模块导入后实例化用的是另一个内存空间,不同内存空间之间不能共享数据,所以单例的class就像平行宇宙一样出现不同的内存地址。

5.总结:

a.以后使用单例模式时,如果不牵涉模块之间调用,则不会出问题。

b.如果牵涉到模块之间调用,则最好将单例class做成被调用的模块(既:不要从含有单例class的模块运行)。

6.迷惑之处

虽然分析到了区别,但这个区别为何会导致内存地址不同?如有前辈看到,还请解惑,不胜感激!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值