*args
Sintaks khusus *args
pada fungsi di Python digunakan untuk melewatkan sembarang jumlah argumen ke fungsi. *args
ini digunakan untuk melewatkan satu atau beberapa argumen non kata kunci.
*args
Sintaks khusus *args
pada fungsi di Python digunakan untuk melewatkan sembarang jumlah argumen ke fungsi. *args
ini digunakan untuk melewatkan satu atau beberapa argumen non kata kunci.
Pada artikel ini, kita akan mempelajari tentang decorator, cara membuat decorator, dan kapan kita sebaiknya menggunakan decorator.
Tabel Konten
Pengertian Decorator
Python memiliki sebuah fitur menarik bernama decorator yang berfungsi menambah fungsionalitas pada kode program.
Hal ini disebut juga metaprogramming karena ada bagian dari program yang mencoba untuk memodifikasi bagian lainnya pada saat eksekusi.
Syarat Sebelum Mempelajari Decorator
Sebelum dapat memahami tentang decorator, kita harus terlebih dahulu memahami dasar – dasar Python.
Kita harus paham terlebih dahulu bahwa semua yang ada di Python adalah objek (termasuk kelas). Nama pengenal, seperti variabel yang kita deklarasikan merujuk kepada objek tersebut. Begitu juga dengan fungsi. Fungsi adalah termasuk objek juga. Satu objek bisa memiliki banyak pengenal (identifier) yang merujuk kepadanya.
Perhatikan contoh berikut
def first(msg):
print(msg)
first("Hello")
second = first
second("Hello")
Pada saat kode di atas dijalankan, kedua fungsi first
dan second
menampilkan output yang sama. Di sini, variabel first
dan second
merujuk pada objek fungsi yang sama.
Sekarang mari kita tinjau hal yang lain. Sebuah fungsi bisa dijadikan sebagai argumen dari fungsi yang lain.
Bila Anda sudah pernah menggunakan fungsi seperti map
, filter
, dan reduce
di Python, maka Anda sudah tahu tentang hal ini.
Fungsi yang menjadikan fungsi lain sebagai argumen disebut juga fungsi dengan orde yang lebih tinggi. Berikut adalah contohnya:
def inc(x):
return x + 1
def dec(x):
return x - 1
def operate(func, x):
result = func(x)
return result
Kita bisa memanggil fungsi tersebut seperti berikut:
>>> operate(inc, 3) 4 >>> operate(dec, 3) 2
Lebih lanjut lagi, sebuah fungsi bisa mengembalikan fungsi lain.
def is_called():
def is_returned():
print("Hello")
return is_returned
new = is_called()
#Outputs "Hello"
new()
Pada contoh tersebut, is_returned()
adalah fungsi bersarang yang didefinisikan dan dikembalikan tiap kali fungsi is_called()
dipanggil.
Selain memahami tentang hal di atas, kita juga sudah harus paham tentang python closure
Kembali ke Decorator
Sebuah decorator mengambil fungsi sebagai argumennya, menambahkan beberapa hal, dan kemudian mengembalikannya.
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
Bila kode di atas kita jalankan pada mode interaktif, maka hasilnya adalah seperti berikut:
>>> ordinary() I am ordinary >>> # Mari kita buat decorator dari fungsi ordinary >>> pretty = make_pretty(ordinary) >>> pretty() I got decorated I am ordinary
Pada contoh di atas, make_pretty()
adalah sebuah decorator.
Pada baris perintah pretty = make_pretty(ordinary)
, fungsi ordinary
didekorasi dan fungsi kembaliannya diberi nama pretty
.
Kita bisa lihat bahwa fungsi decorator menambahkan beberapa fungsionalitas ke fungsi asli. Hal ini mirip dengan pengemasan kado. Decorator bertindak sebagai bungkusnya. Objek yang didekorasi (isi kado) tidak berubah. Akan tetapi, ketika dibungkus, akan terlihat lebih bagus (karena didekorasi).
Umumnya, kita mendekorasi fungsi dan menyimpannya ke variabel seperti berikut:
ordinary = make_pretty(ordinary)
Python memiliki sintaks yang lebih sederhana untuk penulisan fungsi di atas yaitu dengan menggunakan tanda @
diikuti oleh nama fungsi decorator. Kita menempatkannya di atas fungsi yang akan didekorasi. Maka contoh berikut ini:
@make_pretty def ordinary(): print("I am ordinary")
adalah sama dengan yang berikut:
def ordinary(): print("I am ordinary") ordinary = make_pretty(ordinary)
Cara yang menggunakan tanda @
di atas adalah sintaks yang lebih elegan untuk mengimplementasikan decorator.
Dekorasi Fungsi Dengan Parameter
Decorator di atas sangat sederhana dan hanya berlaku untuk fungsi yang tidak memiliki parameter. Bagaimana jika fungsi yang akan didekorasi memiliki argumen seperti berikut?
def divide(a, b): return a/b
Fungsi tersebut memiliki 2 parameter, a
dan b
. Bila kita melewatkan nilai 0 ke b
, maka akan terjadi error ZeroDivisionError
.
>>> divide(2, 5) 0.4 >>> divide(2, 0) Traceback (most recent call last): ... ZeroDivisionError: division by zero
Sekarang kita akan membuat decorator untuk mengecek penyebab error ini.
def smart_divide(func):
def inner(a,b):
print("Saya akan membagi",a,"dan",b)
if b == 0:
print("Whoops! tidak bisa membagi dengan 0")
return
return func(a,b)
return inner
@smart_divide
def divide(a,b):
return a/b
Kode yang menggunakan decorator ini akan mengembalikan None
jika terjadi error.
>>> divide(2, 5) Saya akan membagi 2 dan 5 0.4 >>> divide(2, 0) Saya akan membagi 2 dan 0 Whoops! tidak bisa membagi dengan 0
Dengan cara tersebut kita bisa mendekorasi fungsi yang memiliki parameter.
Bila kita perhatikan dengan baik, kita akan melihat kalau semua parameter dari fungsi yang di dalam decorator akan menjadi parameter dari fungsi yang didekorasi. Dengan itu, kita bisa membuat decorator yang lebih umum yang dapat bekerja dengan berapapun jumlah parameternya.
Di Python, hal ini dapat dilakukan dengan sintaks function(*args, **kwargs)
di mana args
adalah tuple dari argumen – argumen berdasarkan posisi, dan kwargs
adalah dictionary dari argumen – argumen ber-keyword.
Berikut ini adalah contoh fungsi inner()
yang memiliki sembarang parameter didekorasi oleh fungsi works_for_all()
.
def works_for_all(func): def inner(*args, **kwargs): print("Saya bisa mendekorasi fungsi apa saja") return func(*args, **kwargs) return inner()
Menggabungkan Decorator di Python
Beberapa decorator bisa dihubungkan atau digabungkan. Sebuah fungsi bisa didekorasi beberapa kali dengan satu atau beberapa fungsi decorator. Kita meletakkan decorator di atas fungsi yang akan didekorasi. Untuk jelasnya perhatikan contoh berikut:
def star(func):
def inner(*args, **kwargs):
print("*" * 30)
func(*args, **kwargs)
print("*" * 30)
return inner
def percent(func):
def inner(*args, **kwargs):
print("%" * 30)
func(*args, **kwargs)
print("%" * 30)
return inner
@star
@percent
def printer(msg):
print(msg)
printer("Hello")
Outputnya akan tampak seperti berikut:
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
Kode decorator di atas yaitu:
@star @percent def printer(msg): print(msg)
adalah sama dengan:
def printer(msg): print(msg) printer = star(percent(printer))
Urutan dari decorator perlu diperhatikan. Bila kita mengubah urutannya menjadi:
@percent @star def printer(msg): print(msg)
maka hasilnya akan menjadi:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Pada artikel ini, kita akan mempelajari tentang closure (pembungkus), cara mendefinisikan closure, dan alasan mengapa closure digunakan.
Tabel Konten
Variabel Non-lokal Dalam Fungsi Bersarang
Sebelum membahas tentang closure, pertama kali kita harus memahami tentang fungsi bersarang dan variabel non-lokal.
Fungsi bersarang adalah fungsi yang didefinisikan di dalam fungsi lain. Fungsi bersarang ini dapat mengakses variabel dari scope (lingkup) fungsi pembungkusnya.
Di Python, variabel non-lokal defaultnya adalah bersifat read only. Untuk dapat memodifikasinya, kita harus mendeklarasikannya sebagai variabel non-lokal (menggunakan keyword nonlocal
).
Berikut ini adalah contoh fungsi bersarang dan variabel non-lokal.
def print_msg(msg):
# Ini adalah fungsi pembungkus luar
def printer():
# Ini adalah fungsi bersarang
print(msg)
printer()
# Eksekusi fungsi
# Output: Hello
print_msg("Hello")
Bisa kita lihat pada contoh di atas, bahwa fungsi printer()
dapat mengakses variabel non-lokal msg
dari fungsi pembungkusnya.
Mendefinisikan Fungsi Closure
Pada contoh di atas, apa yang terjadi bila baris terakhir fungsi print_msg()
mengembalikan fungsi printer()
dan bukan memanggilnya? Perhatikan contoh berikut.
def print_msg(msg):
# Ini adalah fungsi pembungkus
def printer():
# Ini adalah fungsi bersarang
print(msg)
return printer # baris ini diubah dari yang sebelumnya
# Mari kita panggil fungsinya
# Output: Hello
another = print_msg("Hello")
another()
Hasilnya tampak tidak biasa. Fungsi print_msg()
dipanggil dengan argumen "Hello"
dan fungsi kembaliannya dirujuk ke variabel another
sehingga another
menjadi fungsi. Pada saat pemanggilan another()
, pesan yang ada masih tetap eksis meskipun kita sudah selesai mengeksekusi fungsi print_msg()
. Padahal pada fungsi biasa, seharusnya variabel fungsi akan terhapus begitu eksekusi terhadap fungsi selesai.
Nilai yang ada pada scope fungsi pembungkus masih diingat meskipun variabel sudah di luar scope fungsi, atau bahkan setelah fungsi tersebut dihapus seperti pada contoh berikut.
>>> del print_msg >>> print_msg("Hello") Traceback (most recent call last): ... NameError: name 'print_msg' is not defined >>> another() Hello
Kriteria Closure
Seperti terlihat dari contoh di atas, kita memiliki closure di Python pada saat fungsi bersarang (fungsi yang di dalam) merujuk pada variabel yang ada pada fungsi pembungkusnya.
Kriteria yang harus ada untuk membuat closure di Python adalah sebagai berikut:
Kapan Closure Digunakan?
Closure digunakan untuk menghindari penggunaan variabel global dan menyediakan fungsi penyembunyian data (data hiding) sebagai solusi berorientasi objek terhadap permasalahan.
Jika hanya sedikit (umumnya satu buah) metode yang hendak diimplementasikan pada sebuah kelas, kita lebih baik menggunakan closure daripada mendefinisikan kelas. Tapi, ketika banyak atribut dan metode yang akan dibuat, kita lebih baik menggunakan kelas.
Berikut ini adalah contoh di mana penggunaan closure lebih disarankan ketimbang menggunakan kelas untuk menciptakan objek. Tapi semua terserah pilihan Anda.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Perkalian 3
times3 = make_multiplier_of(3)
# Perkalian 5
times5 = make_multiplier_of(5)
# Output: 27
print(times3(9))
# Output: 15
print(times5(3))
# Output: 30
print(times5(times3(2)))
Closure ini banyak dipergunakan dalam decorator di Python.
Pada artikel ini, kita akan belajar cara menciptakan iterasi menggunakan generator, apa perbedaan generator dengan iterator dan fungsi, dan mengapa kita harus menggunakan generator.
Tabel Konten
Pengertian Generator
Ada banyak hal yang berlebihan (overhead) di dalam membuat iterator di Python. Pertama, kita harus membuat kelas yang menggunakan metode __iter__()
dan __next__()
. Kemudian kita juga harus menjaga state dari item, dan harus membangkitkan StopIteration
pada saat tidak ada lagi item yang tersedia.
Hal ini agak panjang dan rumit. Dalam hal ini, untuk menghindari hal tersebut, kita bisa menggunakan generator.
Generator di Python adalah cara sederhana membuat iterator. Semua overhead yang kita sebutkan di atas, akan ditangani secara otomatis oleh generator.
Singkatnya, generator adalah fungsi yang mengembalikan sebuah objek iterator yang padanya bisa kita lakukan iterasi (satu nilai per satu waktu).
Cara Membuat Generator di Python
Cukup mudah untuk membuat generator di Python. Mirip dengan membuat fungsi biasa. Hanya saja, kita menggantikan pernyataan return
dengan yield
.
Fungsi yang memiliki minimal satu yield
(fungsi bisa berisi lebih dari satu yield
atau return
), akan menjadi fungsi generator. yield
maupun return
sama – sama berfungsi mengembalikan suatu nilai dari sebuah fungsi.
Perbedaan return
dan yield
adalah, return
akan menghentikan (terminasi) fungsi secara keseluruhan, sementara yield
hanya akan menghentikan sementara (pause) fungsi dan menyimpan semua state variabel yang di dalamnya untuk nantinya bisa dilanjutkan kembali dari state tersebut.
Perbedaan Fungsi Generator dan Fungsi Biasa
Berikut adalah perbedaan fungsi generator dengan fungsi biasa:
yield
__iter__()
dan __next__()
sudah diimplementasikan secara otomatis. Jadi kita bisa langsung melakukan iterasi dengan fungsi next()
.yield
, fungsi akan pause dan kendali ditransfer kembali ke pemanggil.StopIteration
dipanggil secara otomatis.Berikut adalah contoh generator dengan beberapa pernyataan yield
# Fungsi generator sederhana
def my_gen():
n = 1
print('This is printed first')
# Fungsi generator berisi pernyataan yield
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
Selanjutnya, hasilnya bisa dijalankan pada mode interaktif seperti berikut:
>>> # my_gen() mengembalikan objek iterator, tapi tidak langsung mengeksekusinya >>> a = my_gen() >>> # Kita bisa melakukan iterasi pertama menggunakan next() >>> next(a) This is printed first 1 >>> # Sekali fungsi menemukan yield, fungsi akan dipause >>> # dan kendali dikembalikan ke pemanggil >>> # Variabel lokal dan state-nya akan diingat untuk pemanggilan selanjutnya >>> next(a) This is printed second 2 >>> next(a) This is printed at last 3 >>> Terakhir, fungsi diterminasi, StopIterasi otomatis dibangkitkan >>> next(a) Traceback (most recent call last): ... StopIteration
Salah satu hal yang perlu diperhatikan untuk contoh di atas adalah, nilai dari variabel n
tetap diingat pada tiap pemanggilan fungsi.
Berbeda dengan fungsi normal, variabel lokal tidak akan dihancurkan pada saat pernyataan yield
. Selain itu, objek generator hanya bisa diiterasi untuk sekali saja. Untuk mengulang kembali proses, kita harus membuat generator lain menggunakan pernyataan seperti misalnya a = my_gen()
.
Kita juga bisa menggunakan generator di dalam loop for
secara langsung. Hal ini karena loop for
memakai iterator dan melakukan iterasi padanya menggunakan fungsi next()
. StopIteration
otomatis dilakukan pada akhir iterasi.
# Fungsi generator sederhana
def my_gen():
n = 1
print('This is printed first')
# Fungsi generator berisi pernyataan yield
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
# Menggunakan loop for
for item in my_gen():
print(item)
Pada saat contoh di atas dijalankan, hasilnya akan tampak seperti berikut:
This is printed first 1 This is printed second 2 This is printed at last 3
Generator Menggunakan Loop
Contoh-contoh di atas jarang dipakai. Kita mempelajarinya hanya untuk tahu teknisnya apa yang sebenarnya terjadi pada generator.
Umumnya, fungsi generator diterapkan pada loop yang memiliki kondisi terminasi (penghentian) yang sesuai.
Mari kita buat contoh generator yang berfungsi membalikkan sebuah string.
def rev_str(my_str):
length = len(my_str)
for i in range(length - 1,-1,-1):
yield my_str[i]
# Loop for untuk membalikkan string
# Output:
# o
# l
# l
# e
# h
for char in rev_str("hello"):
print(char)
Pada contoh di atas, kita menggunakan fungsi range()
untuk mendapatkan indeks secara terbalik yang digunakan dalam loop for
.
Fungsi generator seperti itu tidak hanya berlaku untuk string, tapi juga untuk iterable lainnya seperti list, tuple, dan lain – lain.
Generator Expression
Generator sederhana bisa dibuat dengan menggunakan generator expression. Dengan generator expression ini, pembuatan generator menjadi mudah.
Mirip dengan fungsi lambda yang membuat fungsi anonim, generator expression juga membuat sebuah fungsi generator anonim.
Sintaks dari generator expression mirip dengan list comprehension. Hanya saja tanda kurung [ ]
digantikan dengan tanda kurung ( )
.
Perbedaan utama antara list comprehension dengan generator expression adalah, list comprehension langsung menghasilkan keseluruhan anggota list, sedangkan generator expression menghasilkannya satu item per satu waktu.
Tipe seperti generator expression ini sering disebut tipe lazy (malas), karena hanya memproduksi item pada saat diminta. Hal inilah yang menyebabkan generator expression lebih hemat memori ketimbang list comprehension.
# Membuat list
my_list = [1, 3, 6, 10]
# Tanda [ ] untuk list comprehension
# Output: [1, 9, 36, 100]
[x**2 for x in my_list]
# Hal yang sama bisa menggunakan generator expression
# Output: generator object genexpr at 0x0000000002EBDAF8
(x**2 for x in my_list)
Kita bisa lihat di atas, bahwa generator expression tidak langsung memproduksi hasil secara keseluruhan. Generator expression ini hanya mengembalikan item bila diminta.
# Membuat list
my_list = [1, 3, 6, 10]
a = (x**2 for x in my_list)
# Output: 1
print(next(a))
# Output: 9
print(next(a))
# Output: 36
print(next(a))
# Output: 100
print(next(a))
# Output: StopIteration
next(a)
Generator expression juga bisa digunakan sebagai argumen fungsi. Bila demikian, tanda kurungnya bisa dihilangkan. Misalnya pada fungsi sum()
dan max()
seperti berikut:
>>> my_list = [1, 3, 6, 10] >>> sum(x**2 for x in my_list) 146 >>> max(x**2 for x in my_list) 100
Alasan Penggunaan Generator
Ada beberapa hal yang menjadi alasan penggunaan generator, yaitu sebagai berikut:
1. Mudah diterapkan
Generator bisa diterapkan dengan lebih mudah dan ringkas dibandingkan dengan kelas iterator. Berikut ini contoh penggunaan kelas iterator untuk menghasilkan deret bilangan pangkat 2 dari 0 sampai yang bilangan ditentukan.
class PowTwo: def __init__(self, max=0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n > self.max: raise StopIteration result = 2 ** self.n self.n += 1 return result
Dan berikut hasilnya sama dengan menggunakan fungsi generator.
def PowTwoGen(max = 0): n = 0 while n < max: yield 2 ** n n += 1
Dari contoh di atas, terlihat bahwa penggunaan generator lebih mudah dan ringkas dibandingkan iterator.
2. Lebih Hemat Memori
Fungsi biasa yang dibuat untuk menghasilkan sequence, akan menyimpan keseluruhan sequence sebelum mengembalikan hasilnya. Hal ini akan menghabiskan memori bila jumlah itemnya sangat besar.
Sementara itu, generator jauh lebih hemat memori karena hanya memproduksi item satu persatu yaitu hanya saat dipanggil.
3. Merepresentasikan Stream Tak Berhingga (Infinite Stream)
Generator adalah cara yang paling bagus untuk mewakili aliran data yang tak berhingga. Stream (aliran) data yang tak berhingga, tidak bisa disimpan dalam memori, sehingga cocok menggunakan generator.
Berikut adalah contoh untuk membangkitkan semua bilangan genap yang ada (setidaknya secara teoritis saja)
def all_even(): n = 0 while True: yield n n += 2
4. Pipelining Generator
Pipeline adalah menjadikan input dari sebuah proses menjadi proses dari operasi yang lain. Generator bisa digunakan untuk pipeline dari serangkaian operasi. Hal ini akan lebih jelas bila diilustrasikan dengan contoh.
Anggaplah kita mempunyai sebuah file log dari rantai makanan cepat saji terkenal. File log ini memiliki sebuah kolom (kolom ke-4) yang mencatat jumlah pizza yang terjual setiap jam dan kita ingin menjumlahkannya untuk mendapatkan jumlah pizza yang terjual dalam 5 tahun.
Kita asumsikan bahwa semua yang kosong di kolom ke 4 sebagai 'N/A'
. Maka, generator yang bisa diterapkan untuk hal ini adalah seperti berikut.
with open('penjualan.log') as file: pizza_col = (line[3] for line in file) per_jam = (int(x) for x in pizza_col if x != 'N/A') print("Total pizza terjual = ", sum(per_jam))
Pipelining menjadikan kode menjadi lebih efisien dan mudah dibaca.
Iterator adalah objek yang padanya bisa dilakukan iterasi. Di tutorial ini, kita akan mempelajari bagaimana cara kerja iterator dan cara membuat iterator kita sendiri menggunakan metode __iter__
dan __next__
.
Tabel Konten:
Pengertian Iterator
Iterator di Python ada di mana – mana. Iterator ini sebenarnya sudah diterapkan di dalam looping for
, list comprehension, generator, dan lain – lain, hanya saja tidak tampak secara langsung.
Iterator di Python sederhananya hanyalah suatu objek yang padanya dapat dilakukan iterasi atau looping. Objek akan mengembalikan data, satu data per satu waktu.
Secara teknis, Objek iterator di Python harus menerapkan dua metode, yaitu __iter__()
dan __next__()
, yang disebut dengan protokol iterator.
Suatu objek dikatakan iterable jika dari objek tersebut bisa kita buat iterator. Sebagian besar objek di Python seperti list, tuple, string, dan lain-lain adalah iterable.
Fungsi iter()
(fungsi yang memanggil metode __iter__()
) akan mengembalikan iterator dari iterable yang menjadi argumennya.
Iterasi Menggunakan Iterator di Python
Kita menggunakan fungsi next()
untuk melakukan iterasi pada semua item di iterator. Pada saat iterasi mencapai item terakhir dan tidak ada lagi data untuk dikembalikan, maka fungsi ini akan memunculkan StopIteration
. Berikut adalah contohnya.
# mendefinisikan list
my_list = [4, 7, 0, 3]
# membuat iterator dengan iter()
my_iter = iter(my_list)
# iterasi pada my_iter menggunakan next()
# print 4
print(next(my_iter))
# print 7
print(next(my_iter))
# next(obj) sama dengan obj.__next__()
# print 0
print(my_iter.__next__())
# print 3
print(my_iter.__next__())
# Berikut ini akan memunculkan error karena item sudah habis
next(my_iter)
Cara yang lebih bagus untuk melakukan iterasi pada iterator adalah dengan menggunakan loop for
. Misalnya adalah seperti berikut:
>>> for item in my_list print(item) 4 7 0 3
Bagaimana Loop Bekerja?
Seperti kita lihat pada contoh diatas, loop for
bisa melakukan iterasi otomatis pada list.
Seperti kita ketahui, loop for
bisa melakukan iterasi pada iterable. Mari kita lihat lebih dekat bagaimana loop for
diimplementasikan pada Python.
for item in iterable: # proses item
Di belakang layar, implementasi dari for
di atas adalah sebagai berikut:
# membuat iterator dari iterable iter_obj = iter(iterable) # loop infinite while True: try: # memanggil item selanjutnya item = next(iter_obj) # lakukan sesuatu pada item except StopIteration: # jika muncul StopIteration, keluar dari loop break
Jadi, secara internal, loop for
menciptakan objek iterator, iter_obj
dengan memanggil fungsi iter()
.
Loop for
ini sebenarnya adalah sebuah loop while
infinite (tak berhingga).
Di dalam loop, fungsi next()
akan dipanggil untuk mendapatkan item berikutnya dan body dari loop for
akan dieksekusi menggunakan nilai item bersangkutan. Setelah semua item habis, StopIteration
akan dimunculkan dan ini menandai akhir dari loop.
Membangun Iterator Sendiri
Membangun iterator dari dasar adalah hal yang mudah. Kita hanya perlu menerapkan metode __iter__()
dan __next__()
.
Metode __iter__()
akan mengembalikan objek iterator. Bila diperlukan, beberapa pengaturan awal bisa dilakukan.
Metode __next__()
akan mengembalikan item selanjutnya yang ada di dalam sequence. Saat sudah mencapai item terakhir, maka pemanggilan berikutnya akan menghasilkan StopIteration
.
Berikut contoh program yang menampilkan pangkat 2 dari bilangan setiap kali iterasi. Eksponennya mulai dari nol sampai bilangan yang diset oleh user.
class PowTwo:
"""Kelas yang mengimplementasikan iterator pangkat dua"""
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
Selanjutnya kita dapat membuat iterator dan melakukan iterasi seperti berikut
>>> a = PowTwo(4) >>> i = iter(a) >>> next(i) 1 >>> next(i) 2 >>> next(i) 4 >>> next(i) 8 >>> next(i) 16 >>> next(i) Traceback (most recent call last): ... StopIteration
Kita juga bisa melakukan iterasi menggunakan loop for pada iterator yang sudah kita buat.
>>> for i in PowTwo(5): print(i) 1 2 4 8 16 32
Iterator Tak Berhingga (Infinite Iterator)
Kadangkala kita memerlukan iterator yang itemnya tidak akan habis. Tapi kita harus hati – hati untuk menangani iterator seperti ini.
Berikut ini akan ditunjukkan contoh dari iterator tak berhingga.
Fungsi built-in iter()
dapat dipanggil menggunakan dua argumen, di mana argumen pertama adalah objek callable (sebuah fungsi) dan yang kedua adalah sentinel/penentu. Iterator memanggil fungsi ini sampai nilai yang dikembalikan sama dengan nilai sentinel.
>>> int() 0 >>> inf = iter(int, 1) >>> next(inf) 0 >>> next(inf) 0
Kita bisa lihat bahwa fungsi int()
tanpa argumen akan selalu mengembalikan nilai 0. Oleh sebab itu, saat fungsi int()
dilewatkan ke iter(int, 1)
, akan dikembalikan iterator yang memanggil fungsi int()
terus menerus sampai nilainya sama dengan sentinel 1. Dan hal ini,nilai 1 tidak akan pernah terjadi, sehingga yang didapat adalah iterator tak berhingga.
Kita juga bisa membuat iterator tak berhingga kita sendiri. Secara teori, iterator berikut ini akan mengembalikan semua bilangan ganjil.
class InfIter:
"""Infinite iterator yang mengembalikan semua bilangan ganjil"""
def __iter__(self):
self.num = 1
return self
def __next__(self):
num = self.num
self.num += 2
return num
Contoh penggunaannya adalah seperti berikut:
>>> a = iter(InfIter()) >>> next(a) 1 >>> next(a) 3 >>> next(a) 5 >>> next(a) 7
dan begitu selanjutnya…
Kita perlu hati – hati untuk memasukkan kondisi terminasi untuk menghentikan iterasi pada iterator tak berhingga ini. Hal ini mirip dengan loop menggunakan while
.
Keuntungan dari penggunaan iterator adalah bisa menghemat penggunaan memori. Seperti pada contoh di atas, kita bisa mendapatkan semua bilangan ganjil tanpa harus menyimpan semua bilangan di dalam memori. Secara teori, kita bisa menyimpan item tak berhingga pada memori yang terbatas.
Selain itu, iterator membuat kode terlihat lebih rapi dan bagus.
Ada cara lain yang lebih mudah untuk membuat iterator di Python, yaitu dengan generator menggunakan yield.
Python memiliki metode pemformatan (formatting) yang powerful. Ada dua cara atau style formatting di Python, yaitu dengan style lama dan dengan style baru. Style lama menggunakan tanda persen %
, sedangkan style baru menggunakan metode format()
. Di artikel ini, Anda akan menjumpai formatting string dan bilangan lengkap yang mencakup penggunaan format cara lama dan baru disertai dengan contoh – contohnya.
Regular expression (regex) adalah deretan karakter yang digunakan untuk pencarian string atau teks dengan menggunakan pola (pattern). Anda pasti familiar dengan cara penulisan email, misalnya duniaprogramming1@gmail.com
Pengertian Pemrograman Berorientasi Objek
Pemrograman berorientasi objek atau dalam bahasa inggris disebut Object Oriented Programming (OOP) adalah paradigma atau teknik pemrograman di mana semua hal dalam program dimodelkan seperti objek dalam dunia nyata. Objek di dunia nyata memiliki ciri atau attribut dan juga aksi atau kelakuan (behaviour).
Sebelum membaca artikel ini, seharusnya Anda sudah memahami terlebih dahulu tentang fungsi. Artikel ini membahas lanjutan dari dasar fungsi di Python. Fungsi lanjutan ini terdiri dari rungsi rekursi dan fungsi lambda (fungsi anonim).