Kursus
Salah satu faktor yang membuat Python menjadi bahasa pemrograman yang begitu kuat adalah keberadaan magic methods. Di beberapa komunitas Pythonista, Anda mungkin mendengarnya disebut sebagai ‘dunder methods’ karena konstruksi garis bawah ganda yang mereka gunakan.
Perannya di Python adalah menjalankan prosedur yang dikenal sebagai ‘operator overloading,’ yang berarti operator bawaan diberikan makna yang diperluas. Dengan kata lain, operator overloading digunakan untuk menambahkan perilaku khusus ke kelas kita agar dapat digunakan bersama operator Python dan fungsionalitas bawaan.
Dalam artikel ini, kita akan menelusuri lebih dalam magic methods di Python dengan:
- Membedakan perbedaan antara method dan function
- Menjelaskan apa itu magic methods
- Memberikan beberapa contoh Python.
Lihat buku kerja DataLab ini untuk mengikuti kode yang digunakan dalam tutorial ini.
Metode Python vs. Fungsi
Sebelum membahas apa itu magic methods, kita perlu memahami perbedaan antara method dan function di Python.
Python menggunakan method untuk merepresentasikan perilaku sebuah objek. Jadi, method terkait dengan sebuah objek dan akan melakukan operasi pada data di dalam objek tersebut. Faktor pembeda lain dari sebuah method adalah parameter self yang harus selalu muncul sebagai parameter pertama yang diteruskan ke method.
Catatan: Parameter pertama tidak harus bernama self, tetapi para Pythonista secara universal sepakat itu adalah praktik terbaik.
# Example of a method
class Human:
# This is a method
def walk(self):
print("I am walking")
Method bergantung pada kelas yang terkait dengannya. Jadi, untuk memanggil sebuah method, instance dari kelas harus dibuat sebelum method dapat diakses dengan operator titik.
# This will work
joe = Human()
joe.walk()
"""
I am walking
"""
# This will throw a NameError
walk()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_153/2327344440.py in <module>
4
5 # This will throw a NameError
----> 6 walk()
NameError: name 'walk' is not defined
Sebaliknya, function berbeda: kita tidak perlu membuat instance kelas.
Fungsi Python adalah langkah-langkah yang dijalankan sebagai blok kode hanya saat dipanggil. Fungsi didefinisikan secara independen dari objek kelas mana pun, artinya dapat dipanggil langsung dengan namanya. Karena tidak terkait dengan kelas mana pun, kita tidak perlu meneruskan self sebagai parameter – parameter bersifat opsional.
Pada dasarnya, function hanyalah serangkaian instruksi terdefinisi dengan baik yang digunakan interpreter untuk melakukan suatu tugas.
# Example of a function
def run():
print("I am running.")
run()
"""
I am running.
"""
Seperti dibahas dalam artikel Cara memanggil dan menulis fungsi, function juga hadir dalam dua jenis: bawaan dan yang ditentukan pengguna.
- Fungsi bawaan: Fungsi yang disertakan dalam pustaka standar Python.
- Fungsi yang ditentukan pengguna: Fungsi yang didefinisikan oleh pengguna - Python mengizinkan pengguna untuk mendefinisikan dan menggunakan fungsi mereka sendiri yang dapat diakses dalam program Python.
Dalam banyak hal, method dan function itu identik - misalnya, keduanya didefinisikan dengan pernyataan def. Perbedaan mendasarnya adalah method terkait dengan sebuah objek dan digunakan untuk mengoperasikan data yang terdapat dalam sebuah kelas, sedangkan function didefinisikan secara independen dan dapat dipanggil dengan namanya di mana saja dalam program.
Apa itu magic methods di Python?
Di awal tutorial, kami menyebutkan bahwa magic methods juga disebut sebagai dunder methods karena konstruksi garis bawah ganda. Maksudnya, semua magic methods Python diawali dan diakhiri dengan dua garis bawah.
Magic method yang paling dikenal adalah method __init__, yang memungkinkan sebuah kelas diinisialisasi dengan atribut tertentu.
class Employee:
def __init__(self, name, age, role):
self.name = name
self.age = age
self.role = role
Untuk membuat instance dari kelas ini, kita harus menyertakan atribut name, age, dan role pada instance tersebut. Contohnya:
user_1 = Employee(name="John", age=24, role="Data Scientist")
Jika tidak, akan muncul TypeError.
Method __init__ termasuk dalam kategori magic method inisialisasi dan konstruksi, tetapi ini hanya salah satu dari banyak method. Tabel di bawah merinci beberapa magic method inisialisasi dan konstruksi lainnya.
|
__new__(cls, other) |
Digunakan untuk membuat instance baru dari sebuah kelas |
|
__init__(self, other) |
Dipanggil setelah instance baru dibuat; Semua atribut yang diteruskan ke ekspresi konstruktor kelas akan digunakan sebagai atribut. |
|
__del__(self) |
Juga dikenal sebagai destruktor; Dipanggil ketika sebuah instance akan dihancurkan. |
Cara termudah untuk memaknai magic methods adalah sebagai sebuah kontrak antara implementasi Anda dan interpreter Python. Salah satu butir kontrak mengharuskan Python melakukan beberapa aksi di balik layar dari kondisi tertentu, seperti menginisialisasi instance kelas dengan objek tertentu.
Dengan kata lain, bukan tanggung jawab Anda untuk memanggil magic method secara langsung – Python yang melakukannya untuk Anda di balik layar.
Metode representasi string
Python adalah bahasa pemrograman berorientasi objek (OOP) – segala sesuatu di Python adalah objek. Ketika objek baru dibuat, kita secara implisit membuat objek terkait karena semua kelas mewarisi dari object.
Catatan: Anda juga dapat membuat pewarisan bersifat eksplisit dengan meneruskan class object ke kelas Anda.
# This works
class Car:
pass
# This also works
class Vehicle(object):
pass
car = Car()
vehicle = Vehicle()
print(car, vehicle, sep="\n")
"""
<__main__.Car object at 0x7f80449dc0a0>
<__main__.Vehicle object at 0x7f80449dc1f0>
"""
Pada kode di atas, kita membuat dua kelas kosong, tetapi interpreter Python tetap mengetahui apa yang harus dicetak saat kita memanggil pernyataan print. Hal ini dimungkinkan karena semua kelas mewarisi dari kelas object (induk semua kelas di Python), dan kelas tersebut memiliki magic method bernama __repr__, yang dipanggil oleh pernyataan print untuk mengembalikan nilai ke program utama kita.
Mereka yang akrab dengan pewarisan akan tahu bahwa kelas anak dapat menimpa kelas induknya dengan mendefinisikan method sendiri dengan nama yang sama.
# Overriding the object __repr__
class Vehicle:
def __repr__(self):
return f"{self.__class__.__qualname__}"
vehicle = Vehicle()
print(vehicle)
"""
Vehicle
"""
Anda juga dapat menggunakan magic method __str__ untuk membuat representasi string yang dipanggil dengan pernyataan print.
Faktanya, magic method __repr__ berfungsi sebagai perilaku cadangan untuk magic method __str__. Jadi, saat kita memanggil pernyataan print, Python terlebih dahulu mencari method __str__ yang didefinisikan di kelas Anda sebelum kembali ke method __repr__.
# Using __str__ for string representation
class Vehicle:
def __str__(self):
return f"{self.__class__.__qualname__}"
vehicle = Vehicle()
print(vehicle)
"""
Vehicle
"""
Tabel di bawah berisi daftar magic method representasi string lainnya.
|
__str__(self) |
Dipanggil oleh fungsi bawaan str() Python dan oleh pernyataan print untuk menampilkan representasi string informal dari sebuah objek. Perlu dicatat bahwa ini tidak harus berupa ekspresi Python yang valid. |
|
__repr__(self) |
Dipanggil oleh fungsi bawaan repr() Python dan konversi string untuk menampilkan representasi string resmi dari sebuah objek. Perlu dicatat bahwa ini sebaiknya tampak seperti ekspresi Python yang valid, tetapi jika tidak memungkinkan, string dengan deskripsi yang berguna lebih disukai. |
|
__unicode__(self) |
Dipanggil untuk mengimplementasikan fungsi bawaan unicode() Python dan mengembalikan objek Unicode. |
|
__hash__(self) |
Dipanggil oleh fungsi bawaan hash() Python dan operasi pada anggota koleksi yang di-hash. Method ini harus mengembalikan bilangan bulat. |
|
__nonzero__(self) |
Dipanggil oleh operasi bawaan bool() Python untuk mengimplementasikan pengujian nilai kebenaran. Method ini harus mengembalikan True atau False (atau padanannya berupa bilangan bulat 1 atau 0). |
Metode “sulap” enkapsulasi
Enkapsulasi adalah salah satu konsep fundamental dalam pemrograman berorientasi objek (OOP). Ini mengacu pada pengikatan data dengan method yang beroperasi pada data tersebut atau membatasi akses langsung ke komponen tertentu dalam sebuah objek.
Pengembang yang berasal dari bahasa OOP lain kerap memperdebatkan ketidakmampuan Python untuk benar-benar menerapkan enkapsulasi pada kelas. Mereka terbiasa memiliki modifier eksplisit untuk method atau field yang memungkinkan mereka mendefinisikan hal-hal seperti atribut privat dengan getter dan setter publik. Perbedaannya di Python adalah banyak enkapsulasi yang ada terjadi melalui magic methods.
Misalnya, __setattr__ adalah solusi enkapsulasi yang memungkinkan kita mendefinisikan perilaku untuk penugasan ke sebuah atribut terlepas dari keberadaannya. Dengan kata lain, aturan dapat didefinisikan untuk perubahan nilai atribut.
import string
class Alphabet():
def __setattr__(self, name, value):
self.__dict__[name] = value.upper()
a = Alphabet()
# Assinging an attribute that does not exist
# The setattr should convert it to caps despite being set as lowercase
a.alphabet = string.ascii_lowercase
print(a.alphabet)
Pada kode di atas, kita membuat kelas bernama Alphabet tanpa atribut, tetapi kita memberi tahu Python bahwa kita ingin mengubah menjadi huruf besar setiap atribut instance kelas yang kita setel.
Kami memahami bahwa OOP mungkin terasa agak jauh bagi sebagian pembaca. Untuk menyegarkan pemahaman OOP di Python, lihat Python Programmer Track dari DataCamp.
Magic methods matematika
Kategori lain dari magic methods Python adalah magic methods matematika (juga dikenal sebagai operator aritmetika normal). Ekspresi dibuat menggunakan simbol khusus yang kita sebut ‘operator’ di Python. Menggunakan operator seperti itu dalam sebuah ekspresi melibatkan pembuatan objek dengan magic methods matematika. Jika tidak mematuhinya, akan muncul TypeError.
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
set_a = Numbers(2, 4)
set_b = Numbers(3, 5)
print(set_a + set_b)
"""
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_152/3639634723.py in <module>
7 set_b = Numbers(3, 5)
8
----> 9 print(set_a + set_b)
TypeError: unsupported operand type(s) for +: 'Numbers' and 'Numbers'
"""
Pada kode di atas, kita mencoba membuat beberapa instance dari kelas Numbers dan menambahkannya bersama-sama yang memunculkan error seperti yang diharapkan. Salah satu solusi untuk error ini adalah membuat method di kelas kita untuk menjumlahkan angka, tetapi ini akan mencegah kita membuat ekspresi.
Solusi yang lebih baik adalah mengimplementasikan magic method __add__ sebagai berikut:
# Using add operator
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
# Only permit Numbers objects to be added
if not isinstance(other, Numbers):
return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)
def __repr__(self):
return f"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2, 4)
b = Numbers(3, 5)
print(a + b) # Should result in Numbers(5, 9)
"""
RandomNumbers(5, 9)
"""
Contoh kode di atas hanya memungkinkan kita menambahkan dua objek Numbers. Mari kita implementasikan magic method matematika lain yang memungkinkan kita mengalikan objek Numbers dengan bilangan bulat.
# Multiplying Numbers with an integer
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
# Only permit Numbers objects to be added
if not isinstance(other, Numbers):
return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)
def __mul__(self, other):
if not isinstance(other, int):
return NotImplemented
return Numbers(self.a * other, self.b * other)
def __repr__(self):
return f"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2, 4)
print(a * 5) # Should return 10, 20
"""
RandomNumbers(10, 20)
"""
Pada kode di atas, kita menambahkan magic method __mul__ untuk memungkinkan kita mengalikan angka dari kelas kustom kita dengan bilangan bulat.
Perhatikan objek Numbers berada di sisi kiri operator * - ini bukan kebetulan. Mari letakkan di sisi kanan operator dan lihat apa yang terjadi.
- snip --
a = Numbers(2, 4)
print(3 * a)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_152/2857655049.py in <module>
1 a = Numbers(2, 4)
----> 2 print(3 * a)
TypeError: unsupported operand type(s) for *: 'int' and 'Numbers'
Python melempar TypeError.
Magic method __mul__ yang kita implementasikan hanya berlaku ketika objek Numbers berada di sisi kiri operator *. Untuk memperluas fungsionalitas ini, kita harus menambahkan magic method kebalikan, __rmul__.
# Enabling reverse multiplication
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
# Only permit Numbers objects to be added
if not isinstance(other, Numbers):
return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)
def __mul__(self, other):
if not isinstance(other, int):
return NotImplemented
return Numbers(self.a * other, self.b * other)
def __rmul__(self, other):
return self.__mul__(other)
def __repr__(self):
return f"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2, 4)
print(5 * a) # Should return 10, 20
"""
Numbers(10, 20)
"""
Sekarang kita dapat membuat ekspresi perkalian tanpa harus mempertimbangkan di sisi mana objek Numbers muncul terhadap operator.
Penutup
Prinsip dasar memanfaatkan magic methods di Python tetap sama: buat kelas dan timpa magic method milik kelas object. Ada begitu banyak magic methods di Python, sehingga tutorial ini akan menjadi sangat panjang jika kita membahas semuanya satu per satu. Kami sangat menyarankan Anda memeriksa dokumentasi Python untuk mendapatkan gambaran tentang cakupan penuh magic methods di Python yang dapat Anda gunakan untuk meningkatkan keterampilan pemrograman Python Anda.
