Apa arti dari atribut dunder __total__ dalam Python 3?

17

Di Python 3.8 yang baru dirilis ada anotasi tipe baru typing.TypedDict. Dokumentasinya menyebutkan itu

Info jenis untuk introspeksi dapat diakses melalui Point2D.__annotations__dan Point2D.__total__. [....]

Meskipun __annotations__terkenal, telah diperkenalkan di PEP 3107 , saya tidak dapat menemukan informasi apa pun tentang __total__. Adakah yang bisa menjelaskan maknanya dan jika mungkin menghubungkan ke sumber-sumber resmi?

Antti Haapala
sumber
4
Khas. 99% typinginternal tidak didokumentasikan, dan bagian yang didokumentasikan dengan buruk.
Aran-Fey

Jawaban:

3

Saya menduga bahwa __total__bidang menandakan apakah instance harus lengkap (default) atau tidak (semua bidang opsional). Saya memulai pencarian saya di PEP 589 , yang memperkenalkan TypedDictdan menjelaskan totalitas seperti itu. Itu menggunakan totalargumen, yang masuk akal untuk mengubah nama dunder-style untuk class sintaks. Namun, saya tidak menemukan kapan penggantian nama terjadi.

Melihat ke MyPy, yang merupakan pemeriksa tipe aktual yang peduli dengan anotasi ini, ada dokumentasi TypedDictdan totalitas yang serupa , tetapi sekali lagi tidak ada referensi ke sintaksis bawah. Menggali penerapannya menyebabkan lebih banyak kebingungan, seperti TypedDictTypepada types.py tidak memiliki bidang total, tetapi terpisah itemsdan required_keys. Totalitas akan menyiratkan bahwa items.keys()==required_keystetapi implementasi membuat asumsi yang berbeda, seperti can_be_falsemengandalkan itemssendirian. total=Falseseharusnya pada prinsipnya berarti required_keyskosong.

Sumber CPython untuk _TypedDictMeta setidaknya mengungkapkan bahwa totalargumen dan __total__dunder adalah satu dan sama, meskipun sumber menggambarkan TypedDictdirinya sebagai "dapat ditambahkan segera".

Yann Vernier
sumber
Menerima ini untuk saat ini - jika bukan hal lain, mungkin itu akan membuat orang lain lebih bersedia untuk maju dan menyangkal jawaban Anda: D
Antti Haapala
Saya pribadi curiga can_be_falsemasalahnya adalah bug MyPy, mungkin terkait dengan tidak merencanakan memiliki bidang opsional sejak awal.
Yann Vernier
1

TypedDictditerima dengan Python 3.8 melalui PEP 589 . Dari Python, tampaknya __total__bendera boolean disetel ke Truedefault:

tot = TypedDict.__total__
print(type(tot))
print(tot)

# <class 'bool'>
# True

Seperti disebutkan dalam posting lain, perincian tentang metode ini terbatas dalam dokumen , tetapi tautan @Yann Vernier ke kode sumber CPython sangat menyarankan __total__terkait dengan totalkata kunci baru yang diperkenalkan dengan Python 3.8 :

# cypthon/typing.py

class _TypedDictMeta(type):
    def __new__(cls, name, bases, ns, total=True):
        """Create new typed dict class object.
        ...
        """
        ...
        if not hasattr(tp_dict, '__total__'):
            tp_dict.__total__ = total
        ...

Bagaimana cara kerjanya?

Sinopsis : secara default, semua kunci diperlukan saat instantiasi yang ditentukan TypedDict. total=Falsemengesampingkan pembatasan ini dan memungkinkan kunci opsional. Lihat demonstrasi berikut.

Diberikan

Pohon direktori pengujian:

masukkan deskripsi gambar di sini

Kode

File dalam direktori tes:

# rgb_bad.py

from typing import TypedDict


class Color(TypedDict):
    r: int
    g: int
    b: int
    a: float


blue = Color(r=0, g=0, b=255)                     # missing "a"

# rgb_good.py

from typing import TypedDict


class Color(TypedDict, total=False):
    r: int
    g: int
    b: int
    a: float


blue = Color(r=0, g=0, b=255)                     # missing "a"

Demo

Jika kunci tidak ada, mypy akan mengeluh di commandline:

> mypy code/rgb_bad.py
code\rgb_bad.py:11: error: Key 'a' missing for TypedDict "Color"
...

Pengaturan total=Falsememungkinkan kunci opsional:

> mypy code/rgb_good.py
Success: no issues found in 1 source file

Lihat juga

  • Tweet oleh R. Hettinger menunjukkan totalitas
  • Bagian PEP tentang totalitas dalam PEP 589
  • Bagian Artikel tentang jenis dan TypedDictdalam Python 3.8 oleh Real Python
  • typing-extensionspaket untuk digunakan TypedDictdalam Python 3.5, 3.6
pylang
sumber