在 try 和 except 中使用属性的正确方法 [英] Proper way of using properties with try and except

查看:60
本文介绍了在 try 和 except 中使用属性的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有使用 @property 装饰器设置属性的类.它们使用内部的 try 和 except 子句充当 getter 和 setter.如果没有设置属性,它会从数据库中获取数据并使用它来实例化来自其他类的对象.我试图保持示例简短,但是用于实例化属性对象的代码对于每个属性都略有不同.他们的共同点是一开始的try-except.

class SubClass(TopClass):@财产定义事物(自我):尝试:返回 self._thing除了属性错误:#我们还没有任何东西经过thing = get_some_thing_from_db('东西')如果不是:引发 AttributeError()self._thing = TheThing(东西)返回 self._thing@财产def another_thing(self):尝试:返回 self._another_thing除了属性错误:#我们还没有这样的东西经过another_thing = get_some_thing_from_db('another')如果不是 another_thing:引发 AttributeError()self._another_thing = AnotherThing(another_thing)返回 self._another_thing...等等...@财产def one_more_thing(self):尝试:返回 self._one_more_thing除了属性错误:#我们还没有这个东西经过one_thing = get_some_thing_from_db('one')如果不是 one_thing:引发 AttributeError()self._one_more_thing = OneThing(one_thing)返回 self._one_more_thing

我的问题:这是一种正确的(例如pythonic)做事方式吗?对我来说,在所有内容之上添加 try-except-segment 似乎有点尴尬.另一方面,它保持代码简短.或者有更好的定义属性的方法吗?

解决方案

只要您至少使用 Python 3.2,请使用 functools.lru_cache() 装饰器.

import functools类子类(TopClass):@财产@functools.lru_cache()定义事物(自我):thing = get_some_thing_from_db('东西')如果不是:引发 AttributeError()返回 TheThing(东西)

一个快速运行的例子:

<预><代码>>>>导入功能工具>>>C类:@财产@functools.lru_cache()def foo(self):打印(叫foo")返回 42>>>c = C()>>>foo叫 foo42>>>foo42

如果你有很多这些,你可以组合装饰器:

<预><代码>>>>def lazy_property(f):返回属性(functools.lru_cache()(f))>>>C类:@lazy_propertydef foo(self):打印(叫foo")返回 42>>>c = C()>>>foo叫 foo42>>>foo42

如果您仍在使用旧版本的 Python,那么 ActiveState 虽然在这种情况下,您在调用它时没有传递任何参数,但您可能可以用更简单的东西替换它.

@YAmikep 询问如何访问lru_cachecache_info() 方法.有点乱,不过还是可以通过property对象访问:

<预><代码>>>>C.foo.fget.cache_info()CacheInfo(hits=0,misses=1,maxsize=128,currsize=1)

I have classes that have attributes set with @property decorator. They function as getter and setter using try and except clauses inside them. If attribute is not set, it gets data from database and uses it to instatiate objects from other classes. I tried to keep the example short, but the code used to instantiate attribute objects is a little different with each attribute. What they have in common is the try-except at the beginning.

class SubClass(TopClass):

    @property
    def thing(self):
        try:
            return self._thing
        except AttributeError:
            # We don't have any thing yet
            pass
        thing = get_some_thing_from_db('thing')
        if not thing:
            raise AttributeError()
        self._thing = TheThing(thing)
        return self._thing

    @property
    def another_thing(self):
        try:
            return self._another_thing
        except AttributeError:
            # We don't have things like this yet
            pass
        another_thing = get_some_thing_from_db('another') 
        if not another_thing:
            raise AttributeError()
        self._another_thing = AnotherThing(another_thing)
        return self._another_thing

    ...etc...

    @property
    def one_more_thing(self):
        try:
            return self._one_more_thing
        except AttributeError:
            # We don't have this thing yet
            pass
        one_thing = get_some_thing_from_db('one') 
        if not one_thing:
            raise AttributeError()
        self._one_more_thing = OneThing(one_thing)
        return self._one_more_thing

My question: is this a proper (e.g. pythonic) way of doing stuff? To me it seems a bit awkward to add the try-except-segment on top of everything. On the other hand it keeps the code short. Or is there a better way of defining attributes?

解决方案

So long as you are using at least Python 3.2, use the functools.lru_cache() decorator.

import functools
class SubClass(TopClass):

    @property
    @functools.lru_cache()
    def thing(self):
        thing = get_some_thing_from_db('thing')
        if not thing:
            raise AttributeError()
        return TheThing(thing)

A quick runnable example:

>>> import functools
>>> class C:
    @property
    @functools.lru_cache()
    def foo(self):
        print("Called foo")
        return 42


>>> c = C()
>>> c.foo
Called foo
42
>>> c.foo
42

If you have a lot of these you can combine the decorators:

>>> def lazy_property(f):
    return property(functools.lru_cache()(f))

>>> class C:
    @lazy_property
    def foo(self):
        print("Called foo")
        return 42


>>> c = C()
>>> c.foo
Called foo
42
>>> c.foo
42

If you are still on an older version of Python there's a fully featured backport of lru_cache on ActiveState although as in this case you're not passing any parameters when you call it you could probably replace it with something much simpler.

@YAmikep asks how to access the cache_info() method of lru_cache. It's a little bit messy, but you can still access it through the property object:

>>> C.foo.fget.cache_info()
CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)

这篇关于在 try 和 except 中使用属性的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