1 buatlah program Python untuk membuat class mobil dan objek objeknya

Classes atau kelas-kelas menyediakan sarana untuk menggabungkan data dan fungsionalitas bersama. Membuat sebuah class baru menghasilkan objek dengan type baru, memungkinkan dibuat instance baru dari tipe itu. Setiap instance dari class dapat memiliki atribut yang melekat padanya untuk mempertahankan kondisinya. Instance dari sebuah class juga dapat memiliki metode [ditentukan oleh class] untuk memodifikasi kondisinya.

Dibandingkan dengan bahasa pemrograman lain, mekanisme kelas Python menambah kelas dengan minimum sintaksis dan semantik baru. Ini adalah campuran dari mekanisme kelas yang ditemukan dalam C++ dan Modula-3. Kelas Python menyediakan semua fitur standar Pemrograman Berorientasi Objek: mekanisme pewarisan kelas memungkinkan beberapa kelas dasar, kelas turunan dapat menimpa metode apa pun dari kelas dasar atau kelasnya, dan metode dapat memanggil metode kelas dasar dengan nama yang sama . Objek dapat berisi jumlah dan jenis data yang berubah-ubah. Seperti halnya untuk modul, kelas mengambil bagian dari sifat dinamis Python: mereka dibuat pada saat runtime, dan dapat dimodifikasi lebih lanjut setelah pembuatan.

Dalam terminologi C++, biasanya anggota kelas [termasuk anggota data] adalah public [kecuali lihat di bawah ], dan semua fungsi anggota adalah virtual. Seperti dalam Modula-3, tidak ada singkatan untuk merujuk anggota objek dari metodenya: fungsi metode dideklarasikan dengan argumen pertama eksplisit yang mewakili objek, yang diberikan secara implisit oleh panggilan. Seperti dalam Smalltalk, kelas itu sendiri adalah objek. Ini memberikan semantik untuk mengimpor dan mengganti nama. Tidak seperti C++ dan Modula-3, tipe bawaan dapat digunakan sebagai kelas dasar untuk ekstensi oleh pengguna. Juga, seperti di C++, sebagian besar operator bawaan dengan sintaks khusus [operator aritmatika, subscripting dll] dapat didefinisikan ulang untuk instance kelas.

[Kurangnya terminologi yang diterima secara universal untuk berbicara tentang kelas, saya akan sesekali menggunakan istilah Smalltalk dan C++. Saya akan menggunakan istilah Modula-3, karena semantik berorientasi objeknya lebih dekat dengan Python daripada C++, tapi saya berharap bahwa beberapa pembaca pernah mendengarnya.]

9.1. Sepatah Kata Tentang Nama dan Objek

Objek memiliki individualitas, dan banyak nama [dalam berbagai lingkup] dapat terikat ke objek yang sama. Ini dikenal sebagai aliasing dalam bahasa lain. Ini biasanya tidak dihargai pada pandangan pertama pada Python, dan dapat diabaikan dengan aman ketika berhadapan dengan tipe dasar yang tidak dapat diubah [angka, string, tuple]. Namun, aliasing memiliki efek yang mungkin mengejutkan pada semantik kode Python yang melibatkan objek yang bisa berubah seperti daftar list, kamus dictionary, dan sebagian besar jenis lainnya. Ini biasanya digunakan untuk kepentingan program, karena alias berperilaku seperti pointers dalam beberapa hal. Sebagai contoh, melewatkan objek adalah murah karena hanya sebuah pointer dilewatkan oleh implementasi; dan jika suatu fungsi memodifikasi objek yang dilewatkan sebagai argumen, pemanggil akan melihat perubahan --- ini menghilangkan kebutuhan untuk dua mekanisme yang berbeda melewatkan argumen argument passing seperti dalam Pascal.

9.2. Lingkup Python dan Namespaces

Sebelum memperkenalkan kelas, pertama-tama saya harus memberi tahu Anda tentang aturan ruang lingkup scope Python. Definisi kelas memainkan beberapa trik rapi dengan ruang nama namespaces, dan Anda perlu tahu bagaimana ruang lingkup dan ruang nama namespaces bekerja untuk sepenuhnya memahami apa yang terjadi. Kebetulan, pengetahuan tentang subjek ini berguna untuk programmer Python tingkat lanjut.

Mari kita mulai dengan beberapa definisi.

