【问题标题】:Python: Making a read-only property accessible via **vars(some_class)Python:通过 **vars(some_class) 使只读属性可访问
【发布时间】:2013-09-07 20:06:19
【问题描述】:

我经常使用成语'{var_name}'.format(**vars(some_class))

但是,当我使用属性时,我无法使用它来获取属性值。

考虑这个程序:

#!/usr/bin/env python

class Foo(object):
    def __init__(self):
        self._bar = None
        self.baz = 'baz here'

    @property
    def bar(self):
        if not self._bar:
            # calculate some value...
            self._bar = 'bar here'
        return self._bar

if __name__ == '__main__':
    foo = Foo()

    # works:
    print('{baz}'.format(**vars(foo)))

    # gives: KeyError: 'bar'
    print('{bar}'.format(**vars(foo)))

问题:

有没有办法通过**vars(some_class) 访问属性值?

【问题讨论】:

    标签: python dictionary properties


    【解决方案1】:

    简答:不,不可能使用.format(**vars(object)) 来做你想做的事,因为属性确实使用__dict__vars 文档:

    vars(...)

    vars([object]) -> 字典

    • 不带参数,相当于locals()
    • 带参数,相当于object.__dict__

    但是你可以使用不同的格式说明符来实现你想要的,例如属性查找:

    In [2]: '{.bar}'.format(Foo())
    Out[2]: 'bar here'
    

    请注意,您只需在名称中添加前导 .(点)即可获得所需的内容。


    旁注:您应该使用format_map 方法,而不是使用.format(**vars(object))

    In [6]: '{baz}'.format_map(vars(Foo()))
    Out[6]: 'baz here'
    

    使用dict 参数调用format_map 等效于使用** 表示法调用format,但它更有效,因为它在调用函数之前不必进行任何类型的解包。

    【讨论】:

    • +1,属性查找就是那个时候,我也不知道format_map
    【解决方案2】:

    使用. 表示法-

    print('{0._bar}'.format(foo))

    【讨论】:

    • 刚刚注意到您使用**vars(some_class) 要求某些东西的底部,这真的是一个要求吗?
    • 如果放弃**vars(some_class),也可以使用属性getter:print('{0.bar}'.format(foo))
    • 是的,这行得通,但它应该说print('{0.bar}'.format(foo))(不带下划线),否则该属性将没有意义;D
    【解决方案3】:

    要完全按照您的要求进行操作,您可以编写一个将项目访问转换为属性访问的类:

    class WrapperDict(object):
        def __init__(self, obj):
            self.obj = obj
        def __getitem__(self, key):
            return getattr(self.obj, key)
    

    例子:

    >>> print('{bar}'.format_map(WrapperDict(Foo())))
    bar here
    

    另一个相当老套的选择是添加

    __getitem__ = object.__getattribute__
    

    Foo类,然后直接使用Foo实例:

    >>> print('{bar}'.format_map(Foo()))
    bar here
    

    我认为使用属性访问表示法是更好的解决方案。

    【讨论】:

      【解决方案4】:

      如果我理解你的正确,这样的事情应该可以工作:

      print( eval( 'foo.{bar}'.format( **dict( ( v, v ) for v in dir( foo ) ) ) ) )
      

      不过这感觉有点“非常糟糕”。

      【讨论】:

      • 工作,但我不喜欢使用eval...更好:print('{bar}'.format(**dict((v, getattr(foo,v)) for v in dir(foo)))),但它不是非常优雅。
      【解决方案5】:

      您可以将其写入实例的__dict__

      class Article(object):
          def __init__(self):
              self.content = ""
              self.url = ""
      
          @property
          def title(self):
              return self.__dict__.get("title", "")
      
          @title.setter
          def title(self, title):
              self.__dict__["title"] = title
      

      然后:

      >>> article = Article()
      >>> article.title = "Awesome Title"
      >>> vars(article)
      {'content': '', 'url': '', 'title': 'Awesome Title'}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-17
        • 1970-01-01
        • 1970-01-01
        • 2010-10-11
        • 1970-01-01
        • 2017-06-18
        • 2011-11-08
        • 2010-11-04
        相关资源
        最近更新 更多