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 class
objek 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 Bookshelf
, Library
, Warehouse
, 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 menggunakandefault
jika anda a) gunakanfield
untuk mengubah parameter lain untuk bidang tersebut, dan b) anda ingin menetapkan nilai lalai pada bidang di atasnya. Dalam kes ini kita gunakandefault
untuk menetapkanweight
ke0.0
.default_factory
: Menyediakan nama fungsi, yang tidak memerlukan parameter, yang mengembalikan beberapa objek untuk dijadikan nilai lalai untuk bidang. Dalam kes ini, kami mahuchapters
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 menggunakannyarepr=False
untuk menghilangkannya.compare
: Secara lalai (True
), merangkumi bidang dalam kaedah perbandingan yang dihasilkan secara automatik untuk kelas data. Di sini, kami tidak mahucondition
dijadikan bahagian perbandingan untuk dua buku, jadi kami menetapkancompare=
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 condition
semasa 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)