Sebuah namespace adalah pemetaan dari nama ke objek. Sebagian besar ruang nama namespace saat ini diimplementasikan sebagai kamus dictionary Python, tetapi itu biasanya tidak terlihat dengan cara apa pun [kecuali untuk kinerja], dan itu mungkin berubah di masa depan. Contoh ruang nama namespace adalah: himpunan nama bawaan [berisi fungsi seperti , dan nama pengecualian bawaan]; nama-nama global dalam sebuah modul; dan nama-nama lokal dalam pemanggilan fungsi. Dalam arti himpunan atribut suatu objek juga membentuk namespace. Hal penting yang perlu diketahui tentang ruang nama namespace adalah sama sekali tidak ada hubungan antara nama dalam ruang nama namespace yang berbeda; misalnya, dua modul yang berbeda dapat mendefinisikan fungsi

class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
0 tanpa kebingungan --- pengguna modul harus memberikan awalan dengan nama modul.

Ngomong-ngomong, saya menggunakan kata attribute untuk nama apa pun yang mengikuti titik --- misalnya, dalam ekspresi

class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
1,
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
2 adalah atribut dari objek
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
3 . Sebenarnya, referensi ke nama dalam modul adalah referensi atribut: dalam ekspresi
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
4,
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
5 adalah objek modul dan
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
6 adalah atributnya. Dalam kasus ini akan terjadi pemetaan langsung antara atribut modul dan nama global yang didefinisikan dalam modul: mereka berbagi namespace yang sama!

Atribut dapat baca-saja read-only atau dapat ditulis. Dalam kasus terakhir, pemberian nilai ke atribut dimungkinkan. Atribut modul dapat ditulis: Anda dapat menulis

class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
7. Atribut yang dapat ditulis juga dapat dihapus dengan pernyataan . Sebagai contoh,
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
9 akan menghapus atribut
x = MyClass[]
0 dari objek yang dinamai oleh
class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'
5.

Namespace dibuat pada saat yang berbeda dan memiliki masa hidup yang berbeda. Namespace yang berisi nama-nama bawaan dibuat ketika interpreter Python dimulai, dan tidak pernah dihapus. Namespace global untuk modul dibuat ketika definisi modul dibaca; biasanya, namespace modul juga bertahan hingga interpreter berhenti. Pernyataan yang dieksekusi oleh pemanggilan interpreter tingkat atas, baik membaca dari file skrip atau secara interaktif, dianggap sebagai bagian dari modul yang disebut , sehingga mereka memiliki namespace global sendiri. [Nama bawaan sebenarnya juga hidup dalam modul; ini disebut .]

Namespace lokal untuk suatu fungsi dibuat ketika fungsi dipanggil, dan dihapus ketika fungsi kembali returns atau memunculkan pengecualian yang tidak ditangani dalam fungsi tersebut. [Sebenarnya, melupakan akan menjadi cara yang lebih baik untuk menggambarkan apa yang sebenarnya terjadi.] Tentu saja, pemanggilan rekursif masing-masing memiliki ruang-nama namespace lokal mereka sendiri.

Suatu scope adalah wilayah tekstual dari program Python di mana namespace dapat diakses secara langsung. "Directly accessible" di sini berarti bahwa referensi yang tidak memenuhi syarat untuk suatu nama berusaha menemukan nama tersebut di namespace.

Meskipun cakupan scopes ditentukan secara statis, mereka digunakan secara dinamis. Setiap saat selama eksekusi, setidaknya ada 3 atau 4 cakupan bersarang yang ruang nama-nya namespaces dapat diakses secara langsung:

  • ruang lingkup scope terdalam, yang dicari pertama kali, berisi nama-nama lokal

  • lingkup scope dari setiap fungsi penutup, yang dicari dimulai dengan lingkup penutup terdekat, berisi nama-nama non-lokal, tetapi juga non-global

  • lingkup berikutnya next-to-last berisi nama global modul saat ini

  • ruang lingkup scope terluar [dicari terakhir] adalah namespace yang mengandung nama bawaan

Jika sebuah nama dinyatakan global, maka semua referensi dan penugasan langsung ke lingkup scope tengah yang berisi nama global modul. Untuk mengembalikan variabel yang ditemukan di luar cakupan terdalam, pernyataan dapat digunakan; jika tidak dideklarasikan nonlokal, variabel-variabel itu hanya baca-saja [upaya untuk menulis ke variabel seperti itu hanya akan membuat variabel lokal baru dalam cakupan terdalam, membiarkan variabel luar yang dinamai identik tidak berubah].

