Bab ini diambil dari buku A Primer on Scientific Programming with Python oleh H. P. Langtangen, edisi ke-5, Springer, 2016
Kelas dapat digunakan untuk banyak hal dalam komputasi ilmiah, tetapi salah satu tugas pemrograman yang paling sering dilakukan adalah merepresentasikan fungsi matematika yang memiliki sekumpulan parameter selain satu atau lebih variabel independen. Bagian ini menjelaskan mengapa fungsi matematika seperti itu menimbulkan kesulitan bagi pemrogram, dan bagian ini menunjukkan bagaimana ide kelas mengatasi kesulitan ini. Bagian menyajikan contoh lain di mana kelas mewakili fungsi matematika. Materi lebih lanjut tentang kelas, yang bagi beberapa pembaca mungkin mengklarifikasi ide, tetapi juga dapat dilewati dalam bacaan pertama, muncul di bagian dan bagian
Tantangan. fungsi dengan parameter
Untuk memotivasi konsep kelas, kita akan melihat fungsi dengan parameter. Salah satu contohnya adalah \[ y[t]=v_0t-\frac{1}{2}gt^2 \]. Secara konseptual, dalam fisika, besaran \[ y \] dipandang sebagai fungsi dari \[ t \], tetapi \[ y \] juga bergantung pada dua parameter lain, \[ v_0 \] dan \[ g \], meskipun . Kita dapat menulis \[ y[t;v_0,g] \] untuk menunjukkan bahwa \[ t \] adalah variabel independen, sedangkan \[ v_0 \] dan \[ g \] adalah parameter. Sebenarnya, \[ g \] adalah parameter tetap [selama kita berada di permukaan bumi dan dapat melihat \[ g \] sebagai konstanta], jadi hanya \[ v_0 \] dan \[ t \] yang dapat . Maka akan lebih baik untuk menulis \[ y[t;v_0] \]
Dalam kasus umum, kita mungkin memiliki fungsi \[ x \] yang memiliki \[ n \] parameter \[ p_1,\ldots,p_n \]. \[ f[x; p_1,\ldots,p_n] \]. Salah satu contohnya adalah $$ \begin{equation*} g[x; A, a] = Ae^{-ax} \thinspace. \end{equation*} $$
Bagaimana seharusnya kita mengimplementasikan fungsi seperti itu?
def y[t, v0]: g = 9.81 return v0*t - 0.5*g*t**2 def g[x, a, A]: return A*exp[-a*x]
Masalah
Ada satu masalah besar dengan solusi ini. Banyak perangkat lunak yang dapat kita gunakan untuk operasi matematika pada fungsi dengan asumsi bahwa fungsi dari satu variabel hanya memiliki satu argumen dalam representasi komputer dari fungsi tersebut. Misalnya, kita mungkin memiliki alat untuk membedakan fungsi \[ f[x] \] pada titik \[ x \], menggunakan pendekatan $$ \begin{equation} f'[x]\approx {f[x
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_
Fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]_1 bekerja dengan fungsi apa pun
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]2 yang membutuhkan satu argumen
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_
Sayangnya,
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]_1 tidak akan berfungsi dengan fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]4 kami. Memanggil
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]_5 menyebabkan kesalahan di dalam fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]1, karena ia mencoba memanggil fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 kami hanya dengan satu argumen sedangkan fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 membutuhkan dua
Menulis fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]1 alternatif untuk
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]2 fungsi yang memiliki dua argumen adalah solusi yang buruk karena membatasi himpunan fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]2 yang dapat diterima untuk kasus yang sangat khusus dari suatu fungsi dengan satu variabel independen dan satu parameter. Prinsip dasar dalam pemrograman komputer adalah mengusahakan perangkat lunak yang dapat diterapkan secara umum dan seluas mungkin. Dalam kasus ini, itu berarti bahwa fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]_1 harus berlaku untuk semua fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]2 dari satu variabel, dan membiarkan
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]2 mengambil satu argumen maka keputusan alami untuk dibuat
Ketidaksesuaian argumen fungsi, seperti diuraikan di atas, merupakan masalah utama karena banyak pustaka perangkat lunak tersedia untuk operasi fungsi matematika dari satu variabel. integrasi, diferensiasi, penyelesaian \[ f[x]=0 \], menemukan ekstrem, dll. Semua pustaka ini akan mencoba memanggil fungsi matematika yang kami berikan hanya dengan satu argumen. Saat fungsi kita memiliki lebih banyak argumen, kode di dalam pustaka membatalkan panggilan ke fungsi kita, dan kesalahan semacam itu mungkin tidak selalu mudah dilacak
Solusi yang buruk. variabel global
Persyaratannya adalah untuk mendefinisikan implementasi Python dari fungsi matematika dari satu variabel dengan satu argumen, variabel independen. Kedua contoh di atas kemudian harus diimplementasikan sebagai
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]
Fungsi-fungsi ini hanya berfungsi jika
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5,
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]6, dan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]7 adalah variabel global, diinisialisasi sebelum seseorang mencoba memanggil fungsi. Berikut adalah dua contoh panggilan di mana
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]1 membedakan
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]
Penggunaan variabel global secara umum dianggap pemrograman yang buruk. Mengapa variabel global bermasalah dalam kasus ini dapat diilustrasikan ketika ada kebutuhan untuk bekerja dengan beberapa versi fungsi. Misalkan kita ingin bekerja dengan dua versi \[ y[t;v_0] \], satu dengan \[ v_0=1 \] dan satu lagi dengan \[ v_0=5 \]. Setiap kali kita memanggil
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 kita harus mengingat versi fungsi mana yang kita gunakan, dan mengatur
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 sesuai sebelum panggilan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]
Masalah lain adalah bahwa variabel dengan nama sederhana seperti
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5,
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_7, dan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]6 dapat dengan mudah digunakan sebagai variabel global di bagian lain dari program. Bagian ini dapat mengubah
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 kami dalam konteks yang berbeda dari fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7, tetapi perubahan tersebut memengaruhi kebenaran fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7. Dalam kasus seperti itu, kami mengatakan bahwa mengubah
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 memiliki efek samping, yaitu. e. , perubahan memengaruhi bagian lain dari program dengan cara yang tidak disengaja. Inilah salah satu alasan mengapa aturan emas pemrograman memberi tahu kita untuk membatasi penggunaan variabel global sebanyak mungkin
Solusi lain untuk masalah kebutuhan dua \[ v_0 \] parameter bisa dengan memperkenalkan dua fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7, masing-masing dengan parameter \[ v_0 \] yang berbeda
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**2
Sekarang kita perlu menginisialisasi
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**21 dan
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**22 sekali, dan kemudian kita dapat bekerja dengan
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**23 dan
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**24. Namun, jika kita membutuhkan 100 \[ v_0 \] parameter, kita membutuhkan 100 fungsi. Ini membosankan untuk kode, rawan kesalahan, sulit dikelola, dan hanya solusi yang sangat buruk untuk masalah pemrograman
Jadi, apakah ada obat yang bagus? . konsep kelas memecahkan semua masalah yang dijelaskan di atas
Mewakili fungsi sebagai kelas
Kelas berisi sekumpulan variabel [data] dan sekumpulan fungsi, yang disatukan sebagai satu unit. Variabel terlihat di semua fungsi di kelas. Artinya, kita dapat melihat variabel sebagai "global" dalam fungsi ini. Karakteristik ini juga berlaku untuk modul, dan modul dapat digunakan untuk mendapatkan banyak keuntungan yang sama seperti yang ditawarkan kelas [lihat komentar di bagian ]. Namun, kelas secara teknis sangat berbeda dari modul. Anda juga dapat membuat banyak salinan dari sebuah kelas, sementara hanya ada satu salinan dari sebuah modul. Ketika Anda menguasai modul dan kelas, Anda akan melihat dengan jelas persamaan dan perbedaannya. Sekarang kita lanjutkan dengan contoh spesifik dari sebuah kelas
Pertimbangkan fungsi \[ y[t; v_0]=v_0t - \frac{1}{2}gt^2 \]. Kita dapat mengatakan bahwa \[ v_0 \] dan \[ g \], diwakili oleh variabel
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20, merupakan data. Fungsi Python, misalnya
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**2_7, diperlukan untuk menghitung nilai \[ y[t;v_0] \] dan fungsi ini harus memiliki akses ke data
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20, sementara
'v0*t - 0.5*g*t**2; v0=%g' % self.v00 adalah argumen
Seorang programmer berpengalaman dengan kelas kemudian akan menyarankan untuk mengumpulkan data
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20, dan fungsi
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**27, bersama-sama sebagai sebuah kelas. Selain itu, sebuah kelas biasanya memiliki fungsi lain yang disebut konstruktor untuk menginisialisasi data. Konstruktor selalu bernama
'v0*t - 0.5*g*t**2; v0=%g' % self.v04. Setiap kelas harus memiliki nama, seringkali dimulai dengan huruf besar, jadi kami memilih
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 sebagai nama karena kelas mewakili fungsi matematika dengan nama \[ y \]. Gambar sketsa isi kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 sebagai apa yang disebut diagram UML, di sini dibuat dengan bantuan program class_Y_v1_UML. py. Diagram UML memiliki dua "kotak", satu tempat mencantumkan fungsi, dan satu lagi tempat mencantumkan variabel. Langkah kita selanjutnya adalah mengimplementasikan kelas ini dengan Python
Gambar 1. Diagram UML dengan fungsi dan data di kelas sederhana
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 untuk merepresentasikan fungsi matematika \[ y[t;v_0] \]
Penerapan
Kode lengkap untuk kelas kita
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 terlihat seperti berikut dengan Python
class Y: def __init__[self, v0]: self.v0 = v0 self.g = 9.81 def value[self, t]: return self.v0*t - 0.5*self.g*t**2
Kebingungan bagi pendatang baru di kelas Python adalah parameter
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 , yang mungkin memerlukan upaya dan waktu untuk memahami sepenuhnya
Penggunaan dan diseksi
Sebelum kita menggali apa arti setiap baris dalam implementasi kelas, kita mulai dengan menunjukkan bagaimana kelas dapat digunakan untuk menghitung nilai fungsi matematika \[ y[t;v_0] \]
Kelas membuat tipe data baru, di sini namanya
'v0*t - 0.5*g*t**2; v0=%g' % self.v05, jadi ketika kita menggunakan kelas untuk membuat objek, objek tersebut bertipe
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. [Sebenarnya, semua objek Python standar, seperti daftar, tupel, string, angka titik-mengambang, bilangan bulat, dll. , adalah kelas Python bawaan, dengan nama
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v02,
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v03,
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v04,
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v05,
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v06, dll. ] Objek dari kelas yang ditentukan pengguna [seperti
'v0*t - 0.5*g*t**2; v0=%g' % self.v05] biasanya disebut instance. Kami membutuhkan contoh seperti itu untuk menggunakan data di kelas dan memanggil fungsi
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08. Pernyataan berikut membuat instance yang terikat pada nama variabel
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7
Tampaknya, kita memanggil kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 seolah-olah itu adalah sebuah fungsi. Sebenarnya,
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_01 secara otomatis diterjemahkan oleh Python ke panggilan ke konstruktor
'v0*t - 0.5*g*t**2; v0=%g' % self.v04 di kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. Argumen dalam panggilan, di sini hanya nomor
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h04, selalu diteruskan sebagai argumen ke
'v0*t - 0.5*g*t**2; v0=%g' % self.v04 setelah argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09. Artinya,
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_5 mendapatkan nilai
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h04 dan
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 baru saja dijatuhkan dalam panggilan. Ini mungkin membingungkan, tetapi merupakan aturan bahwa argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 tidak pernah digunakan dalam pemanggilan fungsi di kelas
Dengan contoh
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7, kita dapat menghitung nilai \[ y[t=0. 1;v_0=3] \] dengan pernyataan
Di sini juga, argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 dijatuhkan dalam panggilan ke
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08. Untuk mengakses fungsi dan variabel di kelas, kita harus mengawali nama fungsi dan variabel dengan nama instance dan titik. fungsi
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v0_8 dicapai sebagai
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h15, dan variabel dicapai sebagai
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h16 dan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h17. Kita dapat, misalnya, mencetak nilai
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dalam contoh
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 dengan menulis
Keluaran dalam hal ini adalah
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_04
Kami telah memperkenalkan istilah "contoh" untuk objek kelas. Fungsi dalam kelas biasa disebut metode, dan variabel [data] dalam kelas disebut atribut data. Metode juga dikenal sebagai atribut metode. Mulai sekarang kita akan menggunakan terminologi ini. Di kelas sampel kami
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 kami memiliki dua metode atau atribut metode,
'v0*t - 0.5*g*t**2; v0=%g' % self.v04 dan
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08, dua atribut data,
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20, dan total empat atribut [
'v0*t - 0.5*g*t**2; v0=%g' % self.v04,
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08,
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5, dan _______. Nama atribut dapat dipilih secara bebas, sama seperti nama fungsi dan variabel Python biasa. Namun, konstruktor harus memiliki nama
'v0*t - 0.5*g*t**2; v0=%g' % self.v04, jika tidak maka konstruktor tidak akan dipanggil secara otomatis saat kita membuat instance baru
Anda dapat melakukan apa pun yang Anda inginkan dalam metode apa pun, tetapi merupakan konvensi umum untuk menggunakan konstruktor untuk menginisialisasi variabel di kelas
Perpanjangan kelas
Kita dapat memiliki atribut sebanyak yang kita suka di kelas, jadi mari kita tambahkan metode baru ke kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. Metode ini disebut
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h32 dan mencetak string yang berisi rumus fungsi matematika \[ y \]. Setelah rumus ini, kami memberikan nilai \[ v_0 \]. String kemudian dapat dibangun sebagai
'v0*t - 0.5*g*t**2; v0=%g' % self.v0
di mana
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 adalah turunan dari kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. Panggilan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_32 tidak memerlukan argumen apa pun
harus cukup untuk membuat, mengembalikan, dan mencetak string. Namun, meskipun metode
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_32 tidak memerlukan argumen apa pun, ia harus memiliki argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09, yang tidak disertakan dalam panggilan tetapi diperlukan di dalam metode untuk mengakses atribut. Oleh karena itu penerapan metode ini
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v0
Untuk kelengkapan, seluruh kelas sekarang membaca
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_0
Contoh penggunaan mungkin
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_1
dengan keluaran
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_2
Hati-hati dengan lekukan dalam pemrograman kelas. Kesalahan umum yang dilakukan oleh pendatang baru dalam konstruksi kelas adalah menempatkan kode yang menerapkan kelas pada indentasi yang sama dengan metode kelas. Ini ilegal. Hanya definisi metode dan penugasan untuk apa yang disebut atribut data statis [bagian ] yang dapat muncul di blok indentasi di bawah judul
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h38. Penugasan atribut data biasa harus dilakukan di dalam metode. Program utama yang menggunakan kelas harus muncul dengan indentasi yang sama dengan judul
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h38
Menggunakan metode sebagai fungsi biasa
Kita dapat membuat beberapa fungsi \[ y \] dengan nilai \[ v_0 \] yang berbeda
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_3
Kita dapat memperlakukan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h40,
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h41, dan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h42 sebagai fungsi Python biasa dari
'v0*t - 0.5*g*t**2; v0=%g' % self.v00, lalu meneruskannya ke fungsi Python apa pun yang mengharapkan fungsi dari satu variabel. Secara khusus, kami dapat mengirim fungsi ke fungsi
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h44 dari bagian tersebut
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_4
Di dalam fungsi
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_44, argumen
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]2 sekarang berperilaku sebagai fungsi dari satu variabel yang secara otomatis membawa serta dua variabel
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20. Ketika
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]_2 mengacu pada [mis. g. ]
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_42, Python benar-benar tahu bahwa
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h51 berarti
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h52, dan di dalam
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h42 metode
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 adalah
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h55, dan kami memiliki akses ke
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h56 dan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h57
Kelas gaya baru versus kelas klasik
Saat menggunakan Python versi 2 dan menulis kelas seperti
kita mendapatkan apa yang dikenal sebagai kelas gaya lama atau klasik. Implementasi kelas yang direvisi dalam Python datang dalam versi 2. 2 dengan kelas gaya baru. Spesifikasi kelas gaya baru membutuhkan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h58 setelah nama kelas
Kelas gaya baru memiliki lebih banyak fungsi, dan secara umum disarankan untuk bekerja dengan kelas gaya baru. Oleh karena itu, mulai sekarang kami akan menulis
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_59 daripada hanya
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h60. Di Python 3, semua kelas adalah gaya baru apakah kita menulis
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h60 atau
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h59
String dokumen
Suatu fungsi mungkin memiliki string dokumen tepat setelah definisi fungsi, lihat bagian ref{detik. dasar. dokumen}. Tujuan dari string doc adalah untuk menjelaskan tujuan dari fungsi dan, misalnya, apa argumen dan nilai kembaliannya. Kelas juga dapat memiliki string dokumen, ini hanya string pertama yang muncul tepat setelah judul
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h38. Konvensinya adalah untuk menyertakan string doc dalam tanda kutip rangkap tiga
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h64
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_5
Informasi yang lebih komprehensif dapat mencakup metode dan bagaimana kelas digunakan dalam sesi interaktif
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_6
Variabel diri
Sekarang kami akan memberikan penjelasan lebih lanjut tentang parameter
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 dan cara kerja metode kelas. Di dalam konstruktor
'v0*t - 0.5*g*t**2; v0=%g' % self.v04, argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 adalah variabel yang menampung instance baru yang akan dibangun. Ketika kita menulis
kami mendefinisikan dua atribut data baru dalam contoh ini. Parameter
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 secara tidak terlihat dikembalikan ke kode panggilan. Kita dapat membayangkan bahwa Python menerjemahkan sintaks
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h69 menjadi panggilan yang ditulis sebagai
Sekarang,
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 menjadi instance baru
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 yang ingin kita buat, jadi ketika kita melakukan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h72 di konstruktor, kita benar-benar menetapkan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 ke
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h16. Awalan dengan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h75 mengilustrasikan cara mencapai metode kelas dengan sintaks yang mirip dengan mencapai fungsi dalam modul [seperti
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h76]. Jika kita awali dengan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h75, kita perlu memberi makan secara eksplisit dalam contoh untuk argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09, seperti
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 pada baris kode di atas, tetapi jika kita awali dengan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h80 [nama contoh] argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 dijatuhkan dalam sintaks, dan Python akan . Ini adalah "awalan nama instance" terakhir yang akan kita gunakan saat menghitung dengan kelas. [
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h84 tidak akan berfungsi karena
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 tidak ditentukan dan seharusnya menjadi objek
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. Namun, jika pertama-tama kita membuat
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_87 lalu memanggil
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h84, sintaks berfungsi, dan
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h16 adalah
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h04 setelah panggilan. ]
Mari kita lihat panggilan ke metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 untuk melihat penggunaan serupa dari argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09. Ketika kita menulis
Python menerjemahkan ini menjadi panggilan
sehingga argumen
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 dalam metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 menjadi instance
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7. Dalam ekspresi di dalam metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v0_8,
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_7
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 adalah
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 jadi ini sama dengan
Penggunaan
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 mungkin menjadi lebih jelas ketika kita memiliki banyak instance kelas. Kita dapat membuat kelas yang hanya memiliki satu parameter sehingga kita dapat dengan mudah mengidentifikasi instance kelas dengan mencetak nilai parameter ini. Selain itu, setiap objek Python
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_00 memiliki pengidentifikasi unik yang diperoleh oleh
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]01 yang juga dapat kita cetak untuk melacak apa
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 itu
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_8
Berikut adalah sesi interaktif dengan kelas ini
def diff[f, x, h=1E-5]: return [f[x+h] - f[x]]/h_9
Kami melihat dengan jelas bahwa
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9 di dalam konstruktor adalah objek yang sama dengan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]04, yang ingin kami buat dengan memanggil konstruktor
Objek kedua dibuat oleh
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_0
Sekarang kita dapat memanggil metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 menggunakan sintaks standar
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]06 dan sintaks "lebih pedagogis"
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]07. Menggunakan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]04 dan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]09 mengilustrasikan bagaimana
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 mengambil nilai yang berbeda, sementara kita dapat melihat metode
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]11 sebagai fungsi tunggal yang hanya beroperasi pada objek
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 dan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]13 yang berbeda
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_1
Semoga ilustrasi ini membantu menjelaskan bahwa
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 hanyalah contoh yang digunakan dalam awalan pemanggilan metode, di sini
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]04 atau
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]09. Jika tidak, pasien bekerja dengan pemrograman kelas dengan Python dari waktu ke waktu akan mengungkapkan pemahaman tentang apa sebenarnya
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 itu
Aturan tentang
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_9
- Setiap metode kelas harus memiliki
'v0*t - 0.5*g*t**2; v0=%g' % self.v0
_9 sebagai argumen pertama. [Nama dapat berupa nama variabel yang valid, tetapi nama'v0*t - 0.5*g*t**2; v0=%g' % self.v0
9 adalah konvensi yang sudah mapan di Python. ] 'v0*t - 0.5*g*t**2; v0=%g' % self.v0
_9 mewakili instance [sewenang-wenang] dari kelas- Untuk mengakses atribut kelas apa pun di dalam metode kelas, kita harus diawali dengan
'v0*t - 0.5*g*t**2; v0=%g' % self.v0
9, seperti padadef h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]
23, di manadef h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]
24 adalah nama atribut 'v0*t - 0.5*g*t**2; v0=%g' % self.v0
_9 dijatuhkan sebagai argumen dalam panggilan ke metode kelas
Contoh kelas fungsi lainnya
Mari kita terapkan ide dari kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_5 ke fungsi $$ \begin{equation*} v[r] = \left[{\beta\over 2\mu_0}\right]^{{1/ n}} {n . Kami dapat menulis fungsi ini sebagai \[ v[r; \beta,\mu_0,n,R] \] untuk secara eksplisit menunjukkan bahwa ada satu variabel independen primer [\[ r \]] dan empat parameter fisik \[ \beta \ . Kelas biasanya menyimpan parameter fisik sebagai variabel dan menyediakan metode
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]27 untuk menghitung fungsi \[ v \]
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_2
Tampaknya ada satu hal baru di sini yaitu kami menginisialisasi beberapa variabel pada baris yang sama
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_3
Daftar variabel yang dipisahkan koma di sisi kanan membentuk sebuah tupel sehingga penugasan ini hanyalah konstruksi yang valid di mana sekumpulan variabel di sisi kiri diatur sama dengan daftar atau tupel di sisi kanan . Kode multi-baris yang setara adalah
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_4
Dalam metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 lebih mudah untuk menghindari awalan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]29 dalam rumus matematika dan memperkenalkan nama pendek lokal
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]30,
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]31,
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]32, dan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]33. Ini secara umum merupakan ide yang bagus, karena memudahkan untuk membaca implementasi rumus dan memeriksa kebenarannya
Komentar
Solusi lain untuk masalah mengirim fungsi dengan parameter ke fungsi perpustakaan umum seperti
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]1 disediakan dalam dokumen Jumlah variabel argumen fungsi dengan Python. Obatnya adalah mentransfer parameter sebagai argumen "melalui" fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]1. Hal ini dapat dilakukan secara umum seperti yang dijelaskan pada lampiran tersebut
Implementasi kelas fungsi alternatif
Untuk mengilustrasikan pemrograman kelas lebih lanjut, sekarang kita akan menyadari kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 dari bagian dengan cara yang berbeda. Anda dapat menganggap bagian ini sebagai lanjutan dan melewatinya, tetapi bagi beberapa pembaca materi tersebut mungkin meningkatkan pemahaman kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 dan memberikan beberapa wawasan tentang pemrograman kelas secara umum
Merupakan kebiasaan yang baik untuk selalu memiliki konstruktor di kelas dan menginisialisasi atribut data di kelas di sini, tetapi ini bukan persyaratan. Mari kita tinggalkan konstruktor dan menjadikan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 argumen opsional untuk metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08. Jika pengguna tidak memberikan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_5 dalam panggilan ke
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08, kami menggunakan nilai
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 yang harus diberikan dalam panggilan sebelumnya dan disimpan sebagai atribut data
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]43. Kami dapat mengenali apakah pengguna memberikan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_5 sebagai argumen atau tidak dengan menggunakan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]45 sebagai nilai default untuk argumen kata kunci dan kemudian menguji apakah
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]46
Implementasi alternatif kami dari kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_5, bernama
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]48, sekarang berbunyi
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_5
Kali ini kelas hanya memiliki satu metode dan satu atribut data saat kita melewatkan konstruktor dan membiarkan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20 menjadi variabel lokal dalam metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08
Tetapi jika tidak ada konstruktor, bagaimana sebuah instance dibuat? . Ini memungkinkan kita untuk menulis
untuk membuat contoh
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]_7. Karena tidak ada yang terjadi pada konstruktor kosong yang dihasilkan secara otomatis,
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 tidak memiliki atribut data pada tahap ini. Menulis
sehingga mengarah pada pengecualian
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_6
Dengan menyebut
kami membuat atribut
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]43 di dalam metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08. Secara umum, kita dapat membuat atribut apa pun
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]24 dengan metode apa pun hanya dengan memberikan nilai ke
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]23. Sekarang mencoba a
akan mencetak
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_57. Dalam panggilan baru,
nilai
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_5 sebelumnya [
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]57] digunakan di dalam
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 sebagai
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]43 kecuali argumen
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 ditentukan dalam panggilan
Implementasi sebelumnya tidak aman jika kita gagal menginisialisasi
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5. Misalnya, kode
akan berakhir dengan metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v0_8 dengan pengecualian
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_6
Seperti biasa, lebih baik memberi tahu pengguna dengan pesan yang lebih informatif. Untuk memeriksa apakah kita memiliki atribut
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_5, kita dapat menggunakan fungsi Python
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]66. Memanggil
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_67 mengembalikan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]68 hanya jika instance
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 memiliki atribut dengan nama
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]70. Metode
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 yang ditingkatkan sekarang terbaca
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_8
Sebagai alternatif, kita dapat mencoba mengakses
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_43 dalam blok
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]73, dan mungkin mengajukan pengecualian
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]74 [yang dimunculkan oleh Python jika tidak ada cukup argumen untuk suatu fungsi atau metode]
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_9
Perhatikan bahwa Python mendeteksi
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]_75, tetapi dari sudut pandang pengguna, tidak cukup parameter yang diberikan dalam panggilan sehingga
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]74 lebih tepat untuk berkomunikasi kembali ke kode panggilan
Menurut kami kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05 adalah implementasi yang lebih baik daripada kelas
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]48, karena yang pertama lebih sederhana. Seperti yang telah disebutkan, adalah kebiasaan yang baik untuk memasukkan konstruktor dan mengatur data di sini daripada "merekam data dengan cepat" seperti yang kami coba di kelas
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]48. Seluruh tujuan kelas
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]48 hanya untuk menunjukkan bahwa Python memberikan fleksibilitas yang besar sehubungan dengan mendefinisikan atribut, dan bahwa tidak ada persyaratan untuk apa yang harus dimiliki oleh suatu kelas.
Membuat kelas tanpa konstruksi kelas
Pendatang baru di konsep kelas sering kali kesulitan memahami tentang apa konsep ini. Bagian ini mencoba untuk menjelaskan secara lebih rinci bagaimana kita dapat memperkenalkan kelas tanpa konstruksi kelas dalam bahasa komputer. Informasi ini mungkin atau mungkin tidak meningkatkan pemahaman Anda tentang kelas. Jika tidak, pemrograman dengan kelas pasti akan meningkatkan pemahaman Anda seiring berjalannya waktu, jadi tidak ada alasan untuk khawatir. Bahkan, Anda dapat dengan aman melompat ke bagian karena tidak ada konsep penting di bagian ini yang dibangun di bagian selanjutnya
Kelas berisi kumpulan variabel [data] dan kumpulan metode [fungsi]. Kumpulan variabel unik untuk setiap instance kelas. Artinya, jika kita membuat sepuluh instance, masing-masing memiliki kumpulan variabelnya sendiri. Variabel ini dapat dianggap sebagai kamus dengan kunci yang sama dengan nama variabel. Setiap instance kemudian memiliki kamusnya sendiri, dan kami dapat secara kasar melihat instance sebagai kamus ini. [Instance juga dapat berisi atribut data statis [bagian ], tetapi ini harus dilihat sebagai variabel global dalam konteks saat ini. ]
Di sisi lain, metode dibagikan di antara instance. Kita mungkin menganggap metode di kelas sebagai fungsi global standar yang menggunakan instance dalam bentuk kamus sebagai argumen pertama. Metode kemudian memiliki akses ke variabel dalam contoh [kamus] yang disediakan dalam panggilan. Untuk kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_5 dari bagian dan instance
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7, metodenya adalah fungsi biasa dengan nama dan argumen berikut
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]0
Kelas bertindak sebagai namespace, artinya semua fungsi harus diawali dengan nama namespace, di sini
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. Dua kelas yang berbeda, katakanlah
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]84 dan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]85, mungkin memiliki fungsi dengan nama yang sama, katakanlah
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08, tetapi ketika
def formula[self]: return 'v0*t - 0.5*g*t**2; v0=%g' % self.v08 fungsi milik ruang nama yang berbeda, namanya
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]88 dan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]89 menjadi berbeda. Modul juga merupakan ruang nama untuk fungsi dan variabel di dalamnya [pikirkan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]90,
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]91,
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]92]
Satu-satunya hal yang aneh dengan konstruksi kelas di Python adalah memungkinkan kita untuk menggunakan sintaks alternatif untuk pemanggilan metode
Sintaks ini bertepatan dengan sintaks tradisional pemanggilan metode kelas dan memberikan argumen, seperti yang ditemukan dalam bahasa komputer lainnya, seperti Java, C#, C++, Simula, dan Smalltalk. Notasi titik juga digunakan untuk mengakses variabel dalam contoh sehingga kita di dalam metode dapat menulis
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]43 alih-alih
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]94 [
'v0*t - 0.5*g*t**2; v0=%g' % self.v09 merujuk ke
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 melalui pemanggilan fungsi]
Kita dapat dengan mudah mengimplementasikan versi sederhana dari konsep kelas tanpa konstruksi kelas dalam bahasa. Yang kita butuhkan hanyalah tipe kamus dan fungsi biasa. Kamus bertindak sebagai instance, dan metode adalah fungsi yang mengambil kamus ini sebagai argumen pertama sehingga fungsi tersebut memiliki akses ke semua variabel dalam instance. Kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v0_5 kita sekarang dapat diimplementasikan sebagai
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]1
Kedua fungsi tersebut ditempatkan dalam sebuah modul bernama
'v0*t - 0.5*g*t**2; v0=%g' % self.v05. Penggunaannya sebagai berikut
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]2
Kami tidak memiliki konstruktor karena inisialisasi variabel dilakukan saat mendeklarasikan kamus
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7, tetapi kami juga dapat menyertakan beberapa fungsi inisialisasi dalam modul
'v0*t - 0.5*g*t**2; v0=%g' % self.v05
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]3
Penggunaannya sekarang sedikit berbeda
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_4
Cara mengimplementasikan kelas dengan bantuan kamus dan sekumpulan fungsi biasa ini sebenarnya membentuk dasar implementasi kelas dalam banyak bahasa. Python dan Perl bahkan memiliki sintaks yang mendemonstrasikan jenis implementasi ini. Bahkan, setiap instance kelas di Python memiliki kamus
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]01 sebagai atribut, yang menampung semua variabel dalam instance. Berikut adalah demo yang membuktikan keberadaan kamus ini di kelas
'v0*t - 0.5*g*t**2; v0=%g' % self.v05
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]5
Untuk meringkas. Kelas Python dapat dianggap sebagai beberapa variabel yang dikumpulkan dalam kamus, dan sekumpulan fungsi di mana kamus ini secara otomatis disediakan sebagai argumen pertama sehingga fungsi selalu memiliki akses penuh ke variabel kelas
Komentar pertama
Kami telah di bagian ini memberikan pandangan tentang kelas dari sudut pandang teknis. Orang lain mungkin melihat kelas sebagai cara memodelkan dunia dalam hal data dan operasi pada data. Namun, dalam ilmu yang menggunakan bahasa matematika, pemodelan dunia biasanya dilakukan dengan matematika, dan struktur matematika memberikan pemahaman tentang masalah dan struktur program. Bila sesuai, struktur matematika dapat dengan mudah dipetakan ke kelas dalam program untuk membuat perangkat lunak lebih sederhana dan lebih fleksibel
Komentar kedua
Tampilan kelas di bagian ini mengabaikan topik yang sangat penting seperti pewarisan dan pengikatan dinamis [dijelaskan dalam dokumen Pemrograman berorientasi objek ]. Untuk kelengkapan lebih lanjut dari bagian ini, oleh karena itu kami menjelaskan secara singkat bagaimana kombinasi kamus dan fungsi global kami dapat menangani pewarisan dan pengikatan dinamis [tetapi ini tidak masuk akal kecuali Anda tahu apa itu pewarisan]
Pewarisan data dapat diperoleh dengan membiarkan kamus subkelas melakukan panggilan
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]03 dengan kamus superkelas sebagai argumen. Dengan cara ini semua data di superclass juga tersedia di kamus subclass. Pengikatan dinamis metode lebih rumit, tetapi seseorang dapat berpikir untuk memeriksa apakah metode tersebut ada dalam modul subkelas [menggunakan
def h[t]: return t**4 + 4*t dh = diff[h, 0.1] from math import sin, pi x = 2*pi dsin = diff[sin, x, h=1E-6]66], dan jika tidak, seseorang melanjutkan dengan memeriksa modul kelas super hingga versi metode ditemukan
Penutupan
Bagian ini menindaklanjuti diskusi di bagian ini dan menyajikan konstruksi yang lebih maju yang dapat berfungsi sebagai alternatif konstruksi kelas dalam beberapa kasus
Contoh motivasi kami adalah bahwa kami ingin implementasi Python dari fungsi matematika \[ y[t;v_0]=v_0t - \frac{1}{2}gt^2 \] memiliki \[ t \] sebagai satu-satunya argumen, . Pertimbangkan fungsi berikut, yang mengembalikan fungsi
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]6
Properti luar biasa dari fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7 adalah ia mengingat nilai
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
def y1[t]: g = 9.81 return v0_1*t - 0.5*g*t**2 def y2[t]: g = 9.81 return v0_2*t - 0.5*g*t**20, meskipun variabel ini tidak lokal untuk fungsi induk
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]08 dan bukan lokal di
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7. Secara khusus, kita dapat menentukan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 sebagai argumen untuk
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]08
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]7
Di sini,
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_12 memiliki akses ke
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]13 sementara
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]14 memiliki akses ke
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]15
Fungsi
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_16 yang kita buat dan kembalikan dari
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]08 disebut penutupan dan mengingat nilai variabel lokal di sekitarnya dalam fungsi induk [pada saat kita membuat fungsi
v0 = 3 dy = diff[y, 1] A = 1; a = 0.1 dg = diff[g, 1.5]7]. Penutupan sangat nyaman untuk banyak tujuan dalam komputasi matematika. Contoh muncul di bagian. Penutupan juga penting dalam gaya pemrograman yang disebut pemrograman fungsional
Menghasilkan banyak penutupan dalam suatu fungsi. Segera setelah Anda mendapatkan ide penutupan, Anda mungkin akan sering menggunakannya karena ini adalah cara mudah untuk mengemas fungsi dengan data tambahan. Namun, ada beberapa jebakan. Yang terbesar diilustrasikan di bawah ini, tetapi ini dianggap materi tingkat lanjut
Mari kita buat serangkaian fungsi
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_19 untuk berbagai nilai parameter
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5. Setiap fungsi hanya mengembalikan tuple
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]21 sehingga kita dapat dengan mudah melihat apa argumen dan parameternya. Kami menggunakan
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_22 untuk mendefinisikan setiap fungsi dengan cepat, dan kami menempatkan fungsi dalam daftar
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]8
Sekarang,
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_23 adalah daftar fungsi dengan satu argumen. Memanggil setiap fungsi dan mencetak nilai pengembalian
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 dan
'v0*t - 0.5*g*t**2; v0=%g' % self.v00 memberikan
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]_9
Seperti yang kita lihat, semua fungsi memiliki
def y[t]: g = 9.81 return v0*t - 0.5*g*t**2 def g[t]: return A*exp[-a*x]26, i. e. , mereka menyimpan nilai terbaru
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]5 sebelum dikembalikan. Ini bukan yang kami inginkan
Triknya adalah membiarkan
v0 = 1; r1 = y[t] v0 = 5; r2 = y[t]_5 menjadi argumen kata kunci di setiap fungsi, karena nilai argumen kata kunci dibekukan pada saat fungsi didefinisikan