Python: creating a read property accessible through ** vars (some_class)

I often use idiom '{var_name}'.format(**vars(some_class)) .

However, when I use a property, I cannot use this to get the value of the property.

Consider this program:

 #!/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))) 

Question:

Is there a way to make the property value available through **vars(some_class) ?

+4
source share
4 answers

Short answer: No, using .format(**vars(object)) not possible, since properties do not use __dict__ from the vars documentation vars :

vars(...)

vars([object]) → dictionary

  • Without arguments equivalent to locals() .
  • With an argument equivalent to object.__dict__ .

However, you can achieve what you want using various format specifiers, for example, attribute search:

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

Please note that you just need to add a lead . (dot) to the names, and you get exactly what you want.


Note: instead of .format(**vars(object)) you should use the format_map method:

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

Calling format_map with the dict argument is equivalent to calling format using ** notation, but it is more efficient because it does not need to unpack it before calling the function.

+2
source

Use notation . -

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

+1
source

To accomplish exactly what you requested, you can write a class that translates access to attribute access:

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

Example:

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

Another pretty hacky alternative is to add

 __getitem__ = object.__getattribute__ 

for the Foo class, and then directly use the Foo instance:

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

I think using attribute access notation is a better solution.

+1
source

If I understood correctly, something like this should work:

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

But still it feels somehow "very bad."

0
source

Source: https://habr.com/ru/post/1500497/


All Articles