Используйте str.format() для доступа к атрибутам объекта

У меня есть объект Python с атрибутами a, b, c.

Я все еще использую старое форматирование строк, поэтому обычно печатаю их вручную:

 print 'My object has strings a=%s, b=%s, c=%s' % (obj.a, obj.b, obj.c)

В последнее время мои строки становятся очень длинными, и я бы предпочел просто передать объект в функцию формата строки, например:

 print 'My object has strings a=%a, b=%b, c=%c'.format(obj)

Однако синтаксис неверен. Это возможно?


person Adam Hughes    schedule 07.11.2014    source источник


Ответы (5)


Вы можете использовать нотацию .attribute_name внутри самих полей формата:

print 'My object has strings a={0.a}, b={0.b}, c={0.c}'.format(obj)

Ниже представлена ​​демонстрация:

>>> class Test(object):
...     def __init__(self, a, b, c):
...         self.a = a
...         self.b = b
...         self.c = c
...
>>> obj = Test(1, 2, 3)
>>> 'My object has strings a={0.a}, b={0.b}, c={0.c}'.format(obj)
'My object has strings a=1, b=2, c=3'
>>>

Однако обратите внимание, что при этом вам необходимо пронумеровать поля формата. Также, как видите, поля формата функции str.format обозначаются фигурными скобками {...}, а не знаком %.

Для получения дополнительной информации см. ссылку на синтаксис форматирования строки в Python.

person Community    schedule 07.11.2014
comment
Мне так больше нравится: print 'My object has strings a={obj.a}, b={obj.b}, c={obj.c}'.format(obj=obj) - person Roman L; 07.11.2014
comment
Крутые ребята, спасибо. Означает ли 0. (например, 0.a) индекс элемента, переданного в формат? - person Adam Hughes; 07.11.2014
comment
@AdamHughes - Точно. Нумерация Python начинается с 0, как и в C/C++. 0 — первый (единственный) аргумент str.format. - person ; 07.11.2014
comment
@RomanL - ОП не понравилось его текущее решение, потому что оно требовало от вас ввода obj один раз для каждого атрибута. Много раз писать obj утомительно и ненужно, ИМХО. Но, как вы сказали, это в основном вопрос предпочтений. :) - person ; 07.11.2014
comment
Это верно, но я все еще ценю альтернативные подходы. Я не знал об обоих случаях! - person Adam Hughes; 07.11.2014
comment
@iCodez: 0 и obj повторяются в строке одинаковое количество раз. Реалистичный пример с укороченным объектом: 'a={o.a}, b={o.b}'.format(o=my_actual_object_name). Для тех, кто не знаком с этой нотацией, это гораздо более очевидно, чем 0.a IMO. - person Roman L; 08.11.2014
comment
Также '{a} {b}'.format(**vars(obj)) или '{a} {b}'.format(**obj.__dict__) - person igniteflow; 01.06.2015
comment
@iCodez, можете ли вы также получить доступ к методам класса? или просто атрибуты класса? - person Halcyon Abraham Ramirez; 01.08.2015
comment
@HalcyonAbrahamRamirez - Да, вы можете получить доступ к методам, но вы не сможете их вызывать. Вместо этого вы получите строковое представление метода, например: <bound method Class.method of <__main__.Class object at 0x0000000002CC27B8>>'. - person ; 05.08.2015

Я думаю, что предпочтительнее использовать vars() для доступа к атрибутам объекта как dict вместо использования __dict__.

Итак, вы можете сделать это:

"My object has strings a={a}, b={b}, c={c}".format(**vars(obj))

Дополнительные сведения о том, почему vars() предпочтительнее __dict__, см. в ответе на вопрос Используйте dict или vars()?.

person Geoffrey Hing    schedule 16.02.2017
comment
если вы определяете __slots__, __dict__ нет, то vars вообще не будет работать. - person Shiplu Mokaddim; 05.11.2019

Как написал @igniteflow в скрытом комментарии:

'My object has strings a={a}, b={b}, c={c}'.format(**obj.__dict__)

С моим ограниченным пониманием python: .__dict__ - это dict со всеми атрибутами экземпляров, и оператор ** в основном распаковывает их и добавляет в качестве аргументов ключ = значение к методу.

person Christian    schedule 07.07.2015
comment
Ницца! Использование '**' является ключом. Включение .__dict__ в пример неудачно, поскольку делает его более сложным, чем он есть на самом деле. например 'Мой объект содержит строки a={a}, b={b}'.format(**{'a':'hi', 'b':'mom'}) - person python1981; 13.10.2015

Для полноты, основываясь на @igniteflow и @Christian, вы можете использовать оператор формата строки % и написать:

'My object has strings a=%(a)s, b=%(b)s, c=%(c)s' % obj.__dict__
person Jason    schedule 22.08.2015

Некоторые из предлагаемых ответов, основанных на vars(...), не работают с неизменяемыми объектами:

>>> class foo(object):
...   __slots__ = ()
...   def __init__(self):
...     self.x = 1
...
>>> vars(foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
AttributeError: 'foo' object has no attribute 'x'

Я думаю, что предпочтительнее придерживаться чего-то надежного и явно указывать, что вам нужно напечатать.

Если вам нужно напечатать массу атрибутов, то сохранение этих значений в качестве атрибутов может быть не лучшей идеей.

person iggy    schedule 18.10.2017