Cara menggunakan cermin mata hitam Python

Semua yang ada di Python adalah objek, atau pepatah. Sekiranya anda ingin membuat objek tersuai anda sendiri, dengan sifat dan kaedahnya sendiri, anda menggunakan classobjek Python untuk mewujudkannya. Tetapi membuat kelas di Python kadang-kadang bererti menulis banyak kod pelat berulang untuk mengatur contoh kelas dari parameter yang dilaluinya atau membuat fungsi umum seperti operator perbandingan.

Dataclasses, diperkenalkan dalam Python 3.7 (dan disokong oleh Python 3.6), memberikan cara yang berguna untuk menjadikan kelas kurang verbose. Banyak perkara biasa yang anda lakukan dalam kelas, seperti memberi contoh sifat dari argumen yang dihantar ke kelas, boleh dikurangkan kepada beberapa petunjuk asas.

Contoh pacar data Python

Berikut adalah contoh ringkas kelas konvensional di Python:

Buku kelas:

'' 'Objek untuk melacak buku fizikal dalam koleksi.' ''

def __init __ (diri, nama: str, berat: apungan, rak_id: int = 0):

diri.nama = nama

self.weight = berat # dalam gram, untuk mengira penghantaran

self.shelf_id = shelf_id

def __repr __ (diri):

kembali (f "Buku (nama = {self.name! r},

berat = {self.weight! r}, shelf_id = {self.shelf_id! r}) ")

Sakit kepala yang paling besar di sini adalah cara setiap argumen yang disampaikan  __init__ harus disalin ke sifat objek. Ini tidak begitu buruk jika anda hanya berurusan dengan  Book, tetapi bagaimana jika anda perlu berurusan dengan  BookshelfLibraryWarehouse, dan sebagainya? Selain itu, semakin banyak kod yang perlu anda ketik dengan tangan, semakin besar kemungkinan anda melakukan kesalahan.

Berikut adalah kelas Python yang sama, dilaksanakan sebagai kelas data Python:

dari dataclasses import dataclass @dataclass class Book: '' 'Objek untuk mengesan buku fizikal dalam koleksi.' '' name: str weight: float shelf_id: int = 0 

Apabila anda menentukan sifat, dipanggil  medan,  dalam dataclass,  @dataclass secara automatik menghasilkan semua kod yang diperlukan untuk memulakannya. Ia juga menyimpan maklumat jenis untuk setiap harta tanah, jadi jika anda menggunakan kod penyekat seperti itu  mypy, ia akan memastikan bahawa anda membekalkan jenis pemboleh ubah yang betul kepada pembina kelas.

Perkara lain yang  @dataclass dilakukan di belakang tabir adalah membuat kod secara automatik untuk sebilangan kaedah dunder biasa di kelas. Dalam kelas konvensional di atas, kita harus membuat kelas sendiri  __repr__. Dalam kelas data, ini tidak perlu; @dataclass menjana  __repr__ untuk anda.

Sebaik sahaja dataclass dibuat, fungsi ini serupa dengan kelas biasa. Tidak ada penalti prestasi untuk menggunakan dataclass, kecuali overhead minimum penghias ketika menyatakan definisi kelas.

Sesuaikan medan kelas Python dengan  field fungsinya

Cara kerja kacamata data lalai semestinya sesuai untuk kebanyakan kes penggunaan. Namun, kadangkala, anda perlu memperincikan bagaimana bidang dalam dataclass anda dimulakan. Untuk melakukan ini, anda boleh menggunakan  field fungsi tersebut.

dari dataclass import dataclass, bidang dari menaip import List @dataclass class Book: '' 'Objek untuk mengesan buku fizikal dalam koleksi.' '' name: str condition: str = field (bandingkan = False) weight: float = field (default = 0.0, repr = False) shelf_id: int = 0 bab: List [str] = medan (default_factory = senarai) 

Apabila anda menetapkan nilai lalai ke sebuah contoh  field, itu akan mengubah cara bidang disiapkan bergantung pada parameter apa yang anda berikan  field. Ini adalah pilihan yang paling biasa digunakan field (ada yang lain):

  • default: Menetapkan nilai lalai untuk medan. Anda perlu menggunakan defaultjika anda a) gunakan  field untuk mengubah parameter lain untuk bidang tersebut, dan b) anda ingin menetapkan nilai lalai pada bidang di atasnya. Dalam kes ini kita gunakan  default untuk menetapkan  weight ke  0.0.
  • default_factory: Menyediakan nama fungsi, yang tidak memerlukan parameter, yang mengembalikan beberapa objek untuk dijadikan nilai lalai untuk bidang. Dalam kes ini, kami mahu  chapters menjadi senarai kosong.
  • repr: Secara lalai ( True), mengawal jika bidang yang dimaksudkan muncul dalam kelas data yang dihasilkan secara automatik  __repr__ . Dalam kes ini, kami tidak mahu berat buku tersebut ditunjukkan  __repr__, jadi kami menggunakannya  repr=False untuk menghilangkannya.
  • compare: Secara lalai ( True), merangkumi bidang dalam kaedah perbandingan yang dihasilkan secara automatik untuk kelas data. Di sini, kami tidak mahu  condition dijadikan bahagian perbandingan untuk dua buku, jadi kami menetapkan  compare=False.

