Halo, Habr! Saya mempersembahkan kepada Anda terjemahan artikel “Pemrograman Berorientasi Objek dengan Python vs Java” oleh John Fincher.
Implementasi pemrograman berorientasi objek (OOP) di Jawa dan Python berbeda. Prinsip bekerja dengan objek, jenis variabel, dan kemampuan bahasa lainnya dapat menyebabkan kesulitan dalam beralih dari satu bahasa ke bahasa lain. Artikel ini, yang dapat berguna baik untuk programmer Java yang ingin belajar Python, dan untuk programmer Python yang ingin belajar Java lebih baik, memberikan persamaan dan perbedaan utama antara bahasa-bahasa ini dalam kaitannya dengan OOP.
Lebih detail - di bawah potongan.
Contoh kelas dalam Python dan Java
Untuk memulai, mari kita terapkan kelas paling sederhana dengan Python dan Java untuk mengilustrasikan beberapa perbedaan dalam bahasa-bahasa ini, dan kami akan secara bertahap membuat perubahan pada kelas ini.
Bayangkan kita memiliki definisi kelas mobil berikut di Jawa:
1 public class Car { 2 private String color; 3 private String model; 4 private int year; 5 6 public Car(String color, String model, int year) { 7 this.color = color; 8 this.model = model; 9 this.year = year; 10 } 11 12 public String getColor() { 13 return color; 14 } 15 16 public String getModel() { 17 return model; 18 } 19 20 public int getYear() { 21 return year; 22 } 23 }
Nama file Java sumber harus cocok dengan nama kelas yang disimpan di dalamnya, jadi kita harus memberi nama file Car.java. Setiap file Java hanya dapat berisi satu kelas publik.
Kelas yang sama dengan Python akan terlihat seperti ini:
1 class Car: 2 def __init__(self, color, model, year): 3 self.color = color 4 self.model = model 5 self.year = year
Dengan Python, Anda bisa mendeklarasikan kelas di mana saja, kapan saja. Simpan file ini sebagai car.py.
Menggunakan kelas-kelas ini sebagai dasar, kami melanjutkan studi tentang komponen utama kelas dan objek.
Atribut Objek
Dalam semua bahasa berorientasi objek, data tentang suatu objek disimpan di suatu tempat. Dalam Python dan Java, data ini disimpan dalam atribut , yang merupakan variabel yang terkait dengan objek tertentu.
Salah satu perbedaan paling signifikan antara Python dan Java adalah bagaimana mereka mendefinisikan atribut kelas dan objek dan bagaimana bahasa-bahasa ini mengendalikan mereka. Beberapa perbedaan ini disebabkan oleh pembatasan yang diberlakukan oleh bahasa, sementara yang lain dikaitkan dengan praktik yang lebih efektif.
Deklarasi dan Inisialisasi
Di Jawa, kami mendeklarasikan atribut (menunjukkan jenisnya) di dalam kelas, tetapi di luar semua metode. Sebelum menggunakan atribut class, kita harus mendefinisikannya:
1 public class Car { 2 private String color; 3 private String model; 4 private int year;
Dalam Python, kami mendeklarasikan dan mendefinisikan atribut di dalam metode kelas init (), yang merupakan analog dari konstruktor di Jawa:
1 def __init__(self, color, model, year): 2 self.color = color 3 self.model = model 4 self.year = year
Dengan menentukan sendiri kata kunci di depan nama variabel, kami memberi tahu Python bahwa ini adalah atribut. Setiap instance kelas mendapatkan salinannya. Semua variabel dalam Python tidak diketik secara longgar, dan atribut tidak terkecuali.
Variabel juga dapat dibuat di luar metode init (), tetapi ini tidak akan menjadi solusi terbaik dan dapat menyebabkan bug yang sulit dideteksi. Misalnya, Anda dapat menambahkan atribut roda baru ke objek Mobil sebagai berikut:
1 >>> import car 2 >>> my_car = car.Car("yellow", "beetle", 1967) 3 >>> print(f"My car is {my_car.color}") 4 My car is yellow 5 6 >>> my_car.wheels = 5 7 >>> print(f"Wheels: {my_car.wheels}") 8 Wheels: 5
Namun, jika kita lupa menentukan ekspresi my_car.wheels = 5 di baris ke-6, kita mendapatkan kesalahan:
1 >>> import car 2 >>> my_car = car.Car("yellow", "beetle", 1967) 3 >>> print(f"My car is {my_car.color}") 4 My car is yellow 5 6 >>> print(f"Wheels: {my_car.wheels}") 7 Traceback (most recent call last): 8 File "<stdin>", line 1, in <module> 9 AttributeError: 'Car' object has no attribute 'wheels'
Dalam Python, jika Anda mendeklarasikan variabel di luar metode, maka itu akan dianggap sebagai variabel kelas. Mari kita ubah kelas Mobil:
1 class Car: 2 3 wheels = 0 4 5 def __init__(self, color, model, year): 6 self.color = color 7 self.model = model 8 self.year = year
Sekarang penggunaan roda variabel akan berubah. Alih-alih mengaksesnya melalui objek, kami mengaksesnya menggunakan nama kelas:
1 >>> import car 2 >>> my_car = car.Car("yellow", "beetle", 1967) 3 >>> print(f"My car is {my_car.color}") 4 My car is yellow 5 6 >>> print(f"It has {car.Car.wheels} wheels") 7 It has 0 wheels 8 9 >>> print(f"It has {my_car.wheels} wheels") 10 It has 0 wheels
Catatan: dalam Python, variabel kelas diakses menggunakan sintaks berikut:
- Nama file yang berisi kelas (tanpa ekstensi .py)
- Point
- Nama kelas
- Point
- Nama variabel
Karena kami menyimpan kelas Car di file car.py, kami merujuk ke variabel kelas roda di baris ke-6 dengan cara ini: car.Car.wheels.
Saat bekerja dengan variabel roda, Anda perlu memperhatikan fakta bahwa mengubah nilai variabel instan dari kelas my_car.wheels tidak mengarah pada perubahan variabel kelas car.Car.wheels:
1 >>> from car import * 2 >>> my_car = car.Car("yellow", "Beetle", "1966") 3 >>> my_other_car = car.Car("red", "corvette", "1999") 4 5 >>> print(f"My car is {my_car.color}") 6 My car is yellow 7 >>> print(f"It has {my_car.wheels} wheels") 8 It has 0 wheels 9 10 >>> print(f"My other car is {my_other_car.color}") 11 My other car is red 12 >>> print(f"It has {my_other_car.wheels} wheels") 13 It has 0 wheels 14 15 >>>
Pada baris 2 dan 3, kami mendefinisikan dua objek Mobil: my_car dan my_other_car.
Pertama, properti roda dari kedua objek adalah nol. Pada baris ke-16, kita mengatur variabel kelas: car.Car.wheels = 4, kedua objek sekarang memiliki 4 roda. Namun, kemudian ketika pada baris ke-24 kita mengubah properti objek my_car.wheels = 5, properti objek kedua tetap tidak tersentuh.
Ini berarti bahwa kami sekarang memiliki dua salinan atribut roda yang berbeda:
- Variabel kelas yang berlaku untuk semua objek Mobil
- Variabel instance kelas spesifik yang hanya berlaku untuk objek my_car.
Karena itu, Anda dapat secara tidak sengaja merujuk ke contoh yang salah dan membuat kesalahan yang halus.
Di Jawa, ekivalen atribut kelas adalah atribut statis:
public class Car { private String color; private String model; private int year; private static int wheels; public Car(String color, String model, int year) { this.color = color; this.model = model; this.year = year; } public static int getWheels() { return wheels; } public static void setWheels(int count) { wheels = count; } }
Biasanya kita mengakses variabel statis di Java melalui nama kelas. Anda dapat mengaksesnya melalui instance kelas, seperti dalam Python, tetapi ini bukan solusi terbaik.
Kelas Java kami mulai memanjang. Salah satu alasan Java adalah "verbose" untuk Python adalah gagasan tentang metode dan atribut publik dan pribadi.
Publik dan pribadi
Java mengontrol akses ke metode dan atribut dengan membedakan antara data publik dan pribadi .
Di Jawa, atribut diharapkan akan dinyatakan pribadi (atau dilindungi, jika keturunan kelas membutuhkan akses ke sana). Dengan demikian, kami membatasi akses ke mereka dari luar. Untuk memberikan akses ke atribut pribadi, kami mendeklarasikan metode publik yang menginstal atau menerima data ini (lebih lanjut tentang ini nanti).
Ingatlah bahwa dalam kode Java kami, variabel warna dinyatakan pribadi. Karenanya, kode di bawah ini tidak dapat dikompilasi:
Car myCar = new Car("blue", "Ford", 1972);
Jika Anda tidak menentukan tingkat akses ke atribut, maka secara default itu akan ditetapkan sebagai paket yang dilindungi , yang membatasi akses ke kelas dalam paket. Jika kita ingin kode di atas berfungsi, maka kita harus membuat atribut menjadi publik.
Namun, Java tidak didorong untuk menyatakan atribut publik. Disarankan agar Anda mendeklarasikannya sebagai pribadi, dan kemudian menggunakan metode publik seperti getColor () dan getModel (), seperti yang disebutkan dalam kode di atas.
Sebaliknya, Python tidak memiliki gagasan tentang data publik dan pribadi. Dalam Python, semuanya bersifat publik. Kode python ini akan bekerja dengan bang:
>>> my_car = car.Car("blue", "Ford", 1972) >>>
Alih-alih variabel pribadi dalam Python, ada konsep variabel instance kelas non-publik ( non-publik ). Semua variabel yang namanya dimulai dengan satu garis bawah dianggap non-publik. Konvensi penamaan ini tidak mencegah kita mengakses variabel secara langsung.
Tambahkan baris berikut ke Mobil kelas Python kami:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._cupholders = 6
Kami dapat mengakses variabel _cupholder secara langsung:
>>> import car >>> my_car = car.Car("yellow", "Beetle", "1969") >>> print(f"It was built in {my_car.year}") It was built in 1969 >>> my_car.year = 1966 >>> print(f"It was built in {my_car.year}") It was built in 1966 >>> print(f"It has {my_car._cupholders} cupholders.") It has 6 cupholders.
Python memungkinkan Anda untuk mengakses variabel seperti itu, namun beberapa lingkungan pengembangan seperti VS Code akan memberikan peringatan:

Selain itu, Python menggunakan garis bawah ganda di awal nama variabel untuk menyembunyikan atribut. Ketika Python melihat variabel seperti itu, ia secara otomatis mengubah namanya untuk membuat akses langsung menjadi sulit. Namun, mekanisme ini masih tidak mencegah kita beralih ke sana. Kami mendemonstrasikan ini dengan contoh berikut:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self.__cupholders = 6
Sekarang jika kita melihat variabel __cupholder, kita mendapatkan kesalahan:
>>> import car >>> my_car = car.Car("yellow", "Beetle", "1969") >>> print(f"It was built in {my_car.year}") It was built in 1969 >>> my_car.year = 1966 >>> print(f"It was built in {my_car.year}") It was built in 1966 >>> print(f"It has {my_car.__cupholders} cupholders.") Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Car' object has no attribute '__cupholders'
Jadi mengapa atribut __cupholder tidak ada?
Ini masalahnya. Ketika Python melihat atribut garis bawah dua kali lipat di awal, itu mengubahnya dengan menambahkan nama kelas yang digarisbawahi ke awal. Untuk mengakses atribut secara langsung, Anda juga harus mengubah nama:
>>> print(f"It has {my_car._Car__cupholders} cupholders") It has 6 cupholders
Sekarang muncul pertanyaan: jika atribut dari kelas Java dideklarasikan pribadi dan atribut dari kelas Python didahului oleh double underscore pada namanya, lalu bagaimana cara mengakses data ini?
Kontrol akses
Di Jawa, kami mengakses atribut pribadi menggunakan setter dan getter . Agar pengguna dapat mengecat ulang mesinnya, tambahkan potongan kode berikut ke kelas Java:
public String getColor() { return color; } public void setColor(String color) { this.color = color; }
Karena metode getColor () dan setColor () bersifat publik, setiap pengguna dapat memanggil mereka dan mendapatkan / mengubah warna mesin. Penggunaan atribut pribadi, yang kami akses getter dan setter publik, adalah salah satu alasan untuk "verbositas" Jawa yang lebih besar dibandingkan dengan Python.
Seperti yang ditunjukkan di atas, dalam Python kita dapat mengakses atribut secara langsung. Karena semuanya bersifat publik, kami dapat menjangkau apa saja, kapan saja, di mana saja. Kita bisa mendapatkan dan menetapkan nilai atribut secara langsung dengan memanggil namanya. Dengan Python, kita bahkan dapat menghapus atribut, yang tidak terpikirkan di Jawa:
>>> my_car = Car("yellow", "beetle", 1969) >>> print(f"My car was built in {my_car.year}") My car was built in 1969 >>> my_car.year = 1966 >>> print(f"It was built in {my_car.year}") It was built in 1966 >>> del my_car.year >>> print(f"It was built in {my_car.year}") Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Car' object has no attribute 'year'
Namun, kami juga ingin mengontrol akses ke atribut. Dalam hal ini, properti Python membantu kami.
Dalam Python, properti menyediakan akses terkontrol ke atribut kelas menggunakan dekorator. Menggunakan properti, kami mendeklarasikan fungsi dalam kelas Python seperti getter dan setter di Jawa (menghapus atribut adalah bonus).
Pengoperasian properti dapat dilihat pada contoh kelas Car berikut:
1 class Car: 2 def __init__(self, color, model, year): 3 self.color = color 4 self.model = model 5 self.year = year 6 self._voltage = 12 7 8 @property 9 def voltage(self): 10 return self._voltage 11 12 @voltage.setter 13 def voltage(self, volts): 14 print("Warning: this can cause problems!") 15 self._voltage = volts 16 17 @voltage.deleter 18 def voltage(self): 19 print("Warning: the radio will stop working!") 20 del self._voltage
Dalam contoh ini, kami memperluas konsep kelas Mobil dengan memasukkan mobil listrik. Baris 6 menyatakan atribut _voltage untuk menyimpan tegangan baterai di dalamnya.
Pada baris 9 dan 10 untuk akses terkontrol, kami membuat fungsi voltase () dan mengembalikan nilai variabel privat. Menggunakan @property decorator, kami mengubahnya menjadi pengambil, yang kini dapat diakses oleh pengguna mana pun.
Pada baris 13-15, kita mendefinisikan fungsi yang juga disebut tegangan (). Namun, kami menghiasnya secara berbeda: voltase .setter. Akhirnya, pada baris 18-20, kita menghias fungsi voltage () dengan .deleter voltage dan dapat menghapus atribut _voltage jika perlu.
Fungsi yang didekorasi memiliki nama yang sama, menunjukkan bahwa mereka mengontrol akses ke atribut yang sama. Nama fungsi ini juga menjadi nama atribut yang digunakan untuk mendapatkan nilainya. Begini cara kerjanya:
1 >>> from car import * 2 >>> my_car = Car("yellow", "beetle", 1969) 3 4 >>> print(f"My car uses {my_car.voltage} volts") 5 My car uses 12 volts 6 7 >>> my_car.voltage = 6 8 Warning: this can cause problems! 9 10 >>> print(f"My car now uses {my_car.voltage} volts") 11 My car now uses 6 volts 12 13 >>> del my_car.voltage 14 Warning: the radio will stop working!
Harap dicatat bahwa kami menggunakan tegangan, bukan _ tegangan. Jadi kami memberi tahu Python untuk menerapkan properti yang baru saja didefinisikan:
- Ketika kita mencetak nilai my_car.voltage di baris ke-4, Python memanggil fungsi voltage (), didekorasi dengan @property.
- Ketika kita menetapkan nilai my_car.voltage di baris ke-7, Python memanggil fungsi voltage (), didekorasi dengan setter tegangan .
- Ketika kita menghapus my_car.voltage di baris 13, Python memanggil fungsi voltage (), didekorasi dengan voltase .deleter.
Dekorator di atas memberi kita kemampuan untuk mengontrol akses ke atribut tanpa menggunakan berbagai metode. Anda bahkan dapat menjadikan atribut properti hanya-baca dengan menghapus fungsi @ .setter dan @ .deleter yang didekorasi.
diri dan ini
Di Jawa, sebuah kelas merujuk pada dirinya sendiri menggunakan kata kunci ini:
public void setColor(String color) { this.color = color; }
ini tersirat dalam kode Java. Pada prinsipnya, bahkan tidak perlu untuk menulisnya, kecuali ketika nama-nama variabel bertepatan.
Setter dapat ditulis seperti ini:
public void setColor(String newColor) { color = newColor; }
Karena kelas Mobil memiliki atribut yang disebut warna dan tidak ada lagi variabel dengan cakupan nama yang sama, tautan ke nama ini dipicu. Kami menggunakan kata kunci ini dalam contoh pertama untuk membedakan antara atribut dan parameter dengan nama warna yang sama.
Dalam Python, kata kunci mandiri memiliki tujuan yang sama: mengakses anggota atribut, tetapi tidak seperti Java, diperlukan :
class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._voltage = 12 @property def voltage(self): return self._voltage
Python membutuhkan diri sendiri untuk menjadi wajib. Setiap diri baik menciptakan atau merujuk ke atribut. Jika kita melewatkannya, maka Python hanya akan membuat variabel lokal, bukan atribut.
Perbedaan dalam cara kita menggunakan diri dan ini dalam Python dan Java adalah karena perbedaan utama antara dua bahasa dan cara mereka menamai variabel dan atribut.
Metode dan Fungsi
Perbedaan antara bahasa yang dipertanyakan adalah bahwa dalam Python ada fungsi, tetapi di Jawa tidak.
Dengan Python, kode berikut akan bekerja tanpa masalah (dan digunakan di mana-mana):
>>> def say_hi(): ... print("Hi!") ... >>> say_hi() Hi!
Kita dapat memanggil say_hi () dari mana saja di visibilitas. Fungsi ini tidak mengandung referensi ke diri, yang berarti bahwa itu adalah fungsi global, bukan fungsi kelas. Dia tidak akan dapat mengubah atau menyimpan data apa pun dari kelas apa pun, tetapi dia dapat menggunakan variabel lokal dan global.
Sebaliknya, setiap baris yang kita tulis di Jawa milik kelas. Fungsi tidak ada di luar kelas, dan menurut definisi, semua fungsi Java adalah metode. Di Jawa, hal terdekat dengan fungsi murni adalah metode statis:
public class Utils { static void SayHi() { System.out.println("Hi!"); } }
Utils. SayHi () dipanggil dari mana saja tanpa terlebih dahulu membuat turunan dari kelas Utils. Karena kita memanggil SayHi () tanpa membuat objek, tautan ini tidak ada. Namun, ini masih bukan fungsi dalam arti bahwa say_hi () adalah dalam Python.
Warisan dan polimorfisme
Warisan dan polimorfisme adalah dua konsep dasar dalam OOP. Berkat yang pertama, objek menerima (dengan kata lain, mewarisi) atribut dan fungsionalitas objek lain, membuat hierarki dari objek yang lebih umum ke yang lebih spesifik. Sebagai contoh, baik kelas Mobil dan kelas Perahu adalah tipe spesifik dari kelas Kendaraan. Kedua objek mewarisi perilaku satu orangtua atau beberapa objek orangtua. Dalam hal ini, mereka disebut benda anak.
Polimorfisme, pada gilirannya, adalah kemampuan untuk bekerja dengan objek yang berbeda menggunakan fungsi atau metode yang sama.
Kedua konsep OOP mendasar ini diimplementasikan dalam Java dan Python dengan cara yang sangat berbeda.
Warisan
Python mendukung multiple inheritance, mis. Menciptakan kelas dari lebih dari satu orangtua.
Untuk menunjukkan ini, kami membagi kelas Mobil menjadi dua kategori: satu untuk kendaraan dan satu untuk mobil menggunakan listrik:
class Vehicle: def __init__(self, color, model): self.color = color self.model = model class Device: def __init__(self): self._voltage = 12 class Car(Vehicle, Device): def __init__(self, color, model, year): Vehicle.__init__(self, color, model) Device.__init__(self) self.year = year @property def voltage(self): return self._voltage @voltage.setter def voltage(self, volts): print("Warning: this can cause problems!") self._voltage = volts @voltage.deleter def voltage(self): print("Warning: the radio will stop working!") del self._voltage
Kelas Kendaraan mendefinisikan atribut warna dan model. Kelas perangkat memiliki atribut _voltage. Kelas Mobil berasal dari dua kelas ini, dan atribut warna, model, dan tegangan kini menjadi bagian dari kelas baru.
Metode init () dari kelas Car memanggil metode init () dari kedua kelas induk untuk memastikan bahwa semua data diinisialisasi dengan benar. Setelah itu, kita dapat menambahkan fungsionalitas yang diinginkan ke kelas Mobil. Dalam contoh ini, kita akan menambahkan atribut tahun, serta pengambil dan penyetel untuk _voltage.
Fungsionalitas kelas Mobil baru tetap sama. Kita dapat membuat dan menggunakan objek kelas, seperti yang kita lakukan beberapa contoh sebelumnya:
>>> from car import * >>> my_car = Car("yellow", "beetle", 1969) >>> print(f"My car is {my_car.color}") My car is yellow >>> print(f"My car uses {my_car.voltage} volts") My car uses 12 volts >>> my_car.voltage = 6 Warning: this can cause problems! >>> print(f"My car now uses {my_car.voltage} volts") My car now uses 6 volts
Bahasa Java, pada gilirannya, hanya mendukung pewarisan tunggal, yang berarti bahwa kelas-kelas di Jawa dapat mewarisi data dan perilaku dari hanya satu kelas induk. Namun di Jawa, pewarisan dari beberapa antarmuka dimungkinkan. Antarmuka menyediakan sekelompok metode terkait yang perlu diimplementasikan, memungkinkan kelas anak berperilaku dengan cara yang sama.
Untuk melihat ini, kami membagi kelas Car Java menjadi kelas dan antarmuka induknya:
public class Vehicle { private String color; private String model; public Vehicle(String color, String model) { this.color = color; this.model = model; } public String getColor() { return color; } public String getModel() { return model; } } public interface Device { int getVoltage(); } public class Car extends Vehicle implements Device { private int voltage; private int year; public Car(String color, String model, int year) { super(color, model); this.year = year; this.voltage = 12; } @Override public int getVoltage() { return voltage; } public int getYear() { return year; } }
Jangan lupa bahwa setiap kelas dan setiap antarmuka di Jawa harus ditempatkan di file sendiri.
Seperti dalam contoh di atas dengan Python, kami membuat kelas Kendaraan baru untuk menyimpan data umum dan fungsi yang melekat pada kendaraan. Namun, untuk menambahkan fungsionalitas Perangkat, kita perlu membuat antarmuka yang mendefinisikan metode untuk mendapatkan tegangan perangkat.
Kelas Mobil dibuat dengan mewarisi dari kelas Kendaraan menggunakan kata kunci extends dan mengimplementasikan antarmuka Perangkat menggunakan kata kunci implement. Di konstruktor kelas, kita memanggil induk konstruktor dengan super (). Karena hanya ada satu kelas induk, kami merujuk ke konstruktor kelas Kendaraan. Untuk mengimplementasikan antarmuka, kami mendefinisikan kembali getVoltage () menggunakan anotasi Abaikan .
Alih-alih menggunakan kembali kode dari Perangkat, seperti yang dilakukan Python, Java mengharuskan kami menerapkan fungsi yang sama di setiap kelas yang mengimplementasikan antarmuka. Antarmuka hanya mendefinisikan metode - mereka tidak bisa mendefinisikan data instance kelas atau detail implementasi.
Java? .
Java . , Java- , , . , .
Java- charge(), Device. , Device, charge().
Rhino.java:
public class Rhino { }
Main.java charge() , Car Rhino.
public class Main{ public static void charge(Device device) { device.getVoltage(); } public static void main(String[] args) throws Exception { Car car = new Car("yellow", "beetle", 1969); Rhino rhino = new Rhino(); charge(car); charge(rhino); } }
, : Information:2019-02-02 15:20 - Compilation completed with 1 error and 0 warnings in 4 s 395 ms Main.java Error:(43, 11) java: incompatible types: Rhino cannot be converted to Device
Rhino Device, charge().
( — strict variable typing, , Python ) , Java, Python , : « , » ( : " , , , , " – . ). , Python .
Python:
>>> def charge(device): ... if hasattr(device, '_voltage'): ... print(f"Charging a {device._voltage} volt device") ... else: ... print(f"I can't charge a {device.__class__.__name__}") ... >>> class Phone(Device): ... pass ... >>> class Rhino: ... pass ... >>> my_car = Car("yellow", "Beetle", "1966") >>> my_phone = Phone() >>> my_rhino = Rhino() >>> charge(my_car) Charging a 12 volt device >>> charge(my_phone) Charging a 12 volt device >>> charge(my_rhino) I can't charge a Rhino
charge() _voltage. Device , - (Car Phone) , , , . , Device ( Rhino), , , , (rhino) .
Java Object, . , . Object :
class Object { boolean equals(Object obj) { ... } int hashCode() { ... } String toString() { ... } }
equals() , , hashCode() , . Java . , , , .
toString() . . , , , , System.out.println():
Car car = new Car("yellow", "Beetle", 1969); System.out.println(car);
car:
Car@61bbe9ba
, ? , toString(). Car:
public String toString() { return "Car: " + getColor() + " : " + getModel() + " : " + getYear(); }
, , :
Car: yellow : Beetle : 1969
Python (dunder — double underscore). Python- , , , .
Python : repr () str (). repr (), str () . hashcode() toString() Java.
Java, Python :
>>> my_car = Car("yellow", "Beetle", "1966") >>> print(repr(my_car)) <car.Car object at 0x7fe4ca154f98> >>> print(str(my_car)) <car.Car object at 0x7fe4ca154f98>
, str () Python- Car:
def __str__(self): return f'Car {self.color} : {self.model} : {self.year}'
:
>>> my_car = Car("yellow", "Beetle", "1966") >>> print(repr(my_car)) <car.Car object at 0x7f09e9a7b630> >>> print(str(my_car)) Car yellow : Beetle : 1966
. repr (), .
Python , , , .
Python . Python , Java .
Python- Car :
class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year def __str__(self): return f'Car {self.color} : {self.model} : {self.year}' def __eq__(self, other): return self.year == other.year def __lt__(self, other): return self.year < other.year def __add__(self, other): return Car(self.color + other.color, self.model + other.model, int(self.year) + int(other.year))
, :
Python , , , .
Car:
>>> my_car = Car("yellow", "Beetle", "1966") >>> your_car = Car("red", "Corvette", "1967") >>> print (my_car < your_car) True >>> print (my_car > your_car) False >>> print (my_car == your_car) False >>> print (my_car + your_car) Car yellowred : BeetleCorvette : 3933
, , , Java.
– . Java, Python .
. Python type() isinstance () , :
>>> my_car = Car("yellow", "Beetle", "1966") >>> print(type(my_car)) <class 'car.Car'> >>> print(isinstance(my_car, Car)) True >>> print(isinstance(my_car, Device)) True
Java getClass() instanceof :
Car car = new Car("yellow", "beetle", 1969); System.out.println(car.getClass()); System.out.println(car instanceof Car);
:
class com.realpython.Car true
Python dir() , ( ). , getattr():
>>> print(dir(my_car)) ['_Car__cupholders', '__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_voltage', 'color', 'model', 'voltage', 'wheels', 'year'] >>> print(getattr(my_car, "__format__")) <built-in method __format__ of Car object at 0x7fb4c10f5438>
Java , , , .
getFields() . , Car , :
Field[] fields = car.getClass().getFields();
Java , getDeclaredMethods(). get-, , , :
1) getDeclaredMethods()
2) :
:
1 public static boolean getProperty(String name, Object object) throws Exception { 2 3 Method[] declaredMethods = object.getClass().getDeclaredMethods(); 4 for (Method method : declaredMethods) { 5 if (isGetter(method) && 6 method.getName().toUpperCase().contains(name.toUpperCase())) { 7 return true; 8 } 9 } 10 return false; 11 } 12 13
getProperty() – . . true, , false.
Java, Python .
Java- true , , . , getDeclaredMethods() Method. Method invoke(), Method. 7 true, , method.invoke(object).
Python. , Python , , :
>>> for method_name in dir(my_car): ... if callable(getattr(my_car, method_name)): ... print(method_name) ... __add__ __class__ __delattr__ __dir__ __eq__ __format__ __ge__ __getattribute__ __gt__ __init__ __init_subclass__ __le__ __lt__ __ne__ __new__ __reduce__ __reduce_ex__ __repr__ __setattr__ __sizeof__ __str__ __subclasshook__
Python , Java. str () :
>>> for method_name in dir(my_car): ... attr = getattr(my_car, method_name) ... if callable(attr): ... if method_name == '__str__': ... print(attr()) ... Car yellow : Beetle : 1966
, dir(). , getattr(), callable(), . , , str (), .