Pemformatan string mendukung strifying implisit. Namun, penentu format string tampaknya tidak kompatibel dengan ini, hanya objek str eksplisit (terlepas dari penggunaan type=s). Saya tidak dapat menemukan perilaku ini didokumentasikan di mana pun tanpa menarik kode cpython. instal default ubuntu 20.04 python3.8. menggunakan panggilan str() eksplisit bisa diterapkan tetapi tidak terlalu bersih terutama dalam kasus penggunaan saya di mana sekarang liter kode.

obj = object()
explicit = str(obj)
print(f"{explicit:.5}")
print(f"{obj}")
print(f"{obj:.5}") # TypeError: unsupported format string passed to object.__format__

Pertanyaan:

  • Sudahkah saya menafsirkan ini dengan benar?
  • di mana saya harus mencari untuk mendapatkan info ini sendiri (jika ada di luar kode cpython), dan
  • apakah ada cara untuk mencapai penentu format {:...} sambil mengandalkan str()ifikasi implisit?
0
some bits flipped 7 Januari 2021, 18:40

3 jawaban

Jawaban Terbaik

Anda bisa mengimplementasikan metode __format__ di kelas objek Anda atau menempatkan str() secara langsung dalam format string:

print(f"{str(obj):.5}")

Lihat PEP 498 untuk detailnya.

perhatikan bahwa f"{obj!s:.5}" juga berfungsi tetapi, dalam spesifikasi yang sama, !s dan !r dianggap berlebihan dan hanya dipertahankan untuk kompatibilitas mundur

2
Alain T. 7 Januari 2021, 16:14

Ini berfungsi jika Anda secara eksplisit meminta konversi string:

>>> print(f"{obj!s:.5}")
<obje

Di balik layar, saya menduga bahwa hasil ekspresi tidak diteruskan ke str terlebih dahulu, melainkan ke format:

>>> format(obj, "%s")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to object.__format__

Dalam hal ini, object.__format__ sendiri tidak secara otomatis melakukan konversi ke string menggunakan object.__str__, untuk alasan apa pun.

1
chepner 7 Januari 2021, 15:50

Dari sumber C

/* Issue 7994: If we're converting to a string, we
   should reject format specifications */

Masalah objek.format harus menolak string format berpendapat bahwa objek dasar dari mana semua objek lain yang terbentuk tidak boleh berasumsi bahwa itu adalah hal seperti string yang mendukung penentu string. Penentu format adalah tipe spesifik sehingga induk dari semua tipe tidak dapat membuat penilaian apa pun tentangnya. Itu harus melemparkan dirinya ke salah satu subtipenya yang tidak memiliki formatter, tetapi yang mana?

Contoh yang menarik adalah kelas yang ditentukan pengguna yang tidak mengimplementasikan formatter dan menggunakan default.

>>> class Foo:
...     pass
... 
>>> foo = Foo()
>>> f"{foo:.5}"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to Foo.__format__

Untuk mendapatkan hasil yang Anda inginkan, object.__format__ harus memanggil foo.__str__().__format__(the_specifier) tapi itu hal yang aneh untuk dilakukan. Mengapa harus menganggap bahwa pemformat string adalah hal yang benar untuk diterapkan di sini? Mengapa tidak __repr__ saja? Objeknya jelas tidak menginginkan spesifikasi format yang bau, jadi jangan berikan itu.

Solusinya adalah memberikan konversi string eksplisit terlebih dahulu

f"{obj!s:.5}"
1
tdelaney 7 Januari 2021, 16:21