python - 使用 `is (CustomClass)` 可以安全地检测 Python 中的未初始化值

标签 python caching types initialization

我正在创建一个装饰器来缓存可能抛出异常的昂贵函数的值,我想记录我们是否到达了初始化值的点。截至目前,我只是将该值初始化为“奇数”字符串 new_val = "__THIS_IS_UNINITIALIZED__"感觉很脏

我想知道将 is 与自定义类(什么都不做)一起使用是否安全。

这是我现在拥有的:

class Cache:
    _cached = {}
    @staticmethod
    def cache(prefix):
        def wrapper(wrapped):
            def inner(self, *args, **kwargs):
                new_val = "__THIS_IS_UNINITIALIZED__"
                key = Cache.make_key(*args, **kwargs)
                if key in Cache._cached:
                    print("cache hit")
                    return Cache._cached[key]
                print("cache miss")
                try:
                    # This can throw exceptions
                    new_val = wrapped(self, *args, **kwargs)
                    # Something below this can ALSO throw
                    # exceptions, but the value has been
                    # initialized at this point.
                except:
                    if new_val == "__THIS_IS_UNINITIALIZED__":
                        print("we never got to initialize :_( ")
                else:
                    Cache._cache[key] = new_val
            return inner
        return wrapper

我想知道我是否可以使用 if is Class 而不是 if new_val == "__THIS_IS_UNINITIALIZED__"

像这样:

class Uninitialized:
    pass

class Cache:
    _cached = {}
    @staticmethod
    def cache(prefix):
        def wrapper(wrapped):
            def inner(self, *args, **kwargs):
                new_val = Uninitialized
                key = Cache.make_key(*args, **kwargs)
                if key in Cache._cached:
                    print("cache hit")
                    return Cache._cached[key]
                print("cache miss")
                try:
                    # This can throw exceptions
                    new_val = wrapped(self, *args, **kwargs)
                    # Something below this can ALSO throw
                    # exceptions, but the value has been
                    # initialized at this point.
                except:
                    if new_val is Uninitialized:
                        print("we never got to initialize :_( ")
                else:
                    Cache._cache[key] = new_val
            return inner
        return wrapper

    @staticmethod
    def make_key(*args, **kwargs):
        positional = ':'.join([str(s) for s in args])
        kw = ':'.join('%s=%s' % kf for kv in kwargs.items())
        return ':'.join([positional, kw])

class Test:
    def __init__(self):
        self.foo = 'hi'

    @Cache.cache('api')
    def test_cache(self, a, b):
        raise Exception("foo")

if __name__ == "__main__":
    t = Test()
    t.test_cache(1, 2)

使用字符串 "__THIS_IS_UNINITIALIZED__" 到目前为止工作正常(并且在可预见的将来也将工作正常)。老实说,这主要是出于学习目的。

提前谢谢你。

最佳答案

标准的习惯用法是本质上做你所做的,但是创建一个 object 的实例,而不是为这样的哨兵定义一个新类。

 Uninitialized = object()

因为你的类语句等同于

Uninitialized = type("Uninitialized", (object,), {})

唯一的区别是我实例化了 object 而不是 type


更新(通过 Sentinel object and its applications? ):自定义类的实例可以提供更有用的表示,如 the dataclasses module 中的示例所示:

>>> from dataclasses import MISSING
>>> repr(MISSING)
'<dataclasses._MISSING_TYPE object at 0x10baeaf98>'
>>> repr(object())
'<object object at 0x10b961200>'

定义一个新类可以让您将类名用作简短的诊断消息或哨兵用途的描述。

关于python - 使用 `is (CustomClass)` 可以安全地检测 Python 中的未初始化值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55696875/

相关文章:

python - "Not defined"变量 (table_count) 但我确实定义了它

python - 使用 Flask 在特定页面上禁用缓存

r - R中无法将字符转换为数字

c++ - 相当于 Go 中的 sizeof(aType)

ios - 将具体实例传递给需要协议(protocol)参数的闭包

python - CSV 以字节形式返回而不是字符串 Python

从字符串中提取可能日期的 Python 模块?

java - 缓存认证数据

symfony - 教义二级缓存不执行任何操作

用于计算字母表数量的Python代码