Biasanya, cakupan lokal merujuk nama lokal dari fungsi [secara tekstual] saat ini. Fungsi luar, lingkup lokal merujuk namespace yang sama dengan lingkup global: namespace modul. Definisi kelas menempatkan namespace lain dalam lingkup lokal.

Penting untuk menyadari bahwa cakupan scope ditentukan secara tekstual: ruang lingkup global dari suatu fungsi yang didefinisikan dalam modul adalah ruang nama namespace modul itu, tidak peduli dari mana atau oleh apa alias fungsi itu dipanggil. Di sisi lain, pencarian nama sebenarnya dilakukan secara dinamis, pada saat run time --- namun, definisi bahasa berkembang menuju resolusi nama statis, pada waktu "compile", jadi jangan mengandalkan resolusi nama dinamis! [Faktanya, variabel lokal sudah ditentukan secara statis.]

Sebuah kekhasan khusus dari Python adalah bahwa -- jika tidak ada pernyataan atau pernyataan yang berlaku -- pemberian nilai untuk nama selalu masuk ke ruang lingkup terdalam. Pemberian nilai tidak menyalin data --- mereka hanya mengikat nama ke objek. Hal yang sama berlaku untuk penghapusan: pernyataan

x = MyClass[]
7 menghapus pengikatan
x = MyClass[]
8 dari namespace yang dirujuk oleh lingkup scope lokal. Bahkan, semua operasi yang memperkenalkan nama-nama baru menggunakan lingkup lokal: khususnya, pernyataan dan definisi fungsi mengikat modul atau nama fungsi di lingkup lokal.

Pernyataan dapat digunakan untuk menunjukkan bahwa variabel tertentu hidup dalam lingkup global dan harus kembali ke sana; pernyataan menunjukkan bahwa variabel tertentu hidup dalam cakupan terlampir dan harus dikembalikan ke sana.

9.2.1. Contoh Lingkup Scopes dan Ruang Nama Namespaces

Ini adalah contoh yang menunjukkan cara mereferensikan lingkup scopes dan ruang nama namespaces yang berbeda, dan bagaimana dan memengaruhi pengikatan variabel:

def scope_test[]:
    def do_local[]:
        spam = "local spam"

    def do_nonlocal[]:
        nonlocal spam
        spam = "nonlocal spam"

    def do_global[]:
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local[]
    print["After local assignment:", spam]
    do_nonlocal[]
    print["After nonlocal assignment:", spam]
    do_global[]
    print["After global assignment:", spam]

scope_test[]
print["In global scope:", spam]

Keluaran dari contoh kode adalah:

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

Perhatikan bagaimana pemberian nilai local [yang bawaan] tidak mengubah scope_tests pengikatan spam. Pemberian nilai mengubah scope_test's pengikatan spam, dan pemberian nilai mengubah pengikatan level modul.

Anda juga dapat melihat bahwa tidak ada pengikatan sebelumnya untuk spam sebelum pemberian nilai .

9.3. Pandangan Pertama tentang Kelas

Kelas memperkenalkan sedikit sintaks baru, tiga tipe objek baru, dan beberapa semantik baru.

9.3.1. Sintaks Definisi Kelas

Bentuk definisi kelas paling sederhana terlihat seperti ini:

class ClassName:
    
    .
    .
    .
    

Definisi kelas, seperti definisi fungsi [pernyataan ] harus dieksekusi sebelum mereka memiliki efek. [Anda dapat menempatkan definisi kelas di cabang dari pernyataan , atau di dalam suatu fungsi.]

Dalam praktiknya, pernyataan di dalam definisi kelas biasanya akan menjadi definisi fungsi, tetapi pernyataan lain diizinkan, dan terkadang berguna --- kami akan kembali ke sini nanti. Definisi fungsi di dalam kelas biasanya memiliki bentuk khusus daftar argumen, didikte oleh konvensi pemanggilan untuk metode --- sekali lagi, ini dijelaskan nanti.

Ketika definisi kelas dimasukkan, namespace baru dibuat, dan digunakan sebagai lingkup scope lokal --- dengan demikian, semua tugas untuk variabel lokal masuk ke namespace baru ini. Secara khusus, definisi fungsi mengikat nama fungsi baru di sini.

