Это потому, что вы передаете выражение генератора в качестве аргумента методу join
( см. Этот бит документации и этот бит ).
Когда выражение такого типа используется в качестве аргумента для вызова, вы можете опустить скобки.
Если вы заключите выражение в скобки в интерпретаторе Python, вы увидите что-то как это:
>>> ('<%s>%s</%s>' % (tag, content, tag) for tag, content in {'b': 'bold'}.items())
<generator object <genexpr> at 0x7f2ab9b044f8>
Обратите внимание, что вы можете подтвердить, что вам не нужны скобки, если они являются частью аргумента для вызова, например:
>>> type('<%s>%s</%s>' % (tag, content, tag) for tag, content in {'b': 'bold'}.items())
<class 'generator'>
Из официальной документации :
Примеры итераций включают в себя все типы последовательностей (например, list, str и tuple) и некоторые непоследовательные типы, такие как dict, файловые объекты [...] Итерации можно использовать в a для l oop и во многих других местах, где требуется последовательность [...] См. Также итератор, последовательность и генератор.