V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
huazhaozhe
V2EX  ›  Python

Python 如何实现一个和属性值相关的单例?

  •  
  •   huazhaozhe · 2020-05-26 10:18:47 +08:00 · 2105 次点击
    这是一个创建于 1634 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假如某个类的实例比较耗费内存或者实例化的时候耗费较多的时间,因此想实现一个和实例属性相关的单例,不知道这么叫对不对,,,想达到的效果如下:

    class Example():
        def __init__(self, attr1=None, attr2=None):
            self.attr1 = attr1
            self.attr2 = attr2
    
    instance1 = Example('attr1', 'attr2')
    instance2 = Example('attr1', 'attr2')
    instance3 = Example('attr3', 'attr4')
    instance4 = Example('attr1', 'attr3')
    
    # 希望达到的效果
    # instance1 is instance2 结果为 True
    # instance1 is instance3 结果为 False
    # instance1 is instance4 结果为 False
    

    或者有什么其他更好的解决方法

    14 条回复    2020-05-26 14:15:51 +08:00
    ruanimal
        1
    ruanimal  
       2020-05-26 10:20:24 +08:00
    搞个字典做 cache 就 ok 了啊
    huazhaozhe
        2
    huazhaozhe  
    OP
       2020-05-26 10:26:26 +08:00
    @ruanimal 如果属性值较多那这个字典可能有好多层吧,,,,,而且有好几个这样的类他们属性不同就要写不同的代码和字典,所以有了这个想法
    a719114136
        3
    a719114136  
       2020-05-26 10:30:35 +08:00
    重写 __eq__()方法,然后用 == 判断
    ClericPy
        4
    ClericPy  
       2020-05-26 10:31:02 +08:00
    Borg 模式? 缓存字典放到类属性里, 在 `__new__` 里做类似单例的事情
    ClericPy
        5
    ClericPy  
       2020-05-26 10:33:47 +08:00
    纠正下 #4

    后半句说的是单例模式... new 里做的就是用元组 (attr1, attr2) 做 key 去缓存里找

    上半句是说可以参考下 Borg 模式
    cassidyhere
        6
    cassidyhere  
       2020-05-26 10:36:26 +08:00
    你需要创建缓存实例
    python cookbook 里的例子:

    import weakref

    class Cached(type):
    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.__cache = weakref.WeakValueDictionary()

    def __call__(self, *args):
    if args in self.__cache:
    return self.__cache[args]
    else:
    obj = super().__call__(*args)
    self.__cache[args] = obj
    return obj

    # Example
    class Spam(metaclass=Cached):
    def __init__(self, name):
    self.name = name


    >>> a = Spam('Guido')
    >>> b = Spam('Diana')
    >>> c = Spam('Guido') # Cached
    >>> a is b
    False
    >>> a is c # Cached value returned
    True
    islxyqwe
        7
    islxyqwe  
       2020-05-26 10:42:08 +08:00
    ```python3
    from functools import lru_cache
    @lru_cache(None)
    class Example():
    def __init__(self, attr1=None, attr2=None):
    self.attr1 = attr1
    self.attr2 = attr2

    instance1 = Example('attr1', 'attr2')
    instance2 = Example('attr1', 'attr2')
    instance3 = Example('attr3', 'attr4')
    instance4 = Example('attr1', 'attr3')
    print(instance1 is instance2,instance1 is instance3,instance1 is instance4)
    ```
    结果:True False False
    Vegetable
        8
    Vegetable  
       2020-05-26 10:46:22 +08:00
    楼上正解,直接 lru_cache 完美符合你的需求,同样入参的调用会被缓存
    huazhaozhe
        9
    huazhaozhe  
    OP
       2020-05-26 11:03:30 +08:00
    @islxyqwe nice
    huazhaozhe
        10
    huazhaozhe  
    OP
       2020-05-26 11:33:10 +08:00
    @islxyqwe 当有默认参数的时候有点小问题,他是根据传入参数来决定的
    noparking188
        11
    noparking188  
       2020-05-26 11:36:03 +08:00
    如果是数据相关的话,或许可以用下 dataclasses
    ruanimal
        12
    ruanimal  
       2020-05-26 11:48:39 +08:00
    @huazhaozhe 字典可以用 tuple 做 key,这样多少个属性都可以。 如果使用单例,最终也是用 dict 来缓存的。
    huazhaozhe
        13
    huazhaozhe  
    OP
       2020-05-26 14:14:01 +08:00
    @ruanimal 这样的话传入参数必须一样的顺序,否则就不是同一个 tuple
    huazhaozhe
        14
    huazhaozhe  
    OP
       2020-05-26 14:15:51 +08:00
    @ruanimal 而且当有默认参数时也有点问题,不过也可以用了,上边有人说的 lru_cache 可以直接用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2179 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:32 · PVG 08:32 · LAX 16:32 · JFK 19:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.