Ketika definisi kelas dibiarkan normal [melalui akhir], class object dibuat. Ini pada dasarnya adalah pembungkus di sekitar isi namespace yang dibuat oleh definisi kelas; kita akan belajar lebih banyak tentang objek kelas di bagian selanjutnya. Lingkup scope lokal asli [yang berlaku tepat sebelum definisi kelas dimasukkan] diaktifkan kembali, dan objek kelas terikat di sini dengan nama kelas yang diberikan dalam header definisi kelas [

def __init__[self]:
    self.data = []
9 dalam contoh].

9.3.2. Objek Kelas Class Objects

Objek kelas mendukung dua jenis operasi: referensi atribut dan instansiasi.

Attribute references menggunakan sintaks standar yang digunakan untuk semua referensi atribut dalam Python:

x = MyClass[]
0. Nama atribut yang valid adalah semua nama yang ada di namespace kelas saat objek kelas dibuat. Jadi, jika definisi kelas tampak seperti ini:

class MyClass:
    """A simple example class"""
    i = 12345

    def f[self]:
        return 'hello world'

kemudian

x = MyClass[]
1 dan
x = MyClass[]
2 adalah referensi atribut yang valid, masing-masing mengembalikan integer dan objek fungsi. Atribut kelas juga dapat ditetapkan, sehingga Anda dapat mengubah nilai
x = MyClass[]
1 oleh penugasan.
x = MyClass[]
4 juga merupakan atribut yang valid, mengembalikan docstring milik kelas:
x = MyClass[]
5.

instantiation kelas menggunakan notasi fungsi. Hanya berpura-pura bahwa objek kelas adalah fungsi tanpa parameter yang mengembalikan instance baru dari kelas. Misalnya [dengan asumsi kelas di atas]:

x = MyClass[]

membuat instance baru dari kelas dan menetapkan objek ini ke variabel lokal

x = MyClass[]
8.

Operasi instansiasi ["calling" objek kelas] membuat objek kosong. Banyak kelas suka membuat objek dengan instance yang disesuaikan dengan kondisi awal tertentu. Oleh karena itu sebuah kelas dapat mendefinisikan metode khusus bernama , seperti ini:

def __init__[self]:
    self.data = []

Ketika sebuah kelas mendefinisikan metode , instantiasi kelas secara otomatis memanggil untuk instance kelas yang baru dibuat. Jadi dalam contoh ini, contoh baru yang diinisialisasi dapat diperoleh oleh:

x = MyClass[]

Tentu saja, metode mungkin memiliki argumen untuk fleksibilitas yang lebih besar. Dalam hal itu, argumen yang diberikan kepada operator instantiasi kelas diteruskan ke . Sebagai contoh,

>>> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]

9.3.3. Objek Instance

Sekarang apa yang bisa kita lakukan dengan objek instan? Satu-satunya operasi yang dipahami oleh objek instan adalah referensi atribut. Ada dua jenis nama atribut yang valid: atribut data, dan metode.

data attributes sesuai dengan "variabel instan" di Smalltalk, dan "data members" di C++. Atribut data tidak perlu dinyatakan; seperti variabel lokal, mereka muncul ketika mereka pertama kali ditugaskan. Misalnya, jika

x = MyClass[]
8 adalah turunan dari
>>> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
3 yang dibuat di atas, bagian kode berikut akan mencetak nilai
>>> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
4, tanpa meninggalkan jejak:

x.counter = 1
while x.counter >> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
5 adalah referensi metode yang valid, karena
x = MyClass[]
2 adalah fungsi, tetapi
>>> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
7 tidak, karena
x = MyClass[]
1 tidak. Tetapi
>>> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
5 bukan hal yang sama dengan
x = MyClass[]
2 --- itu adalah method object, bukan objek fungsi.

9.3.4. Metode Objek

Biasanya, metode dipanggil tepat setelah itu terikat:

x.f[]

Dalam contoh

>>> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
3, ini akan mengembalikan string
x.counter = 1
while x.counter >> class Complex:
...     def __init__[self, realpart, imagpart]:
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex[3.0, -4.5]
>>> x.r, x.i
[3.0, -4.5]
5 adalah metode objek, dan dapat disimpan dan dipanggil di lain waktu. Sebagai contoh:

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
0

akan terus mencetak

x.counter = 1
while x.counter 

Bài mới nhất

Chủ Đề