2013-09-04 3 views
4

Я часто использую idiom '{var_name}'.format(**vars(some_class)).Python: создание свойства, доступного только для чтения, через ** 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)?

ответ

2

Короткий ответ: Нет, это не представляется возможным использовать .format(**vars(object)) делать то, что вы хотите, так как свойства делают не использование __dict__ и из vars документации:

vars(...)

vars([object]) -> Словарь

  • Без аргументов, эквивалентных locals().
  • С аргументом, эквивалентным object.__dict__.

Однако вы можете добиться того, что вы хотите, используя различные спецификаторы формата, к примеру поиск атрибута:

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

Заметьте, что вы просто должны добавить ведущую . (точка) к именам и вы получаете именно то, что хотите.


Side Примечание: вместо использования .format(**vars(object)) вы должны использовать format_map метод:

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

Вызов format_map с dict аргумента эквивалентно вызову format с использованием ** обозначения, но это более эффективно, поскольку перед вызовом функции он не должен делать никаких распаковки.

+0

+1, поиск атрибута это тогда, также я не знал о 'format_map' – phoibos

1

Использование . обозначения -

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

+0

Только что заметил нижнюю часть, где вы просите что-то, используя '** vars (some_class)' это действительно требование? –

+2

Если вы откажетесь от '** vars (some_class)', вы также можете использовать свойство getter: 'print ('{0.bar}'. Format (foo))'. – ford

+0

Да, это работает, но он должен сказать 'print ('{0.bar}'. Format (foo))' (без подчеркивания), в противном случае свойство не имеет смысла; D – phoibos

0

Если я понял, вы исправить, что-то, как это должно работать:

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

Но все же это чувствует себя как-то "очень плохо".

+0

Работает, но я не как использовать 'eval' ... better:' print ('{bar}'. format (** dict ((v, getattr (foo, v)) для v в dir (foo)))) ', но это не ужасно изящный. – phoibos

1

Чтобы сделать именно то, что вы просили, вы можете написать класс, который транслирует доступ пункт приписывать доступа:

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 

Другой довольно Hacky альтернативой было бы добавить

__getitem__ = object.__getattribute__ 

к классу Foo, а затем используйте Foo экземпляр непосредственно:

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

Я думаю, используя нотацию доступа атрибута является лучшим решением, хотя.

Смежные вопросы