# Repr output of t-strings

**URL:** <https://discuss.python.org/t/repr-output-of-t-strings/107653>\
**Category:** Core Development\
**Created:** [June 6, 2026, 2:10pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653 "2026-06-06T14:10:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 6, 2026, 2:10pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/1 "2026-06-06T14:10:05Z")

</div>

I really like the new t-strings in Python 3.14 and am experimenting with them.

However what seems problematic to me is the `repr` output of t-strings for two reasons.

For example:

```python
x = 1
y = 2
t = t"{x} + {y}"
print(repr(t))

```

prints

```python
Template(strings=('', ' + ', ''), interpolations=(Interpolation(1, 'x', None, ''), Interpolation(2, 'y', None, '')))

```

`repr` output is supposed to show the exact Python source that recreates the object. If this is not possible the `<...>` for is used. The actual output seems to show a constructor call, but `templatelib.Template` has no keyword arguments `strings` and `interpolations`. I actually tried recreating the t-string with:

```python
from string import templatelib
t = templatelib.Template(
	strings=('', ' + ', ''),
	interpolations=(
		templatelib.Interpolation(1, 'x', None, ''),
		templatelib.Interpolation(2, 'y', None, '')
	)
)

```

but got

```python
TypeError: Template. __new__ only accepts *args arguments

```

So the `repr` output is misleading.

The second problem is that the output makes it really hard to reconstruct the structure of the t-string in my head, since the parts of the template are output in “scrambled” order.

An output that shows the parts in the order that they had in the template would be much more useful, i.e.

```python
Template(Interpolation(1, 'x', None, ''), ' + ', Interpolation(2, 'y', None, ''))

```

This has three advantages:

1. This is very close to the expression that created the t-string (in this case it really _is_ the correct expression).
2. It show the parts in the order that they are in the t-string.
3. It is shorter, since the keyword names are gone, and the empty strings between the interpolations are omitted.

I realize that what the repr currently displays it how the parts of the template are stored internally, which makes the implementation really short:

```c
static PyObject *
template_repr(PyObject *op)
{
    templateobject *self = templateobject_CAST(op);
    return PyUnicode_FromFormat("%s(strings=%R, interpolations=%R)",
                                _PyType_Name(Py_TYPE(self)),
                                self->strings,
                                self->interpolations);
}

```

But IMHO the `repr` output for `Template` objects should be changed to show the real order of the parts.

Servus,  
Walter

---

<div class="post-metadata">

**Author:** ![nedbat](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nedbat/32/8744_2.png) [@nedbat](https://discuss.python.org/u/nedbat)\
**Post date:** [June 6, 2026, 9:42pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/2 "2026-06-06T21:42:32Z")

</div>

> [@doerwalter](#):
>
> `repr` output is supposed to show the exact Python source that recreates the object. If this is not possible the `<...>` for is used.

I don’t think this is a rule, and I don’t think it’s useful. In my mind, the important thing about repr output is that it be useful to developers, and part of that is being unambiguous. Python source that can recreate the object meets those criteria, but it’s not the only way to meet them.

> [@doerwalter](#):
>
> An output that shows the parts in the order that they had in the template would be much more useful, i.e.
> 
> ```python
> Template(Interpolation(1, 'x', None, ''), ' + ', Interpolation(2, 'y', None, ''))
> 
> ```

I agree: this looks like a useful output that meets the repr criteria.

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 7, 2026, 11:59am UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/3 "2026-06-07T11:59:53Z")

</div>

It’s even worse for nested t-strings:

```python
table = "tablename"
fields = {
	"field1": "foo",
	"field2": "bar",
}

condition = t"field1={fields['field1']} and field2={fields['field2']}"
query = t"select * from {table:l} where {condition:l}"

```

The default repr gives:

```python
Template(
	strings=('select * from ', ' where ', ''),
	interpolations=(
		Interpolation('tablename', 'table', None, 'l'),
		Interpolation(
			Template(
				strings=('field1=', ' and field2=', ''),
				interpolations=(
					Interpolation('foo', "fields['field1']", None, ''),
					Interpolation('bar', "fields['field2']", None, '')
				)
			),
			'condition',
			None,
			'l'
		)
	)
)

```

the new repr would give:

```python
Template(
	'select * from ',
	Interpolation('tablename', 'table', None, 'l'),
	' where ',
	Interpolation(
		Template(
			'field1=',
			Interpolation('foo', "fields['field1']", None, ''),
			' and field2=',
			Interpolation('bar', "fields['field2']", None, '')
		),
		'condition',
		None,
		'l'
	)
)

```

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 8, 2026, 7:14am UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/4 "2026-06-08T07:14:08Z")

</div>

Since templates are immutable they can never reference themselves directly, but if a template is part of an interpolated mutable value it can. For this the current repr gives:

```python
x = []
t = t"{x}"
x.append(t)
print(repr)

Template(
	strings=('', ''),
	interpolations=(
		Interpolation(
			[
				Template(
					strings=('', ''),
					interpolations=(...)
				)
			],
			'x',
			None,
			''
		),
	)
)

```

With the new repr and proper recursion detection we get:

```python
...
print(repr)

Template(
	Interpolation(
		[
			Template(...)
		],
		'x',
		None,
		''
	)
)

```

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [June 8, 2026, 1:22pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/5 "2026-06-08T13:22:12Z")

</div>

> [@nedbat](#):
>
> > [@doerwalter](#):
> >
> > `repr` output is supposed to show the exact Python source that recreates the object. If this is not possible the `<...>` for is used.
> 
> I don’t think this is a rule, and I don’t think it’s useful.

It’s never been a universal rule, though some objects are specified to round-trip via repl/eval. `str` being one of them.

In this case, I do think it’s useful. Not necessarily that `repr(t)` is identical to the original string, but certainly that `eval(repr(t))` is identical to the original `Template` object (which allows for differences in whitespace, escaping, etc.).

Probably just requires someone to implement it, though. I can’t imagine we’d reject such an addition _unless_ it’s merely wasting memory by keeping the unparsed string around. Regenerating the string on request (i.e. someone has invoked ` __repr__ `) is the way.

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 8, 2026, 2:03pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/6 "2026-06-08T14:03:05Z")

</div>

I do have a patch that implements that (that’s how I generated the outputs for the new `repr` ;))

If there are no objections I can open an issue and prepare a pull request for that.

My last patch was ages ago, so I’m no longer familiar with the current workflow.

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [June 8, 2026, 2:31pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/7 "2026-06-08T14:31:59Z")

</div>

> [@doerwalter](#):
>
> If there are no objections I can open an issue and prepare a pull request for that.

It’s certainly easier to discuss something like this over an actual pull request, rather than in generalities.

The process is basically a standard GitHub process - create an issue (you can link here, but put context into the issue), then create the PR against `main`, link to it from here and give it a couple days for the relevant/interested committers to take a look.

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 8, 2026, 6:27pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/8 "2026-06-08T18:27:38Z")

</div>

OK, I’ve created the issue [Better `repr` for `string.templatelib.Template`. · Issue #151099 · python/cpython · GitHub](https://github.com/python/cpython/issues/151099)

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 8, 2026, 6:55pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/9 "2026-06-08T18:55:53Z")

</div>

And here’s the pull request: [gh-151099: Better repr output for template strings. by doerwalter · Pull Request #151104 · python/cpython · GitHub](https://github.com/python/cpython/pull/151104)

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 17, 2026, 8:10am UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/10 "2026-06-17T08:10:06Z")

</div>

After some discussion on the issue [Better `repr` for `string.templatelib.Template`. · Issue #151099 · python/cpython · GitHub](https://github.com/python/cpython/issues/151099) it is unclear what the best repr output for template strings is.

Currently

```pycon
>>> x = 1
>>> y = 2
>>> t = t"{x} + {y}"
>>> print(repr(t))

```

outputs (1):

```python
Template(strings=('', ' + ', ''), interpolations=(Interpolation(1, 'x', None, ''), Interpolation(2, 'y', None, '')))

```

With the proposed patch it outputs (2):

```python
Template(Interpolation(1, 'x', None, ''), ' + ', Interpolation(2, 'y', None, ''))

```

(1) looks evaluatable, but isn’t, (2) is evaluatable, but that only holds as long as the interpolated values are themselves output in evaluatable form (and only after `from string.templatelib import Template, Interpolation`). So the first question is whether the repr output should include the fully qualified class name (like `datetime.datetime` does) nor not. This would look like this (3):

```python
string.templatelib.Template(string.templatelib.Interpolation(1, 'x', None, ''), ' + ', string.templatelib.Interpolation(2, 'y', None, ''))

```

Another option is to forgo evaluatable output in constructor form and output the t-string in its literal syntax (4):

```python
t'{x} + {y}'

```

but that hides the values of the interpolated expressions.

Or we could drop evaluatable output altogether and use the `<...>` form like this (5):

```python
<Template t'{x} + {y}', x=1, y=2>

```

which looks good when the interpolated values are simple variable references, but not so good, if they are literals, e.g. `t"{[1, 2, 3]} + {'foo'}"` would look like this:

```python
<Template t'{[1, 2, 3]} + {"foo"}', [1, 2, 3]=[1, 2, 3], 'foo'='foo'>

```

What do people think?

---

<div class="post-metadata">

**Author:** ![MegaIng](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/megaing/32/16162_2.png) [@MegaIng](https://discuss.python.org/u/MegaIng)\
**Post date:** [June 17, 2026, 9:39am UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/11 "2026-06-17T09:39:47Z")

</div>

> [@doerwalter](#):
>
> is evaluatable, but that only holds as long as the interpolated values are themselves output in evaluatable form (and only after `from string.templatelib import Template, Interpolation`).

This is the default restriction when outputting evalutable reprs, so these should not be considered drawbacks. Option (2) is always better than Option (1) and (3).

Option (4) looks the most useful for debugging, although I think inlineing the value could also be considered:

`<Template t'{x=1} + {y=2}'>`

That would prevent confusion of the exact same expression is used multipe times (although this is hopefully very rare)🙂

`<Template t'(rand()=4} + {rand()=5}'>` compared to `\<Template t’{rand()} + {rand()}‘, rand()=4, rand()=5\>’

OTOH, Option (4) has the benefit that the template string can be copied out of the terminal and is then valid code, assuming you define the variables. So I think I prefer (4).

---

<div class="post-metadata">

**Author:** ![nedbat](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nedbat/32/8744_2.png) [@nedbat](https://discuss.python.org/u/nedbat)\
**Post date:** [June 17, 2026, 10:13am UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/12 "2026-06-17T10:13:00Z")

</div>

I don’t have a strong opinion among the choices, but I’ll re-iterate: I don’t believe it’s important for the output of repr() to be evaluatable. How often does anyone actually evaluate the output of repr? (rarely). And if they do, how often does it fail because some class somewhere isn’t evaluatable? (often).

The important thing about repr() output is that it be unambiguous and useful to a developer to understand the data. Evaluatability is one way to achieve that, but not the only way.

---

<div class="post-metadata">

**Author:** ![Andrew5057](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/andrew5057/32/35016_2.png) [@Andrew5057](https://discuss.python.org/u/Andrew5057)\
**Post date:** [June 17, 2026, 1:10pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/13 "2026-06-17T13:10:49Z")

</div>

From the [` __repr__ ` docs](https://docs.python.org/3/reference/datamodel.html#object. __repr__ ):

> If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment)

I don’t see much point in relitigating that. Even if we did, I’d imagine we’d come to the conclusion that in this case, an evaluable repr is more information-dense that the alternatives.

---

<div class="post-metadata">

**Author:** ![Andrew5057](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/andrew5057/32/35016_2.png) [@Andrew5057](https://discuss.python.org/u/Andrew5057)\
**Post date:** [June 17, 2026, 1:22pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/14 "2026-06-17T13:22:41Z")

</div>

> [@doerwalter](#):
>
> Or we could drop evaluatable output altogether and use the `<...>` form like this (5):
> 
> ```python
> <Template t'{x} + {y}', x=1, y=2>
> 
> ```
> 
> which looks good when the interpolated values are simple variable references, but not so good, if they are literals, e.g. `t"{[1, 2, 3]} + {'foo'}"` would look like this:
> 
> ```python
> <Template t'{[1, 2, 3]} + {"foo"}', [1, 2, 3]=[1, 2, 3], 'foo'='foo'>
> 
> ```

The literal thing is kind of a game-breaker for me. It’s very confusing to see an invalid identifier on the LHS of an equal sign.

2 and 4 are both much better than 3 IMO; the fully qualified imports seem verbose, and t-strings can have a lot of parts. 2 is somewhat better than 4 since it preserves context; I don’t think we should use a repr that privileges names over values since some applications will care more about the latter than the former.

---

<div class="post-metadata">

**Author:** ![nedbat](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nedbat/32/8744_2.png) [@nedbat](https://discuss.python.org/u/nedbat)\
**Post date:** [June 17, 2026, 1:43pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/15 "2026-06-17T13:43:19Z")

</div>

TBH, I’d be happy to update that section of the docs to clarify the goals of `repr()`. I don’t think it’s ever been common to literally re-evaluate the output of `repr()`. Evaluatability is a means to an end: unambiguous information-rich strings useful to developers.

---

<div class="post-metadata">

**Author:** ![MegaIng](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/megaing/32/16162_2.png) [@MegaIng](https://discuss.python.org/u/MegaIng)\
**Post date:** [June 17, 2026, 2:43pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/16 "2026-06-17T14:43:36Z")

</div>

> [@nedbat](#):
>
> I don’t think it’s ever been common to literally re-evaluate the output of `repr()`.

Do you have any actual evidence for this or is this just your opinion? I regularly make use of this, especially for dataclasses. Primarily when trying to check edge cases for short scripts.

I don’t think a long established policy should be abolished because you feel like it.

---

<div class="post-metadata">

**Author:** ![steve.dower](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steve.dower/32/56_2.png) [@steve.dower](https://discuss.python.org/u/steve.dower)\
**Post date:** [June 17, 2026, 3:22pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/17 "2026-06-17T15:22:24Z")

</div>

> [@MegaIng](#):
>
> Do you have any actual evidence for this or is this just your opinion? I regularly make use of this, especially for dataclasses.

It’s also already the case for all other string types, but I think the implication of the text that’s currently there is that it should be _very_ familiar to a Python developer, to disallow “if we base 64 encode the original bits then it can be perfectly recreated” which is _obviously_ silly, but sometimes we need to write down guidelines to save ourselves from politely explaining how silly some ideas are.

> [@MegaIng](#):
>
> Option (4) looks the most useful for debugging, although I think inlineing the value could also be considered:
> 
> `<Template t'{x=1} + {y=2}'>`

I kind of like this one, though I’m also happy without the inlined values. The “given an appropriate environment” note from the repr docs I think gives us justification for omitting them, but at least for reasonable cases it’s definitely more useful to have them.

---

<div class="post-metadata">

**Author:** ![nedbat](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nedbat/32/8744_2.png) [@nedbat](https://discuss.python.org/u/nedbat)\
**Post date:** [June 17, 2026, 3:45pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/18 "2026-06-17T15:45:45Z")

</div>

> [@MegaIng](#):
>
> I don’t think a long established policy should be abolished because you feel like it.

I’m not talking about forbidding making it evaluatable. I’m talking about clarifying the goal. It wouldn’t change how dataclasses are repr’d. There are many classes now that are not round-trippable through repr/eval, so clearly it’s not a policy. It’s a common way to achieve a goal. If it works to achieve the goal, then make your class evaluatable.

Understanding the goal will help people write better reprs.

---

<div class="post-metadata">

**Author:** ![doerwalter](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/doerwalter/32/329_2.png) [@doerwalter](https://discuss.python.org/u/doerwalter)\
**Post date:** [June 17, 2026, 7:48pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/19 "2026-06-17T19:48:07Z")

</div>

I think the output of `repr()` should be unambigous and should show all relevant parts of the object, so the users know what they’re dealing with. An object with a different value should have a different repr. This is a problem for option (4). If a logfile contained t’{x} + {y}’ relevant information (the values of x and y) would be lost. This is probable the most valuable part of the t-string, since it’s the only variable part, all other parts are found literally in the source code. Of course this is limited: I wouldn’t expect the repr output of an XML element node to dump the whole XML tree. (But then again a large JSON compatible data structure consisting of nested dicst an list would dump the complete tree).

So IMHO for `t"{x} + y{}"` it’s either:

```python
Template(Interpolation(1, 'x', None, ''), ' + ', Interpolation(2, 'y', None, ''))

```

or

```python
<Template t'{x=1} + {y=2}'>

```

And of course we would need to output the conversion and format spec, so it would probably be:

```python
<Template t'{x=1!r:02} + {y=2:x}'>

```

for

```python
t'{x!r:02} + {y:x}'

```

For expressions that are not variables or literals like

```python
t'{x+y} {'foo'} {[1,2,3]}'

```

we would get:

```python
<Template t'{x+y=3} {'foo'='foo'} {[1,2,3]=[1, 2, 3]}'>

```

This looks a bit strange. Option (2) would give

```python
Template(Interpolation(3, 'x+y', None, ''), ' ', Interpolation('foo', "'foo'", None, ''), ' ', Interpolation([1, 2, 3], '[1,2,3]', None, ''))

```

which is much longer but makes it clear, that the interpolated value is whatever type it is, and the expression is a string.

---

<div class="post-metadata">

**Author:** ![loic-simon](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/loic-simon/32/37461_2.png) [@loic-simon](https://discuss.python.org/u/loic-simon)\
**Post date:** [June 17, 2026, 8:57pm UTC](https://discuss.python.org/t/repr-output-of-t-strings/107653/20 "2026-06-17T20:57:48Z")

</div>

I like

```python
Template(Interpolation(1, 'x', None, ''), ' + ', Interpolation(2, 'y', None, ''))

```

most, because we see at a glance both

- the internal reprensentation of the t-string (notably the fact that it’s NOT a string, which can be not obvious to newcommers; I dislike option 4 `t'{x} + {y}'` for this reason);
- the global shape of the string (unlike the current `template=` and `interpolations=`, where we need to mentally intertwine them).

[Next page](https://discuss.python.org/t/repr-output-of-t-strings/107653.md?page=2)