Perhatikan bahawa kita harus menyesuaikan urutan bidang supaya bidang bukan lalai menjadi yang pertama.

Gunakan  __post_init__ untuk mengawal inisialisasi Pacon data

Pada ketika ini anda mungkin tertanya-tanya: Sekiranya  __init__ kaedah dari sebuah dataclass dihasilkan secara automatik, bagaimana saya dapat mengawal proses init untuk membuat perubahan yang lebih halus?

Masukkan  __post_init__ kaedah. Sekiranya anda memasukkan  __post_init__kaedah dalam definisi dataclass anda, anda boleh memberikan arahan untuk mengubah medan atau data contoh lain.

dari dataclass import dataclass, bidang dari menaip import List @dataclass class Book: '' 'Objek untuk mengesan buku fizikal dalam koleksi.' '' name: str weight: float = field (default = 0.0, repr = False) shelf_id: int = medan (init = False) bab: List [str] = field (default_factory = list) condition: str = field (default = "Good", bandingkan = False) def __post_init __ (self): if self.condition == "Dibuang ": self.shelf_id = Tiada lain: self.shelf_id = 0 

Dalam contoh ini, kami telah mencipta satu  __post_init__ kaedah untuk menetapkan shelf_id untuk  None jika keadaan buku ini dimulakan sebagai  "Discarded". Nota cara kami menggunakan  field untuk memulakan  shelf_id, dan lulus  init sebagai  False untuk  field. Ini bermaksud  shelf_id tidak akan dimulakan dalam  __init__.

Gunakan  InitVar untuk mengawal inisialisasi Pacon data

Cara lain untuk menyesuaikan penyediaan dataclass Python adalah menggunakan  InitVar jenisnya. Ini membolehkan anda menentukan medan yang akan diteruskan ke  __init__ dan kemudian ke  __post_init__, tetapi tidak akan disimpan dalam contoh kelas.

Dengan menggunakan InitVar, Anda dapat mengambil parameter ketika menyiapkan dataclass yang hanya digunakan selama inisialisasi. Satu contoh:

dari dataclasses import dataclass, field, InitVar dari menaip import List @dataclass class Book: '' 'Objek untuk mengesan buku fizikal dalam koleksi.' '' name: str condition: InitVar [str] = Tiada berat: float = field (lalai = 0.0, repr = False) shelf_id: int = field (init = False) bab: List [str] = field (default_factory = list) def __post_init __ (self, condition): if condition == "Dibuang": self.shelf_id = Tiada yang lain: self.shelf_id = 0 

Menetapkan jenis medan ke  InitVar (dengan subjenisnya menjadi jenis bidang yang sebenarnya) memberi isyarat  @dataclass untuk tidak menjadikan bidang itu menjadi bidang dataclass, tetapi untuk meneruskan data  __post_init__ sebagai argumen.

Dalam versi  Book kelas ini, kami tidak menyimpan  condition sebagai medan dalam contoh kelas. Kami hanya menggunakan conditionsemasa peringkat permulaan. Jika kita mendapati bahawa  condition bakal  "Discarded", kami menetapkan  shelf_id untuk  None - tetapi kami tidak menyimpan  condition dalam contoh kelas.

Bila hendak menggunakan cermin mata hitam Python - dan bila tidak menggunakannya

Salah satu senario yang biasa digunakan untuk menggunakan kacamata data adalah sebagai pengganti nama yang dinamakan. Kacamata data menawarkan tingkah laku yang sama dan banyak lagi, dan ia boleh dibuat tidak berubah (seperti disebut nama) dengan hanya menggunakan  @dataclass(frozen=True) sebagai penghias.

Another possible use case is replacing nested dictionaries, which can be clumsy to work with, with nested instances of dataclasses. If you have a dataclass Library, with a list property shelves, you could use a dataclass ReadingRoom to populate that list, and then add methods to make it easy to access nested items (e.g., a book on a shelf in a particular room).

But not every Python class needs to be a dataclass. If you’re creating a class mainly as a way to group together a bunch of static methods, rather than as a container for data, you don’t need to make it a dataclass. For instance, a common pattern with parsers is to have a class that takes in an abstract syntax tree, walks the tree, and dispatches calls to different methods in the class based on the node type. Because the parser class has very little data of its own, a dataclass isn’t useful here.

How to do more with Python

  • Get started with async in Python
  • How to use asyncio in Python
  • How to use PyInstaller to create Python executables
  • Cython tutorial: How to speed up Python
  • How to install Python the smart way
  • How to manage Python projects with Poetry
  • How to manage Python projects with Pipenv
  • Virtualenv dan venv: Persekitaran maya Python dijelaskan
  • Python virtualenv dan venv lakukan dan tidak boleh dilakukan
  • Penjelasan dan proses subtitle Python dijelaskan
  • Cara menggunakan debugger Python
  • Cara menggunakan timeit untuk profil kod Python
  • Cara menggunakan cProfile untuk profil kod Python
  • Cara menukar Python ke JavaScript (dan kembali lagi)