akan belajar tentang anonymous function atau fungsi

tanpa nama yang biasa disebut dengan lambda.

A.26.1. Pengenalan Lambda

Lambda yaitu  fungsi yang tidak memiliki nama. Lambda umumnya disimpan

ke suatu variabel atau dieksekusi langsung. Lambda bisa memiliki parameter

dan mengembalikan nilai balik, seperti fungsi pada umumnya.

Perbedaan signifikan antara lambda dengan fungsi/closure yaitu  pada

lambda isinya hanya boleh 1 baris satement. Jika ada lebih dari 1 baris silakan

gunakan fungsi saja.

Untuk mempermudah pemahaman kita tentang lambda, silakan pelajari kode

berikut. Ada dua blok fungsi dibuat, satu berbentuk fungsi biasa dan satunya

lagi yaitu  lambda. Keduanya memiliki tugas sama persis yaitu menampilkan

pesan hello python .

Bisa dilihat bagaimana perbedaan penulisan syntax fungsi memakai  

def say_hello1():

print("hello python")

say_hello1()

# output ➜ hello python

say_hello2 = lambda : print("hello python")

say_hello2()

# output ➜ hello python

lambda dibandingkan dengan fungsi biasa. Lambda ditulis memakai  

keyword lambda , diikuti tanda titik 2 : lalu statement satu baris. Lambda

perlu ditampung ke sebuah variabel (misalnya say_hello2() ), setelahnya

variabel tersebut digunakan untuk mengeksekusi lambda dengan cara

memanggilnya seperti fungsi.

A.26.2. lambda return value

Lambda selalu mengembalikan nilai balik atau return value. Jika isi lambda

yaitu  suatu data atau operasi yang menghasilkan data, maka data tersebut

otomatis jadi nilai balik. Contoh:

Pada kode di atas lambda get_hello_message2() mengembalikan nilai balik

bertipe string.

Lalu bagaimana dengan lambda say_hello2() yang telah dipraktekan di

atas, apakah juga mengembalikan nilai balik? Iya, lambda tersebut juga ada

return value-nya. Namun, karena isi lambda say_hello2() yaitu 

pemanggilan fungsi print() maka nilai balik lambda yaitu  data None .

def get_hello_message1():

return "hello python"

res = get_hello_message1()

print(res)

# output ➜ hello python

get_hello_message2 = lambda : "hello python"

res = get_hello_message2()

print(res)

# output ➜ hello python

Pembahasan detail mengenai tipe data None ada di chapter None

A.26.3. Lambda argument/parameter

Sama seperti fungsi, lambda bisa memiliki parameter baik itu jenisnya

parameter positional, optional, ataupun keyword argument.

Sebagai contoh, lihat perbandingan fungsi get_full_name1() dengan lambda

get_full_name2() pada kode berikut. Parameter di lambda dituliskan

diantara keyword lambda dan tanda titik 2 : . Jika ada lebih dari 1

parameter, gunakan tanda koma , sebagai separator.

Untuk penerapan optional argument dan keyword argument, contohnya bisa

dilihat pada kode berikut:

def get_full_name1(first_name, last_name):

return f"{first_name} {last_name}"

get_full_name2 = lambda first_name, last_name : f"{first_name}

{last_name}"

res = get_full_name1("Darion", "Mograine")

print(res)

# output ➜ Darion Mograine

res = get_full_name2("Sally", "Whitemane")

print(res)

# output ➜ Sally Whitemane

get_full_name3 = lambda first_name, last_name = "" : f"{first_name}

{last_name}".strip()

A.26.4. Lambda dengan parameter *args

& **kwargs

Penerapan *args dan **kwargs pada parameter lambda tidak berbeda

dengan penerapannya di fungsi biasa. Sebagai perbandingan Silakan pelajari 2

contoh berikut yang masing-masing berisi contoh penulisan lambda vs versi

fungsi biasa.

• Contoh lambda dengan parameter *args:

• Contoh lambda dengan parameter **kwargs:

# %% A.26.4. Lambda *args dan **kwargs

def debug1(separator, *params):

res = []

for i in range(len(params)):

res.append(f"param {i}: {params[i]}")

return separator.join(res)

debug2 = lambda separator, *params : separator.join([f"param {i}:

{params[i]}" for i in range(len(params))])

res = debug1(", ", "Darion Mograine", ["Highlord", "Horseman of the

Ebon Blade", "Ashbringer"], True)

print(res)

# output ➜ param 0: Darion Mograine, param 1: ['Highlord', 'Horseman

of the Ebon Blade', 'Ashbringer'], param 2: True

res = debug2(", ", "Darion Mograine", ["Highlord", "Horseman of the

Ebon Blade", "Ashbringer"], True)

print(res)

# output ➜ param 0: Darion Mograine, param 1: ['Highlord', 'Horseman

of the Ebon Blade', 'Ashbringer'], param 2: True

A.26.5. Isi lambda: statement 1 baris

Lambda secara penulisan bisa dibilang lebih praktis dibanding fungsi, namun

limitasinya yang hanya bisa berisi statement 1 baris saja terkadang menjadi

masalah, terutama untuk mengakomodir operasi komplex yang umumnya

def debug3(separator, **params):

res = []

for key in params:

res.append(f"{key}: {params[key]}")

return separator.join(res)

debug4 = lambda separator, **params : separator.join([f"{key}:

{params[key]}" for key in params])

res = debug3(

", ",

name="Darion Mograine",

occupations=["Highlord", "Horseman of the Ebon Blade",

"Ashbringer"],

active=True

)

print(res)

# output ➜ name: Darion Mograine, occupations: ['Highlord', 'Horseman

of the Ebon Blade', 'Ashbringer'], active: True

res = debug4(

", ",

name="Darion Mograine",

occupations=["Highlord", "Horseman of the Ebon Blade",

"Ashbringer"],

active=True

)

print(res)

# output ➜ name: Darion Mograine, occupations: ['Highlord', 'Horseman

of the Ebon Blade', 'Ashbringer'], active: True

membutuhkan lebih dari 1 baris kode.

Namun Python dari segi bahasa yaitu  cukup flexibel, banyak API yang

memungkinkan kita selaku programmer untuk bisa menuliskan kode yang

cukup kompleks tapi dalam 1 baris saja. Pada contoh berikut, operasi

transpose matrix bisa dilakukan hanya dalam 1 baris dengan menerapkan list

comprehension.

Pembahasan detail mengenai list comprehension ada di chapter List

Comprehension

A.26.6. Lambda dengan parameter

def transpose_matrix1(m):

tm = []

for i in range(len(m[0])):

tr = []

for row in m:

tr.append(row[i])

tm.append(tr)

return tm

transpose_matrix2 = lambda m : [[row[i] for row in matrix] for i in

range(len(m[0]))]

matrix = [[1, 2], [3, 4], [5, 6]]

res = transpose_matrix1(matrix)

print(res)

# output ➜ [[1, 3, 5], [2, 4, 6]]

res = transpose_matrix2(matrix)

print(res)

# output ➜ [[1, 3, 5], [2, 4, 6]]

fungsi/lambda

Lambda, closure, fungsi, ketiganya bisa digunakan sebagai argument suatu

pemanggilan fungsi dengan cara implementasi juga sama, yaitu cukup tulis

saja lambda sebagai argument baik secara langsung maupun lewat variabel

terlebih dahulu.

Contoh penerapannya bisa dilihat pada kode berikut. Lambda aggregate()

dibuat dengan desain parameter ke-3 yaitu f bisa menampung nilai berupa

fungsi/closure/lambda.

Lambda aggregate() dipanggil 3x yang pada pemanggilan ke-2 dan

ke-3-nya, argument parameter ke-3 diisi dengan lambda.

aggregate = lambda message, numbers, f: print(f"{message} is

{f(numbers)}")

numbers = [24, 67, 22, 98, 3, 50]

def average1(numbers):

return sum(numbers) / len(numbers)

aggregate("average", numbers, average1)

# output ➜ average is 44.0

average2 = lambda numbers : sum(numbers) / len(numbers)

aggregate("average", numbers, average2)

# output ➜ average is 44.0

aggregate("average", numbers, lambda numbers : sum(numbers) /

len(numbers))

# output ➜ average is 44.0

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../lambda

â—‰ Chapter relevan lainnya

• Function

• Function ➜ Positional, Optional, Keyword Arguments

• Function ➜ Args & Kwargs

• Function ➜ Closure

â—‰ Referensi

• https://docs.python.org/3/reference/expressions.html#lambda

A.27. Python Modules

Pada chapter ini, kita akan menjelajahi konsep module beserta

implementasinya di Python.

A.27.1. Pengenalan Modules

Module di Python merupakan istilah untuk file yang berisi kode-kode python

(seperti deklarasi variabel, fungsi, class, dan lainnya). Kode-kode tersebut

diisolasi sesuai dengan tugasnya. Contoh:

• Module numbers berisi fungsi-fungsi untuk keperluan operasi angka

• Module random yang isinya kode untuk generate data random

Dengan adanya module kode menjadi lebih modular, rapi, dan mudah dikelola.

Pembuatan module di Python sangat mudah karena dilakukan dengan cukup

membuat file. Nama file yang digunakan yaitu  menjadi nama module.

Misalnya, file calculate.py , maka nama module yaitu  calculate .

Module dapat di-import di module lain, atau digunakan sebagai entry point

eksekusi program (sebutannya main module). Misalnya di praktek-praktek

pada chapter sebelumnya kita sering memakai   command python.exe

main.py untuk menjalankan program Python. Command tersebut menjadikan

module main (file main.py ) sebagai entrypoint eksekusi program.

Ok, sekarang mari kita coba praktekan penerapan module sebagai dependency

(module yang di-import di module lain).

Buat program baru dengan isi kode di bawah ini. File my_program.py kita

fungsikan sebagai entrypoint program, sedangkan module calculate sebagai

dependency yang di-import di my_program .

Project structure

Selanjutnya tulis isi kode file calculate :

File calculate.py

Module calculate berisi 1 buah variabel dan 3 buah fungsi:

• Variabel note berisi string

• Fungsi calc_hypotenuse() untuk menghitung nilai hipotenusa dari a

dan b

• Fungsi pow() untuk meperingkas operasi pangkat

• Fungsi sqrt() untuk mencari akar kuadrat

belajar-module/

│─── calculate.py

└─── my_program.py

note = "module calculate contains mathematic functions"

def calc_hypotenuse(a, b):

return sqrt(pow(a) + pow(b))

def pow(n, p = 2):

return n ** p

def sqrt(x):

n = 1

for _ in range(10):

n = (n + x/n) * 0.5

return n

Kesemua unit di atas di-import ke my_program untuk kemudian digunakan

dalam perhitungan pencarian nilai hipotenusa.

File my_program.py

Coba jalankan program memakai   command berikut agar module

my_program menjadi entrypoint eksekusi program.

Output:

a = 10

b = 15

import calculate

print(calculate.note)

res = calculate.calc_hypotenuse(a, b)

print("hypotenuse:", res)

res = calculate.sqrt(a**2 + b**2)

print("hypotenuse:", res)

res = calculate.sqrt(calculate.pow(a) + calculate.pow(b))

print("hypotenuse:", res)

python my_program.py

Implementasi module di Python cukup mudah bukan?

Keyword import digunakan untuk meng-import suatu module atau class.

Pada contoh di atas module calculate di-import ke my_program.py untuk

kemudian digunakan fungsi-fungsi didalamnya.

Pengaksesan variabel/konstanta dari suatu module memakai   notasi

<module>.<variable/constant> , contohnya calculate.note .

Sedangkan pengaksesan fungsi memakai   notasi

<module>.<function>() , contohnya seperti calculate.calc_hypotenuse() ,

calculate.sqrt() , dan calculate.pow() .

A.27.2. Behaviour import module

Ketika suatu module di-import, semua unit di dalamnya dapat diakses dari file

peng-import. Contohnya bisa dilihat pada kode yang sudah ditulis, variabel

note dan fungsi calc_hypotenuse() yang berada di module calculate ,

keduanya bisa langsung digunakan.

Jika dalam module ada statement yang sifatnya bukan deklarasi variabel atau

fungsi, misalnya seperti statement print, maka statement tersebut akan

langsung dieksekusi saat module ter-import.

Mari coba praktekan. Tambahkan statement berikut di file calculate.py :

File calculate.py

print("hello from calculate")

note = "module calculate contains mathematic functions"

Jalankan program, lihat hasilnya:

A.27.3. Naming convention module

Mengacu ke dokumentasi PEP 8 – Style Guide for Python Code, nama module

dianjurkan untuk ditulis dalam huruf kecil (lowercase) dengan underscode

sebagai pembatas antar kata.

A.27.4. Keyword from dan import

Ada dua bentuk penerapan keyword import . Pertama, yaitu untuk meng-

import module, contohya seperti pada praktek di atas ( import calculate ).

Kedua, yaitu  mengkombinasikan keyword tersebut dengan keyword from

untuk meng-import langsung fungsi atau item lainnya dari suatu module.

Contoh:

File my_program.py

a = 10

b = 15

from calculate import note

from calculate import calc_hypotenuse

from calculate import sqrt

Dua versi berbeda my_program.py di atas yaitu  ekuivalen, keduanya

melakukan operasi yang sama persis dan menghasilkan output yang sama

pula.

Pada contoh ke-2 (program yang baru saja ditulis), variabel note , fungsi

calc_hypotenuse() dan sqrt() di-import secara langsung via statement

from calculate import <function> .

Untuk penulisannya bisa dituliskan satu per satu statement import-nya, atau

bisa cukup sebaris saja (cara ini hanya berlaku untuk import item yang

bersumber dari module yang sama).

â—‰ Fungsi pow()

Fungsi pow() merupakan fungsi bawaan Python Standard Library yang bisa

langsung digunakan tanpa perlu meng-import apapun.

Cara penggunaan fungsi pow() yaitu  dengan langsung menulisnya dalam

skema pow(a, b) . Fungsi ini menghasilkan operasi matematika a pangkat

b .

Pada kode di atas, fungsi pow() milik module calculate sengaja tidak di-

import agar tidak meng-override atau menimpa fungsi pow() bawaan Python.

from calculate import note

from calculate import calc_hypotenuse

from calculate import sqrt

# vs

from calculate import note, calc_hypotenuse, sqrt

A.27.5. Statement from <module> import

*

Statement from <module> import * digunakan untuk meng-import semua

unit yang ada dalam module <module> . Contoh penerapannya:

File my_program.py

A.27.6. Keyword as

Module maupun fungsi bisa di-import dengan diberi nama alias. Biasanya

teknik ini digunakan pada situasi dimana module yang di-import namanya

cukup panjang, maka digunakan alias agar lebih pendek. Pembuatan alias

sendiri dilakukan via keyword as .

a = 10

b = 15

from calculate import *

print(note)

res = calc_hypotenuse(a, b)

print("hypotenuse:", res)

res = sqrt(a**2 + b**2)

print("hypotenuse:", res)

res = sqrt(pow(a, 2) + pow(b, 2))

print("hypotenuse:", res)

Penerapannya bisa dilihat pada contoh berikut:

File my_program.py

Penjelasan:

• Statement import calculate as calc meng-import module calculate

dengan alias calc . Nantinya fungsi-fungsi dalam module tersebut bisa

diakses via calc.<function>() .

• Statement from calculate import calc_hypotenuse as hptns, sqrt

meng-import:

â—¦ Fungsi calc_hypotenuse() dari module calculate dengan alias

hptns() .

â—¦ Fungsi sqrt() dari module calculate .

a = 10

b = 15

import calculate as calc

from calculate import calc_hypotenuse as hptns, sqrt

print(calc.note)

res = hptns(a, b)

print("hypotenuse:", res)

res = sqrt(a**2 + b**2)

print("hypotenuse:", res)

res = sqrt(calc.pow(a) + calc.pow(b))

print("hypotenuse:", res)

A.27.7. Urutan pencarian module

Ketika suatu module di-import, Python akan melakukan pencarian file module

di beberapa tempat berikut secara berurutan:

1. Pertama, Python akan mencari module di folder yang sama dimana

statement import digunakan.

2. Jika pencarian pertama tidak menemukan hasil, maka Python lanjut

mencari file module ke folder dimana environment variable PYTHONPATH

di-set.

3. Jika pencarian kedua juga tidak menemukan hasil, Python melanjutkan

pencarian di folder dimana Python di-install.

4. Jika pencarian ketiga juga tidak sukses (file module tidak ditemukan), maka

eksekusi program menghasilkan error.

A.27.8. File module dalam folder

Bagaimana jika suatu file module (misalnya calculate.py ) berada di dalam

suatu sub-folder dalam folder program, apakah cara import-nya sama?

Sebenarnya sama namun ada sedikit perbedaan yang harus diketahui.

Selengkapnya akan kita bahas pada chapter selanjutnya, yaitu Packages.

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../modules

â—‰ Chapter relevan lainnya

• Packages

• Special Names

â—‰ Referensi

• https://docs.python.org/3/tutorial/modules.html

A.28. Python Packages

Pada chapter ini, kita akan membahas cara Python mengelola module melalui

packages. Dengan package, module bisa diakses memakai   notasi

pengaksesan module, contohnya seperti calculate.calc_hypotenuse() .

A.28.1. Pengenalan Packages

Mari kita mulai dengan sedikit mengulang pembahasan yang ada di chapter

sebelumnya. Di Python, module direpresentasikan oleh file, dan agar bisa

mengakses item yang ada dalam module tersebut kita perlu meng-import-nya

terlebih dahulu.

Package yaitu  cara mengelola module dengan menempatkannya dalam

suatu folder. Sederhananya: module yaitu  file, dan package yaitu 

folder.

Untuk mendemonstrasikan konsep ini, mari kita praktekan. Buat project baru

dengan struktur seperti berikut:

Project structure

Program yang dibuat masih sama seperti yang ada di praktek sebelumnya.

belajar-package/

│─── libs/

| │─── calculate.py

| └─── common/

| │─── message.py

| └─── number.py

└─── my_program.py

Perbedaannya, kali ini fungsi sqrt() dan pow() ditempatkan dalam path

libs/common/number.py , dan ada juga satu fungsi baru dibuat di libs/

common/message.py .

File: libs/common/number.py

File: libs/common/message.py

Selanjutnya, isi file calculate.py dengan deklarasi variabel note dan fungsi

calc_hypotenuse() .

File: libs/calculate.py

note = "module libs.common.number contains numerical functions"

def pow(n, p = 2):

return n ** p

def sqrt(x):

n = 1

for _ in range(10):

n = (n + x/n) * 0.5

return n

note = "module libs.common.message contains messaging/printing functions"

def print_hypotenuse(v):

print("hypotenuse:", v)

import libs.common.number

note = "module libs.calculate contains mathematic functions"

Terakhir, di file my_program.py (file entrypoint eksekusi program), import

module libs/common/number.py , libs/common/message.py , dan libs/

calculate.py lalu panggil fungsi yang ada di masing-masing module. Contoh:

File: my_program.py

Bisa dilihat bagaimana peran package dalam operasi import module dan

pengaksesan unit dalam module.

• Module yang berada dalam package di import memakai   notasi

<package>.<module> . Contoh:

â—¦ import libs.calculate di file my_program.py

• Jika ada package di dalam package, maka ditulis semua subfoldernya,

a = 10

b = 15

import libs.calculate

import libs.common.number

import libs.common.message

print(libs.calculate.note)

print(libs.common.number.note)

print(libs.common.message.note)

res = libs.calculate.calc_hypotenuse(a, b)

libs.common.message.print_hypotenuse(res)

res = libs.common.number.sqrt(a**2 + b**2)

libs.common.message.print_hypotenuse(res)

res = libs.common.number.sqrt(libs.common.number.pow(a) +

libs.common.number.pow(b))

libs.common.message.print_hypotenuse(res)

seperti: <package>.<package>.<module> . Contoh:

â—¦ import libs.common.number di file libs/calculate.py

â—¦ import libs.common.number di file my_program.py

â—¦ import libs.common.message di file my_program.py

• Pengaksesan unit dalam module diwajibkan dengan ditulis namespace nya

secara utuh, jadi nama package juga ditulis. Contohnya bisa dilihat pada

beberapa statement seperti:

â—¦ libs.common.number.sqrt() di file libs/calculate.py

â—¦ libs.common.number.pow() di file libs/calculate.py

â—¦ libs.calculate.calc_hypotenuse() di file my_program.py

â—¦ libs.common.message.print_hypotenuse() di file my_program.py

Ok, selanjutnya coba jalankan program dan lihat hasilnya:

A.28.2. Naming convention package

Berdasarkan dokumentasi PEP 8 – Style Guide for Python Code, disarankan

untuk menulis nama package dengan huruf kecil (lowercase) dan dianjurkan

untuk menghindari penggunaan underscore.

A.28.3. Metode import module package

Seperti halnya module biasa, module dalam package bisa di-import dengan

beberapa cara:

â—‰ Alias module via keyword as

Alias cukup berguna untuk mempersingkat penulisan module saat memanggil

item didalamnya. Keyword as digunakan untuk pemberian nama alias

module.

File: libs/calculate.py

File: my_program.py

import libs.common.number as num

note = "module libs.calculate contains mathematic functions"

def calc_hypotenuse(a, b):

return num.sqrt(num.pow(a) + num.pow(b))

a = 10

b = 15

import libs.calculate as calc

import libs.common.number as num

import libs.common.message as msg

print(calc.note)

print(num.note)

print(msg.note)

Dengan memakai   alias, namespace tidak perlu lagi dituliskan secara

penuh, contohnya libs.common.number.note cukup ditulis dengan

num.note .

â—‰ Import package via from & import

Kombinasi keyword from dan import dapat digunakan dengan ketentuan:

setelah keyword from yang ditulis yaitu  namespace package, lalu diikuti

oleh keyword import dan nama module. Contoh:

File: libs/calculate.py

File: my_program.py

import libs.common.number

print(libs.common.number.note)

# vs

import libs.common.number as num

print(num.note)

from libs.common import number

note = "module libs.calculate contains mathematic functions"

def calc_hypotenuse(a, b):

return number.sqrt(number.pow(a) + number.pow(b))

a = 10

b = 15

â—‰ Penggunaan import *

Ada beberapa hal yang perlu diketahui dalam penggunaan import * , namun

sebelum membahasnya, silakan coba terlebih dahulu kode berikut. Silakan

buka my_program.py lalu ubah statement import menjadi seperti ini:

Hasilnya yaitu  error:

from libs import calculate as calc

from libs.common import *

A.28.4. File __init__.py

Melanjutkan pembahasan sebelumnya dimana import * menghasilkan error,

hal tersebut terjadi karena Python tidak bisa mendeteksi module apa saja yang

bisa direpresentasikan dengan * saat meng-import suatu package.

Untuk mengatasi error, tambahkan file bernama ___init___.py di setiap

package/folder. Dengan ini maka struktur file program menjadi seperti ini:

Project structure

Isi file __init__.py dengan sebuah statement deklarasi variabel bernama

__all__ , dengan nilai yaitu  list nama module yang ada di dalam folder

tersebut.

File: libs/common/__init__.py

File: libs/__init__.py

belajar-package/

│─── libs/

| │─── __init__.py

| │─── calculate.py

| └─── common/

| │─── __init__.py

| │─── message.py

| └─── number.py

└─── my_program.py

__all__ = ["message", "number"]

Setelah penambahan di atas dilakukan, maka module yang berada dalam

package bisa di-import memakai   import * .

Coba sekarang test dengan mengaplikasikannya di program:

File: my_program.py

â—‰ Best practice file __init__.py

Sesuai penjelasan di dokumentasi Package, dianjurkan untuk selalu membuat

file __init__.py di setiap package/folder untuk menghindari masalah saat

pencarian module.

__all__ = ["calculate"]

a = 10

b = 15

from libs import *

from libs.common import *

print(calculate.note)

print(number.note)

print(message.note)

res = calculate.calc_hypotenuse(a, b)

message.print_hypotenuse(res)

res = number.sqrt(a**2 + b**2)

message.print_hypotenuse(res)

res = number.sqrt(number.pow(a) + number.pow(b))

message.print_hypotenuse(res)

Meskipun module dalam package tidak digunakan via statement import * ,

dianjurkan untuk tetap membuat file tersebut. Isinya biarkan kosong saja tidak

apa-apa.

â—‰ Special name __all__

Variabel yang diawali dan diakhir dengan karakter double underscore seperti

__all__ disebut sebagai variabel special name. Pembahasan lebih lanjut

tentang special names ada di chapter Special Names.

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../packages

â—‰ Chapter relevan lainnya

• Modules

• Special names

â—‰ Referensi

• https://docs.python.org/3/tutorial/modules.html#packages

A.29. Python Variables

Scope (Local vs. Global)

Pada chapter ini kita akan membahas tentang variable scope, yaitu kapan

suatu variabel valid dan bisa digunakan di dalam block serta beberapa fungsi

yang masih relevan dengan topik variabel scope.

A.29.1. Local vs. global variable

Global variable yaitu  variabel yang dideklarasikan di root (tidak di dalam

suatu block fungsi). Sedangkan local variable yaitu  yang dideklarasikan di

dalam suatu block dan hanya valid di block tersebut saja.

Contoh, sebuah file program Python bernama main.py di isi dengan kode

berikut:

File main.py

name = "Cleaver Bmurglbrm"

print("greetings", name)

def greet():

today = "Saturday"

print("happy", today, name)

if name:

greet()

greet_message = "have a good day"

print("hello", name, greet_message)

# output ↓

Variabel name disitu merupakan variabel global. Variabel jenis ini bisa diakses

dari block manapun. Di contoh, variabel name diakses di dalam block fungsi

greet() dan di block seleksi kondisi if name: .

Berbeda dengan variabel today yang tempat deklarasinya ada di block fungsi

greet() , membuatnya hanya valid untuk digunakan di block itu saja. Variabel

today dikategorikan sebagai variabel local dengan scope yaitu  block fungsi

greet() .

Selain itu ada juga variabel lain bernama greet_message yang dideklarasikan

di block seleksi kondisi if name: .

Sekarang coba akses variabel today dari luar block, hasilnya pasti error.

Keterangan errornya: variabel today tidak dikenali.

Bagaimana jika variabel greet_message diakses dari luar block seleksi

kondisi, apakah juga error? Jawabannya, tidak!

Di editor terlihat variabel greet_message digaris-bawahi merah, menandakan

ada error namun hanya di level linter saja. Error tersebut tidak membuat

eksekusi program menjadi gagal.

Sampai sini bisa ditarik kesimpulan bahwa variabel global bisa diakses dari

mana saja, sedangkan variabel local bisa diakses di dalam block dimana ia

dideklarasikan. Pengaksesan variabel local diluar block-nya memiliki efek

samping berikut:

• Jika variabel local dideklarasikan di dalam block fungsi/lambda/closure,

maka pengaksesannya dari luar block menghasilkan error.

• Jika variabel local dideklarasikan di block seleksi kondisi atau lainnya, maka

pengaksesaannya dari luar block diperbolehkan dan tidak membuat

eksekusi program menjadi error. Namun warning atau error di level linter

muncul.

A.29.2. Local dan global variable dengan

nama sama

Katakanlah ada variabel global dan variabel local yang namanya sama persis,

di situasi seperti ini maka nilai variabel local pada block-nya yaitu  sesuai

dengan saat deklarasinya dalam block. Di luar block, variabel tersebut nilainya

kembali berisi nilai variabel global.

Agar lebih jelas coba praktekan kode berikut:

Bisa dilihat dari output bahwa variabel name nilainya yaitu  Keymaster

Urmgrgl , sesuai dengan isi variabel saat deklarasi di block fungsi greet() .

Namun di luar block fungsi, nilainya kembali menjadi Cleaver Bmurglbrm .

Dari sini bisa diambil kesimpulan bahwa di luar block, perubahan nilai variabel

local tidak berefek ke variabel global, meskipun namanya sama persis.

name = "Cleaver Bmurglbrm"

def greet():

name = "Keymaster Urmgrgl"

print("hello", name)

greet()

print("greetings", name)

# output ↓

#

# hello Keymaster Urmgrgl

# greetings Cleaver Bmurglbrm

A.29.3. Keyword global

Untuk mengubah nilai suatu variabel global dari block, maka perlu adanya

penggunaan keyword global . Keyword ini menandai variabel dalam block

bahwa reference yang digunakan yaitu  variabel global. Efeknya, perubahan

nilai pada variabel juga berpengaruh ke variabel global.

Contoh penerapan:

Cara penggunaan keyword global yaitu  dengan cukup menuliskannya di

dalam block kemudian diikuti nama variabel. Dari output terlihat bahwa di luar

block fungsi greet() nilai variabel name berubah.

A.29.4. Fungsi globals()

Fungsi globals() mengembalikan informasi semua variabel global yang bisa

name = "Cleaver Bmurglbrm"

def greet():

global name

name = "Keymaster Urmgrgl"

print("hello", name)

greet()

print("greetings", name)

# output ↓

#

# hello Keymaster Urmgrgl

# greetings Keymaster Urmgrgl

diakses dari tempat dimana fungsi dipanggil. Nilai balik berbentuk dictionary

dengan key yaitu  nama variabel dan value yaitu  nilai variabel.

Contoh penerapannya bisa dilihat pada kode berikut. Ada variabel bernama

my_var yang nilainya diakses via nilai balik pemanggilan fungsi globals()

A.29.5. Fungsi locals()

Fungsi locals() mengembalikan informasi variabel yang dideklarasikan di

block dimana fungsi tersebut dipanggil dengan nilai balik berbentuk dictionary.

Pada contoh berikut, variabel my_var dideklarasikan di luar block fungsi

task_two() , sedangkan another_var didalamnya.

Di dalam task_two() , variabel another_var bisa diakses via nilai balik

fungsi locals() karena masih satu block. Tidak seperti my_var ,

pengaksesannya via nilai balik fungsi locals() akan menghasilkan error

karena variabel tersebut tidak dikenali.

my_var = 12

def task_one():

all_global_vars = globals()

print(all_global_vars['my_var'])

task_one()

# output ➜ 12

my_var = 12

def task_two():

another_var = "Hello Python"

Di contoh, ditambahkan block try except untuk menangkap error yang

muncul saat statement all_locals_vars['my_var'] dieksekusi.

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../local-

global-var

â—‰ TBA

• Variabel global pada module

â—‰ Referensi

• https://docs.python.org/3/faq/programming.html

• https://docs.python.org/3/library/functions.html#locals

• https://docs.python.org/3/library/functions.html#globals

A.30. Python Special

Names

Chapter ini membahas tentang variabel spesial yang ada di Python (umumnya

disebut special names).

Python memiliki variabel spesial yang bisa diakses secara global. Ciri khas

special names yaitu  penulisannya diawali dan diakhiri dengan karakter __ .

Salah satunya yaitu  variabel __all__ yang telah diulas di chapter

sebelumnya.

Setiap special names memiliki kegunaan yang unik dan berbeda satu sama

lain.

A.30.1. Variabel __name__

Variabel __name__ yaitu  salah satu special names di Python. Isinya

mencakup informasi nama modul atau string __main__ , tergantung apakah

variabel tersebut di-print dari file entrypoint eksekusi program atau di-import.

File entrypoint yang dimaksud disini yaitu  file yang digunakan pada

argument command python <nama_file_program> .

Agar lebih jelas, mari kita langsung praktekan. Silakan siapkan folder project

baru dengan struktur file seperti ini:

Project structure example-1

example-1/

Folder project example-1 ini berisi hanya 2 file, yaitu calculate.py dan

my_program.py .

Selanjutnya, buka calculate.py dan tulis kode untuk mencari bilangan

prima:

File: calculate.py

File calculate.py difungsikan sebagai module bernama calculate , yang

nantinya di-import pada file my_program.py . Statement print("from

calculate.py:", __name__) akan otomatis dieksekusi saat ter-import. Selain

itu, ada juga fungsi is_prime() yang berisi kode pencarian bilangan prima.

Penjelasan detail mengenai module ada di chapter Modules

print("from calculate.py:", __name__)

def is_prime(num):

print("from calculate.py is_prime(num):", __name__)

flag = False

if num == 1:

print(num, "is not a prime number")

elif num > 1:

for i in range(2, num):

if (num % i) == 0:

flag = True

break

if flag:

print(num, "is not a prime number")

else:

print(num, "is a prime number")

Lanjut, buka file my_program.py dan isi dengan kode berikut:

File: my_program.py

File my_program.py nantinya kita gunakan sebagai entrypoint eksekusi

program via perintah python.exe my_program.py . Isi file tersebut yaitu  5

buah statement yang masing-masing penjelasannya bisa dilihat di bawah ini:

1. Statement print("from my_program.py:", __name__) dieksekusi

2. Module calculate di-import

3. Module random di-import

4. Fungsi randint() dalam module random dieksekusi

5. Fungsi is_prime() milik module calculate dieksekusi

Jalankan program memakai   command python my_program.py , lalu lihat

outputnya:

Dari contoh, dapat dilihat bahwa special names __name__ jika di-print dari

print("from my_program.py:", __name__)

import calculate

import random

num = random.randint(0, 999)

calculate.is_prime(num)

my_program.py memiliki value string "__main__" . Hal ini karena file

my_program.py yaitu  entrypoint program. Sedangkan pada module

calculate , variabel yang sama menghasilkan output berbeda, yaitu

calculate yang merupakan nama module file calculate.py .

Untuk mengetahui file mana yang merupakan file entrypoint eksekusi

program, selain dengan mengecek nilai variabel __name__ bisa juga

dengan melihat argument eksekusi program. Misalnya python

my_program.py , maka file entrypoint yaitu  my_program.py

Variabel __name__ biasanya dimanfaatkan sebagai kontrol entrypoint

program, misalnya untuk membedakan statement yang akan dieksekusi ketika

module digunakan sebagai entrypoint atau digunakan sebagai dependency

atau module yang di-import di module lain.

Contoh pengaplikasian skenario yang disebutkan dapat ditemukan pada

contoh program ke-2 berikut:

Project structure example-2

File: calculate.py

example-2/

│─── calculate.py

└─── main.py

def is_prime(num):

flag = False

if num == 1:

print(num, "is not a prime number")

File: main.py

Penjelasan:

• Module calculate jika di-run sebagai entrypoint, maka statement dalam

blok seleksi kondisi if __name__ == '__main__' otomatis tereksekusi.

Jika tidak digunakan sebagai entrypoint, maka tidak ada statement yang

dieksekusi.

• Module main jika di-run sebagai entrypoint, maka module tersebut akan

meng-import module calculate lalu memanggil fungsi is_prime() yang

dideklarasikan didalamnya.

A.30.2. Variabel __file__

Variabel special name __file__ berisi informasi path file di mana variabel

tersebut ditulis atau digunakan. Ada dua cara untuk memakai   variabel ini:

• Dengan mengaksesnya secara langsung

import calculate

import random

num = random.randint(0, 999)

calculate.is_prime(num)

• Dengan mempergunakannya sebagai property dari module, misalnya:

random.__file__

Contoh penerapannya bisa dilihat pada program berikut:

Project structure example-3

File: calculate.py

File: main.py

example-3/

│─── calculate.py

└─── main.py

def is_prime(num):

flag = False

if num == 1:

print(num, "is not a prime number")

elif num > 1:

for i in range(2, num):

if (num % i) == 0:

flag = True

break

if flag:

print(num, "is not a prime number")

else:

print(num, "is a prime number")

print("module main", __file__)

import calculate

Bisa dilihat pada gambar berikut bahwa output program yaitu  memunculkan

nama module beserta lokasi di mana file module tersebut berada:

Penggunaan __file__ akan menampilkan path file dimana variabel tersebut

ditulis, sedangkan penggunaannya sebagai property module (misalnya

calculate.__file__ ) menghasilkan informasi path module.

A.30.3. Variabel __all__ & file

__init__.py

Variabel __all__ digunakan untuk menentukan module apa saja yang ter-

import ketika statement import * digunakan. Variabel __all__ wajib ditulis

di file __init__.py yang ditempatkan dalam package.

Penjelasan detail mengenai import * ada pada chapter Packages.

A.30.4. Attribute __name__ milik class

type

Kita telah memakai   fungsi type() beberapa kali pada banyak chapter

sebelum ini. Fungsi type() yaitu  fungsi yang mengembalikan data dengan

tipe yaitu class type .

Class type memiliki attribute bernama __name__ isinya informasi nama

class. Contoh penerapan pengaksesan attribute ini:

A.30.5. Attribute __class__ milik semua

class / tipe data

Setiap tipe data memiliki akses ke attribute bernama __class__ . Isi dari

attribute ini yaitu  data yang sama hasil pemanggilan fungsi type() yaitu

informasi tipe data atau class.

Pada kode sebelumnya, statement type(data1) menghasilkan nilai balik yang

sama dengan statement data1.__class__ . Dari nilai balik (yang bertipe

type ) tersebut bisa langsung dilakukan pengaksesan attribute __name__ .

A.30.6. Attribute __mro__ milik semua

data1 = "Noval Agung"

print(f"var: data1, data: {data1}, type: {type(data1).__name__}")

# output ➜ var: data1, data: Noval Agung, type: str

data2 = 24 * 7

print(f"var: data2, data: {data2}, type: {type(data2).__name__}")

# output ➜ var: data2, data: 168, type: int

data1 = "Noval Agung"

print(f"var: data1, data: {data1}, type: {data1.__class__.__name__}")

# output ➜ var: data1, data: Noval Agung, type: str

data2 = 24 * 7

print(f"var: data2, data: {data2}, type: {data2.__class__.__name__}")

# output ➜ var: data2, data: 168, type: int

class / tipe data

Class attribute __mro__ berisi informasi hirarki class dalam tipe data tuple.

Penjelasan lebih lanjut mengenai __mro__ ada di chapter OOP ➜ Class

Inheritance.

A.30.7. Package __future__

Package __future__ berisi modules yang hanya tersedia di Python versi

terbaru. Package ini biasa di-import pada program yang dijalankan

memakai   Python versi lama (misalnya 2.5), yang didalamnya ada

penerapan kode yang hanya ada di versi Python terbaru.

Salah satu contoh yaitu  penggunaan operator // untuk operasi floor

division atau pembagian dengan hasil dibulatkan. Operator tersebut hanya

tersedia di Python 3.0+.

Agar bisa memakai   operator tersebut di Python versi lama harus ada,

perlu untuk meng-import module division dari package __future__ . Tulis

statement import di file program baris paling atas sendiri.

from __future__ import division

print(8 / 7)

# output ➜ 1.1428571428571428

print(8 // 7)

# output ➜ 1

A.30.8. Fungsi __init__()

Fungsi __init__() digunakan untuk membuat konstruktor pada suatu class.

Penjelasan lebih lanjut mengenai __init__() ada di chapter OOP ➜ Class &

Object.

A.30.9. Attribute __doc__ milik semua

class dan fungsi

Attribute __doc__ digunakan untuk melihat informasi komentar docstring.

Penjelasan lebih lanjut mengenai __doc__ ada di chapter DocString.

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../special-

names

â—‰ Chapter relevan lainnya

• Modules

• Packages

• OOP ➜ Class & Object

• OOP ➜ Class Inheritance

â—‰ Referensi

• https://docs.python.org/3/tutorial/modules.html

• https://docs.python.org/3/tutorial/special-names.html

• https://stackoverflow.com/questions/7075082/what-is-future-in-python-

used-for-and-how-when-to-use-it-and-how-it-works

A.31. Python None

Pada chapter ini kita akan belajar tentang object special bernama None .

A.31.1. Pengenalan None

None merupakan object bawaan Python yang umumnya digunakan untuk

merepresentasikan nilai kosong atau null.

Ketika suatu variabel berisi data yang nilainya bisa kosong, umumnya sebelum

variabel tersebut digunakan, dilakukan pengecekan terlebih dahulu

memakai   seleksi kondisi untuk memastikan apakah nilainya benar-benar

kosong atau tidak.

Sebagai contoh, pada kode berikut, dipersiapkan sebuah fungsi bernama

inspect_data() , tugasnya mengecek apakah variabel memiliki nilai atau

tidak.

def inspect_data(data):

if data is None:

print("data is empty. like very empty")

else:

print(f"data: {data}, type: {type(data).__name__}")

data = 0

inspect_data(data)

# output ➜ data: 0, type: int

data = ""

inspect_data(data)

# output ➜ data: , type: str

Bisa dilihat pada program di atas output tiap statement yaitu  berbeda-beda

sesuai tipe datanya.

• Ketika variabel data berisi 0 maka variabel tersebut tidak benar-benar

kosong, melainkan berisi angka 0 .

• Karakteristik yang sama juga berlaku ketika variabel berisi string kosong

"" , meskipun ketika di-print tidak muncul apa-apa, variabel tersebut

sebenarnya berisi tipe data string namun tanpa isi (string dengan panjang

nol). Maka variabel tersebut sebenarnya tidak benar-benar kosong.

• Barulah ketika variabel isinya data None maka dianggap benar-benar

kosong.

Kode di atas berisi penerapan salah satu special name, yaitu attribute

__name__ milik class type .

Pembahasan detail mengenai special name ada di chapter Special

Names ➜ Attribute name milik class type

A.31.2. Penggunaan operator is

terhadap None

Ketika memeriksa apakah sebuah objek bernilai None atau tidak, disarankan

untuk memakai   operator is dibanding == , karena sifat dari operator

== memanggil special method __eq__() dari objek yang diperiksa dan pada

praktiknya tidak semua class memakai   implementasi default method

__eq__() . Dari sini maka potensi penggunaan operator == menghasilkan

nilai yg berbeda dibanding yang diharapkan yaitu  ada (meskipun sangat

kecil).

Serta, operator is lebih cepat dibanding == untuk pengecekan data None .

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../none

â—‰ Chapter relevan lainnya

• Tipe Data

• Special Names

â—‰ Referensi

• https://docs.python.org/3/c-api/none.html

• https://stackoverflow.com/questions/3257919/what-is-the-difference-

between-is-none-and-none

• https://stackoverflow.com/questions/26595/is-there-any-difference-

between-foo-is-none-and-foo-none/26611#26611

A.32. Python Pack Unpack

tuple, list, set, dict

Python mengenal teknik packing dan unpacking, dimana teknik ini umum

diterapkan sesuai kebutuhan pada beberapa jenis tipe data kolektif seperti

tuple, list, set, dan dictionary. Pada chapter ini kita akan mempelajari cara

penggunaannya, beserta peran penggunaan tanda * dan ** pada operasi

packing dan unpacking.

A.32.1. Unpacking element tuple, list, set

Unpacking (yang dalam Bahasa Indonesia berarti bongkar muatan) yaitu 

teknik pendistribusian elemen tipe data kolektif ke banyak variabel.

Distribusinya sendiri bisa 1 on 1 yang berarti setiap elemen ditampung 1

variabel, atau hanya beberapa elemen saja yang didistribusikan ke variabel

baru, sisanya tetap ditampung dalam bentuk data kolektif.

â—‰ Unpack 1 element = 1 variable

Pada program berikut ada sebuah tuple bernama names yang setiap element-

nya perlu untuk didistribusikan ke variabel independen. Karena ada 6 buah

elemen dalam tuple tersebut, maka perlu disiapkan 6 buah variabel untuk

menampung data masing-masing element.

names = (

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

Jika jumlah variabel penampung tidak sama dengan jumlah element data

kolektif, misalnya jumlah variabel lebih sedikit, maka error pasti muncul saat

eksekusi program.

â—‰ Unpack hanya N elements pertama

Ada alternatif cara lain untuk kasus lainnya dimana element yang perlu

ditampung ke variabel baru hanya beberapa element pertama saja. Misalnya,

dari 6 element tuple, hanya 3 yang perlu disimpan ke variabel baru. Hal seperti

ini bisa dilakukan dengan konsekuensi: sisa element lainnya ditampung dalam

bentuk kolektif di satu variabel lain.

Contoh penerapannya bisa dilihat di kode berikut. Tuple yang sama, 3 element

pertamanya saja yang ditampung ke variabel baru. Untuk element sisanya,

tetap harus ditampung juga tapi cukup di 1 variabel saja, tersimpan dalam

tiple data list .

Variabel penampung sisa element selalu dalam bentuk list meskipun

sumber datanya bertipe data lain.

Bisa dilihat dari output, bahwa 3 element pertama berhasil ditampung di 3

variabel baru. Sisanya tetap disimpan ke variabel lain yang pada contoh di

atas yaitu  variabel warriors .

Penulisan variabel penampung sisa element diawali dengan karakter * dan

pasti tipe datanya yaitu  list.

Penulisan karakter * di awal variabel ini wajib. Jika tidak ditulis, maka

Python menganggap ada 4 buah variabel mencoba menampung element

tuple.

names = (

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

'Zeke Yeager',

'Reiner Braun',

'Annie Leonhart'

)

soldier1, soldier2, deceiver1, *warriors = names

print(soldier1) # output ➜ Mikasa Ackerman

print(soldier2) # output ➜ Armin Arlert

print(deceiver1) # output ➜ Eren Yeager

print(warriors) # output ➜ ['Zeke Yeager', 'Reiner Braun', 'Annie

Leonhart']

Jika diterapkan pada kasus di atas, statement tersebut pasti

menghasilkan error, karena data names berisi 6 element.

Katakanlah data element yang dibutuhkan hanya 3 pertama, sisanya bisa

dibuang, maka bisa gunakan variabel _ sebagai tempat pembuangan

element yang tidak terpakai.

â—‰ Unpack hanya N elements terakhir

teknik ini mirip seperti sebelumnya, perbedaannya: variabel penampung

element berada di sebelah kanan dan sisa element ditampung di variabel

paling kiri.

Jadi variabel bertanda * harus ditulis di paling kiri.

Pada contoh berikut, element yang sama disimpan namun dalam bentuk tipe

data berbeda, yaitu set.

soldier1, soldier2, deceiver1, *_ = names

print(soldier1) # output ➜ Mikasa Ackerman

print(soldier2) # output ➜ Armin Arlert

print(deceiver1) # output ➜ Eren Yeager

names = {

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

'Zeke Yeager',

'Reiner Braun',

'Annie Leonhart'

}

Variabel penampung sisa element (yaitu soldiers ) tipe datanya list .

â—‰ Unpack hanya N elements pertama dan terakhir

Bagaimana jika elements yang di-unpack yaitu  yang posisinya ada di

samping? Bisa juga, caranya dengan menampung sisanya di tengah.

Pada contoh berikut, ada sebuah list yang 2 element pertamanya ditampung

ke variabel independen, 2 terakhir juga ditampung ke variabel independen,

dan sisanya (yang posisinya di tengah) ditampung ke variabel lain.

Tanda * dituliskan pada variabel yang ditengah dengan penulisan bebas di

posisi mana saja, asalkan tidak di awal dan tidak di akhir. Python secara cerdas

tahu element mana yang dianggap sisa dengan melihat statementnya.

names = [

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

'Zeke Yeager',

'Reiner Braun',

'Annie Leonhart'

]

soldier1, soldier2, *deceivers, warrior1, warrior2 = names

print(soldier1) # output ➜ Mikasa Ackerman

print(soldier2) # output ➜ Armin Arlert

print(deceivers) # output ➜ ['Eren Yeager', 'Zeke Yeager']

print(warrior1) # output ➜ Reiner Braun

print(warrior2) # output ➜ Annie Leonhart

A.32.2. Packing element tuple, list, set

Packing element yaitu  operasi pemuatan banyak data ke sebuah data

kolektif. Cara penerapannya sangat mudah, cukup tulis saja variabel yang ingin

di-pack sebagai element data kolektif. Untuk tipenya bisa berupa tuple, list,

maupun set.

soldier1 = 'Mikasa Ackerman'

soldier2 = 'Armin Arlert'

soldier3 = 'Eren Yeager'

warrior1 = 'Zeke Yeager'

warrior2 = 'Reiner Braun'

warrior3 = 'Annie Leonhart'

tuple1 = (soldier1, soldier2, soldier3, warrior1, warrior2, warrior3)

print(tuple1)

# output ↓

#

# ('Mikasa Ackerman',

#  'Armin Arlert',

#  'Eren Yeager',

#  'Zeke Yeager',

#  'Reiner Braun',

#  'Annie Leonhart')

list1 = [soldier1, soldier2, soldier3, warrior1, warrior2, warrior3]

print(list1)

# output ↓

#

# ['Mikasa Ackerman',

#  'Armin Arlert',

#  'Eren Yeager',

#  'Zeke Yeager',

#  'Reiner Braun',

#  'Annie Leonhart']

Perlu diingat, bahwa tipe data set tidak menjamin elemennya tersimpan

secara urut. Jadinya sewaktu diakses atau di-print bisa saja urutan

elemen berubah.

Pembahasan detail mengenai set ada di chapter Set

â—‰ Prepend element

Operasi prepend bisa dilakukan dengan mudah memakai   syntax

(newElement, *oldData) . Contohnya pada kode berikut, tuple names

ditambahi element baru dengan posisi di awal.

Operasi ('Jean Kirstein', *names) menghasilkan data tuple karena disitu

names = [

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

'Zeke Yeager',

'Reiner Braun',

'Annie Leonhart'

]

names = ('Jean Kirstein', *names)

print(names)

# output ↓

#

# ('Jean Kirstein',

#  'Mikasa Ackerman',

#  'Armin Arlert',

#  'Eren Yeager',

#  'Zeke Yeager',

#  'Reiner Braun',

#  'Annie Leonhart')

literal tuple digunakan ( ( ) ). Selain tuple, operasi ini bisa didesain untuk

ditampung ke tipe data kolektif lainnya, misalnya list dan set .

â—‰ Append element

Append yaitu  operasi penambahan element baru di posisi akhir data.

Penulisan syntax-nya mirip seperti prepend element namun dituliskan terbalik,

seperti ini (*oldData, newElement) .

names = ('Jean Kirstein', *names)

print(f"type: {type(names).__name__}")

# output ➜ type: tuple

names2 = ['Jean Kirstein', *names]

print(f"type: {type(names2).__name__}")

# output ➜ type: list

names3 = {'Jean Kirstein', *names}

print(f"type: {type(names3).__name__}")

# output ➜ type: set

names = [

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

'Zeke Yeager',

'Reiner Braun',

'Annie Leonhart'

]

names = ('Jean Kirstein', *names)

print(names)

# output ↓

#

# ('Jean Kirstein',

â—‰ Append dan prepend element bersamaan

Operasi append dan prepend bisa dilakukan secara bersamaan.

names = [

'Mikasa Ackerman',

'Armin Arlert',

'Eren Yeager',

'Zeke Yeager',

'Reiner Braun',

'Annie Leonhart'

]

names = ('Jean Kirstein', *names)

print(names)

# output ↓

#

# ('Jean Kirstein',

#  'Mikasa Ackerman',

#  'Armin Arlert',

#  'Eren Yeager',

#  'Zeke Yeager',

#  'Reiner Braun',

#  'Annie Leonhart')

names = [*names, 'Connie Springer']

print(names)

# output ↓

#

# ['Jean Kirstein',

#  'Mikasa Ackerman',

#  'Armin Arlert',

#  'Eren Yeager',

#  'Zeke Yeager',

#  'Reiner Braun',

#  'Annie Leonhart',

#  'Connie Springer']

Perlu diingat, bahwa tipe data set tidak menjamin elemennya tersimpan

secara urut. Jadinya sewaktu diakses atau di-print bisa saja urutan

elemen berubah.

Pembahasan detail mengenai set ada di chapter Set

A.32.3. Pemanfaatan teknik unpacking

pada argument parameter

Tenik unpacking umum dimanfaatkan pada penyisipan data argument

parameter pemanggilan fungsi/method. Contoh aplikasinya bisa dilihat pada

kode berikut, dimana ada fungsi bernama show_biography() yang akan

dipanggil beberapa kali dengan cara pemanggilan berbeda satu sama lain.

• Pemanggilan ke-1: Argument parameter disisipkan memakai   cara

normal.

• Pemanggilan ke-2: Argument pertama diisi secara normal, sedangkan

def show_biography(id, name, occupation, gender):

print(f"id: {id}")

print(f"name: {name}")

print(f"occupation: {occupation}")

print(f"gender: {gender}")

id = 'U0001'

name = 'Mikasa Ackerman'

occupation = 'Paradise Survey Corps'

gender = 'female'

show_biography(id, name, occupation, gender)

parameter kedua dan seterusnya disisipkan memakai   metode

unpacking.

• Pemanggilan ke-3: metode unpacking juga digunakan tetapi untuk

argument ke-1 hingga ke-3 (sesuai dengan jumlah element user3_data ).

• Pemanggilan ke-4: Metode unpacking digunakan pada penyisipan

argument parameter ke-2 dan ke-3 saja.

A.32.4. Packing-unpacking item

dictionary

â—‰ Operasi unpack pada dictionary

Operasi unpack pada tipe data dictionary mengembalikan hanya nilai key-nya

saja dalam bentuk list . Nilai value-nya tidak ikut didistribusikan.

user2_id = 'U0002'

user2_data = ('Annie Leonhart', 'Marley Warrior', 'female')

show_biography(user2_id, *user2_data)

user3_data = ('U0003', 'Levi Ackerman', 'Paradise Survey Corps')

show_biography(*user3_data, 'male')

user4_data = ('Hange Zoë', 'Paradise Survey Corps')

show_biography('U0004', *user4_data, 'male')

user_id, *user_data = data

â—‰ Operasi append & prepend pada dictionary

Di atas telah dicontohkan kalau tanda * bisa digunakan untuk menampung

sisa pendistribusian keys dictionary (ingat, hanya keys-nya saja!), maka berarti

tidak bisa digunakan untuk operasi append dan prepend dictionary.

Cara append/prepend dictionary yaitu  dengan memanfaatkan tanda ** .

Contoh penerapannya bisa dilihat pada kode berikut:

data = {

'name': 'Mikasa Ackerman',

}

print(data)

# output ➜ { 'name': 'Mikasa Ackerman' }

data = {

**data,

'occupation': 'Paradise Survey Corps',

}

print(data)

# output ➜ { 'name': 'Mikasa Ackerman', 'occupation': 'Paradise Survey

Corps' }

data = {

'id': 'U0001',

**data,

'gender': 'female',

}

print(data)

# output ↓

#

# {

#   'id': 'U0001',

#   'name': 'Mikasa Ackerman',

#   'occupation': 'Paradise Survey Corps',

#   'gender': 'female'

â—‰ Pemanfaatan teknik unpacking dictionary pada

argument parameter

Tanda ** bisa digunakan untuk operasi unpack dictionary sebagai argument

pemanggilan fungsi. Key dictionary menjadi nama parameter, dan value

dictionary menjadi nilai argument parameter.

Teknik ini bisa dilakukan dengan ketentuan nama parameter fungsi yaitu 

sama dengan key dictionary.

def show_biography(id, name, occupation, gender):

print(f"id: {id}")

print(f"name: {name}")

print(f"occupation: {occupation}")

print(f"gender: {gender}")

data1 = {

'id': 'U0001',

'gender': 'female',

'name': 'Mikasa Ackerman',

'occupation': 'Paradise Survey Corps',

}

show_biography(**data1)

# output ↓

#

# id: U0001

# name: Mikasa Ackerman

# occupation: Paradise Survey Corps

# gender: female

data2 = {

'gender': 'female',

'name': 'Mikasa Ackerman',

'occupation': 'Paradise Survey Corps',

}

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../pack-

unpack-elements

â—‰ Chapter relevan lainnya

• List

• Tuple

• Set

â—‰ Referensi

• https://peps.python.org/pep-0448/


A.33. Python OOP ➜ Class

& Object

Python mendukung paradigma pemrograman berbasis objek (OOP) melalui

implementasi Class dan Object API. Pada bab ini, kita akan mempelajari konsep

dasar beserta penerapannya.

Pembahasan OOP pada ebook ini lebih fokus pada pengaplikasiannya di

Python. Jadi pembahasan teorinya tidak terlalu banyak.

A.33.1. Pengenalan Class

Class yaitu  blueprint untuk membuat variabel, class bisa diartikan juga

sebagai tipe data. Di Python, setiap data pasti memiliki tipe data yang tipe

tersebut merupakan yaitu  class. Sebagai contoh:

• Data string "noval" tipe datanya yaitu  class str

• Data numerik 24 tipe datanya yaitu  class int

• Data floating point 3.1567 tipe datanya yaitu  class float

• ... dan lainnya

Selain memakai   class-class yang tersedia di Python Standard Library, kita

bisa membuat custom class via keyword class . Topik custom class ini

merupakan inti pembahasan chapter ini.

Custom class (atau cukup class) digunakan untuk membuat variabel object.

Cara termudah memahami hubungan antara class dan objek yaitu  melalui

analogi berikut: dimisalkan ada sebuah class bernama Car , class tersebut

kemudian digunakan untuk mendeklarasikan tiga buah variabel bernama

bmw_m3_gtr , mazda_rx8 , dan audi_le_mans . Ketiga object tipe datanya

yaitu  class Car .

Deklarasi class dilakukan dengan memakai   keyword class diikuti oleh

nama class yang diinginkan. Lalu di dalam block class tersebut perlu

dideklarasikan suatu fungsi dengan skema __init__(self) dengan isi body

fungsi yaitu  deklarasi attribute. Contohnya:

Pada contoh di atas, class Car memiliki tiga attribute: name , manufacturer ,

dan year . Nantinya, variabel objek yang dibuat dari class tersebut akan

memiliki tiga atribut sesuai dengan yang dideklarasikan.

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

Fungsi __init__(self) disebut dengan method konstruktor.

Pembahasan detail mengenai konstruktor ada di chapter Class ➜

Constructor

â—‰ Deklarasi class tanpa attribute

Dengan memakai   keyword pass , suatu class bisa dideklarasikan tanpa

memiliki attribute. Contoh penerapannya:

Atau dapat juga ditulis seperti ini:

Pembahasan detail mengenai keyword pass ada di chapter Function

section Keyword pass

A.33.2. Naming convention class

Berdasarkan dokumentasi PEP 8 – Style Guide for Python Code, disarankan

untuk menulis nama class dalam bentuk TitleCase, contoh: FavoriteFood .

class Car:

def __init__(self):

pass

class Car:

pass

A.33.3. Pembuatan Instance object

Object (atau instance object) yaitu  variabel yang dibuat dari class. Cara

pembuatan object yaitu  dengan memanggil nama class diikuti oleh tanda

kurung fungsi () (seperti pemanggilan fungsi). Statement tersebut

mengembalikan nilai balik berupa object baru yang bertipe data sesuai dengan

class yang digunakan.

Ada banyak istilah lain yang merujuk pada variabel objek, seperti

instance, instance variable, instance object, dan lainnya. Namun tidak

usah bingung, karena semua istilah tersebut memiliki makna yang sama.

Contoh deklarasi class Person beserta pembuatan variabel object bernama

person1 :

Penjelasan:

• Class Person dideklarasikan dengan dua atribut, yaitu first_name dan

last_name .

• Class Person dipanggil seperti pemanggilan fungsi (memakai   sintaks

Person() ) dan menghasilkan variabel objek baru bertipe Person , yang

class Person:

def __init__(self):

self.first_name = ""

self.last_name = ""

person1 = Person()

print(f"instance object: {person1}")

print(f"type: {type(person1)}")

kemudian ditampung dalam variabel person1 .

Output program:

Dari output program, terlihat bahwa tipe data variabel person1 yaitu  class

__main__.Person . Syntax tersebut artinya yaitu  tipe data class Person

yang deklarasinya ada di file __main__ atau file entrypoint eksekusi program.

Contoh lainnya pembuatan instance object dari class class Car :

A.33.4. Instance Attribute

Salah satu property class yaitu  attribute. Attribute yaitu  variabel yang

terasosiasi dengan class, jadi dalam pengaksesannya harus dilakukan melalui

class dan/atau instance object.

Sebelumnya, kita telah membuat class bernama Car yang memiliki 3

attribute:

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

car1 = Car()

car2 = Car()

car3 = Car()

• name untuk menyimpan informasi nama/seri mobil

• manufacturer untuk menyimpan informasi manufaktur atau pembuat

mobil

• year untuk menyimpan informasi tahun rilis mobil

Attribute sebenarnya ada 2 jenis, yaitu instance attribute dan class attribute.

Yang sedang kita pelajari di chapter ini yaitu  instance attribute.

Perbedaan mendetail antara instance attribute vs class attribute ada di

chapter Class ➜ Class Attribute & Method

Cara deklarasi instance attribute mirip dengan deklarasi variabel,

perbedaannya pada penulisannya diawali dengan self. . Selain itu

deklarasinya harus berada di dalam body fungsi __init__(self) .

Untuk mengakses instance attribute, kita dapat melakukannya melalui variabel

objek yang dibuat dari class dengan notasi pengaksesan:

<object>.<attribute> .

Contoh:

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

car1 = Car()

print(f"car1 name: {car1.name}")

print(f"car1 manufacturer: {car1.manufacturer}")

print(f"car1 year: {car1.year}")

Saat di-print, dapat dilihat bahwa semua nilai instance attribute milik car1

sesuai dengan nilai default yang ditentukan saat deklarasi attribute dalam

fungsi __init__(self) , yaitu: string kosong "" untuk attribute name &

manufacturer , dan 0 untuk attribute year .

Langkah berikutnya, mari buat tiga buah variabel object dari class Car dan isi

instance attribute-nya dengan suatu nilai. Tiga variabel yang perlu dibuat

yaitu  bmw_m3_gtr , mazda_rx8 , dan audi_le_mans .

Bentuk penerapannya dalam kode Python kurang lebih seperti ini:

Jalankan program untuk melihat outputnya:

Class jika dilihat dari strukturnya memiliki kesamaan dengan dictionary.

Class mempunyai attribute name dan value, sementara dictionary

car1 = Car()

car1.name = "M3 GTR"

car1.manufacturer = "BMW"

car1.year = 2001

print(f"Car name: {car1.manufacturer} {car1.name}\nYear released:

{car1.year}\n")

car2 = Car()

car2.name = "RX-8"

car2.manufacturer = "Mazda"

car2.year = 2002

print(f"Car name: {car2.manufacturer} {car2.name}\nYear released:

{car2.year}\n")

car3 = Car()

car3.name = "Le Mans Quattro"

car3.manufacturer = "Audi"

car3.year = 2003

print(f"Car name: {car3.manufacturer} {car3.name}\nYear released:

{car3.year}\n")

memiliki key dan value.

Perbedaan utama dari keduanya yaitu  pada dictionary key-nya bisa

dikelola secara dinamis, sedangkan pada class nama attribute-nya

yaitu  fixed.

A.33.5. Pengecekan instance object

Fungsi isinstance() cukup berguna untuk mengecek apakah suatu instance

object tipe datanya yaitu  class tertentu atau class yang meng-inherit class

tertentu.

Misalnya, variabel car1 di atas kita cek apakah tipe data nya yaitu  class

Car . Cara penggunaannya cukup panggil fungsi isinstance() lalu sertakan

variabel object yang ingin dicek sebagai argument pertama dan tipe data class

sebagai argument ke-dua.

A.33.6. Class turunan object

Setiap class yang ada di Python baik itu class bawaan Python Standard Library

ataupun custom class, secara otomatis yaitu  turunan dari class bernama

car1 = Car()

car1.name = "M3 GTR"

car1.manufacturer = "BMW"

car1.year = 2001

if isinstance(car1, Car):

print(f"car1 class is Car")

# output ➜ car1 class is Car

object .

Jadi, class str , float , custom class Car yang telah dibuat, dan lainnya,

kesemua class-nya yaitu  turunan dari class object .

Silakan cek memakai   fungsi isinstance() untuk membuktikannya:

Pembahasan detail mengenai class inheritance ada di chapter OOP ➜

Class Inheritance

data1 = Car()

if isinstance(data1, Car):

print(f"data1 class inherit from Car")

if isinstance(data1, object):

print(f"data1 class inherit from object")

data2 = "Noval Agung"

if isinstance(data2, str):

print(f"data2 class inherit from str")

if isinstance(data2, object):

print(f"data2 class inherit from object")

# output ↓

#

# data1 class inherit from Car

# data1 class inherit from object

# data2 class inherit from str

# data2 class inherit from object

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../class-

object

â—‰ Chapter relevan lainnya

• OOP ➜ Instance Method

• OOP ➜ Constructor

• OOP ➜ Property Visibility

• OOP ➜ Instance Attribute & Class Attribute

• OOP ➜ Class Method

• OOP ➜ Static Method

• OOP ➜ Class Inheritance

• OOP ➜ Abstract Method

• OOP ➜ Data Class

â—‰ Referensi

• https://docs.python.org/3/tutorial/classes.html

A.34. Python OOP ➜

Instance Method

Jika attribute yaitu  variabel yang berasosiasi dengan class, maka method

yaitu  fungsi yang berasosiasi dengan class.

Python mengenal 3 jenis method yaitu instance method, class method, dan

static method. Chapter ini fokus ke pembahasan tentang instance method saja.

• Pembahasan detail mengenai class method ada di chapter OOP ➜

Class Method

• Pembahasan detail mengenai static method ada di chapter OOP ➜

Static Method

A.34.1. Pengenalan Instance Method

Instance method memiliki beberapa karakteristik jika dilihat dari syntax-nya:

1. Deklarasinya di dalam block class

2. Parameter pertamanya yaitu  self

3. Method diakses memakai   notasi <object>.<method>()

Dalam praktik kali ini, kita akan melanjutkan praktek class Car yang telah

dibuat di chapter sebelumnya.

Ok, pertama-tama siapkan deklarasi class Car dengan 4 buah property yaitu

name , manufacturer , year , dan description . Kemudian dari class

tersebut, buat 3 buah instance object baru, lalu print data attribute tiap

variabel.

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

self.description = ""

all_cars = []

car1 = Car()

car1.name = "M3 GTR"

car1.manufacturer = "BMW"

car1.year = 2001

car1.description = "Best car in NFS Most Wanted"

all_cars.append(car1)

car2 = Car()

car2.name = "RX-8"

car2.manufacturer = "Mazda"

car2.year = 2002

car2.description = "Best car in NFS Underground 2"

all_cars.append(car2)

car3 = Car()

car3.name = "Le Mans Quattro"

car3.manufacturer = "Audi"

car3.year = 2003

car3.description = "Best car in NFS Carbon"

all_cars.append(car3)

for c in all_cars:

print(f"Car name: {c.manufacturer} {c.name}")

print(f"Description: {c.description}")

print(f"Year released: {c.year}")

print()

Output program:

Setelah itu, modifikasi class Car dengan menambahkan instance method

baru bernama info() . Melalui method ini, value attribute di-print.

Pada bagian blok kode perulangan, ganti tiga baris statement print dengan

pemanggilan method info() .

• Before:

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

self.description = ""

def info(self):

print(f"Car name: {self.manufacturer} {self.name}")

print(f"Description: {self.description}")

print(f"Year released: {self.year}")

• After:

Jalankan program dan lihat outputnya, pasti sama persis dengan program

sebelumnya.

A.34.2. Variabel self

Salah satu aturan pada instance method yaitu  fungsi harus memiliki

parameter pertama bernama self . Parameter tersebut wajib ada saat

deklarasi, dan tidak boleh diisi argument saat pemanggilan. Jika dipaksa diisi

dengan argument, maka pasti muncul error.

for c in all_cars:

print(f"Car name: {c.manufacturer} {c.name}")

print(f"Description: {c.description}")

print(f"Year released: {c.year}")

print()

for c in all_cars:

c.info()

print()

Parameter self bisa disebut dengan parameter implicit atau implisit

karena kita tidak berinteraksi secara langsung saat pengisian nilai. Nilai

self otomatis terisi saat pemanggilan instance method via instance

object.

Dimisalkan lagi, parameter self tidak ditulis saat deklarasi instance method,

hasilnya juga error.

Parameter self merupakan variabel yang merepresentasikan suatu object

atau instance. Melalui variabel ini, kita dapat mengakses instance attribute

maupun instance method (selama property tersebut masih dalam satu class).

Pada contoh sebelumnya, terlihat bagaimana aplikasi dari variabel self

untuk mengakses attribute:

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

Selain untuk mengakses nilainya, dari variabel self suatu attribute juga

dapat diubah nilainya, sebagaimana pada contoh berikut nilai attribute year

dan description diubah melalui pemanggilan instance method

set_details() .

Karena instance method wajib dideklarasikan dengan parameter pertama

self , maka parameter untuk menampung data year dan description

ditulis sebagai parameter setelahnya.

Setelah itu, ubah statement pengisian nilai year dan description

memakai   method set_details() seperti ini:

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 0

self.description = ""

def info(self):

print(f"Car name: {self.manufacturer} {self.name}")

print(f"Description: {self.description}")

print(f"Year released: {self.year}")

def set_details(self, year, description):

self.year = year

self.description = description

all_cars = []

car1 = Car()

car1.name = "M3 GTR"

car1.manufacturer = "BMW"

car1.set_details(2001, "Best car in NFS Most Wanted")

Pada pemanggilan method set_details() object car1 :

• Argument 2001 ditampung oleh parameter year

• Argument Best car in NFS Most Wanted ditampung oleh parameter

description .

A.34.3. Naming convention method &

param

Mengacu pada dokumentasi PEP 8 – Style Guide for Python Code, nama

method dianjurkan untuk ditulis memakai   snake_case (seperti fungsi).

Contohnya bisa dilihat pada method get_name() berikut:

Sedangkan aturan penulisan nama parameter/argument yaitu  sama seperti

nama variabel, yaitu memakai   snake_case juga. Misalnya:

class FavoriteFood:

def __init__(self):

self.name = ""

def print_name(self):

print(self.name)

def get_name(self) -> str:

return self.name

class FavoriteFood:

def __init__(self):

self.name = ""

def print_name(self):

print(self.name)

A.34.4. Pengaksesan instance method

dari class

Sebenarnya ada dua cara untuk mengakses instance method:

1. Lewat instance object, contohnya seperti kode car1.set_details() yang

telah dipraktekan.

2. Lewat class dengan ketentuan dalam pemanggilan methodnya, parameter

pertama harus diisi dengan instance object.

Silakan perhatikan kode berikut agar lebih jelas mengenai cara ke-2.

class FavoriteFood:

def __init__(self):

self.name = ""

def print_name(self):

print(self.name)

def get_name(self) -> str:

return self.name

def set_name(self, name):

self.name = name

food1 = FavoriteFood()

food1.set_name("Pizza")

food1.print_name()

print(food1.get_name())

FavoriteFood.set_name(food1, "Burger")

FavoriteFood.print_name(food1)

print(food1.get_name())

Pada kode di atas, food1 merupakan instance object dari class

FavoriteFood . Lewat object tersebut 3 buah method ini dipanggil:

set_name() , print_name() , dan get_name() .

Kemudian dibawahnya lagi, method set_name() dan print_name() dipanggil

ulang namun dengan syntax yang berbeda. Method dipanggil dari class dan

argument parameter parameter pertamanya diisi instance object food1 .

Penulisan pemanggilan method dari class seperti itu yaitu  diperbolehkan dan

ekuivalen dengan pemanggilan instance method via instance object.

Perbedaannya:

• Pada pengaksesan instance method via instance object, parameter self

tidak perlu diisi.

• Pada pengaksesan instance method via class, parameter self harus

selalu diisi dengan instance object.

Agar makin jelas, silakan lihat tabel berikut. Contoh di kolom pertama yaitu 

ekuivalen dengan contoh di kolom ke 2.

Via instance object Via class

food1.set_name("Pizza") FavoriteFood.set_name(food1, "Pizza")

food1.print_name() FavoriteFood.print_name(food1)

food1.get_name() FavoriteFood.get_name(food1)

A.34.5. Pengaksesan method dari

method lain

Lewat variabel self tidak hanya instance attribute yang dapat diakses,

melainkan semua jenis property (termasuk instance method). Pada contoh

berikut, di dalam method info() terdapat statement pemanggilan method

yaitu get_name() .

Instance method get_name() mengembalikan data string berisi kombinasi

attribute manufacturer dan name .

A.34.6. Argument method: positional,

class Car:

def __init__(self):

self.name = ""

self.manufacturer = ""

self.year = 2023

self.description = ""

def set_details(self, year, description):

self.year = year

self.description = description

def get_name(self):

return f"{self.manufacturer} {self.name}"

def info(self):

print(f"Car name: {self.get_name()}")

print(f"Description: {self.description}")

print(f"Year released: {self.year}")

optional, keyword arg

Aturan-aturan dalam deklarasi parameter dan pengisian argument fungsi juga

berlaku pada method, diantaranya:

• Parameter method yang memiliki default value:

• Positional argument:

• Optional argument:

• Keyword argument:

class Car:

# ...

def set_details(self, year = 2002, description = ""):

self.year = year

self.description = description

# ...

car1 = Car()

car1.name = "M3 GTR"

car1.manufacturer = "BMW"

car1.set_details(2001, "Best car in NFS Most Wanted")

car2 = Car()

car2.name = "RX-8"

car2.manufacturer = "Mazda"

car2.set_details(description="Best car in NFS Underground 2")

A.34.7. Argument method: args & kwargs

Sama seperti fungsi, method juga bisa berisi parameter args maupun kwargs.

Contoh penerapan kwargs pada method bisa dilihat di program berikut.

Modifikasi program di atas, pada method set_details() ubah isinya menjadi

seperti ini:

Melalui parameter **param, kita dapat menentukan attribute mana yang akan

diisi nilainya secara dinamis. Sekarang panggil methodnya lalu isi sesuai

kebutuhan, misalnya:

car3 = Car()

car3.name = "Le Mans Quattro"

car3.manufacturer = "Audi"

car3.set_details(description="Best car in NFS Carbon", year=2003)

class Car:

# ...

def set_details(self, **param):

for key in param:

if key == "name":

self.name = param[key]

if key == "manufacturer":

self.manufacturer = param[key]

if key == "year":

self.year = param[key]

if key == "description":

self.description = param[key]

# ...

Output program:

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../instance-

method

â—‰ Chapter relevan lainnya

• OOP ➜ Class & Object

• OOP ➜ Constructor

• OOP ➜ Class Method

• OOP ➜ Static Method

• OOP ➜ Abstract Method

• OOP ➜ Data Class

car4 = Car()

car4.set_details(name="Chiron Sport", manufacturer="Bugatti")

car4.set_details(year=2021)

car4.set_details(description="Best car in NFS Unbound")

car4.info()

â—‰ TBA

• method & lambda

• method & closure

â—‰ Referensi

• https://docs.python.org/3/tutorial/classes.html

A.35. Python OOP ➜

Constructor

Constructor/konstruktor yaitu  salah satu topik penting dalam pemrograman

berbasis object (OOP). Konstruktor sendiri yaitu  fungsi khusus yang dipanggil

saat pembuatan object dilakukan dari suatu class.

Pada chapter ini kita akan belajar tentang konstruktor dan apa saja yang bisa

dilakukan didalamnya.

A.35.1. Pengenalan constructor

Di bahasa yang mengadopsi konsep OOP, setiap class memiliki default

constructor. Sebagai contoh pada statement pembuatan object bertipe class

Car , syntax Car() digunakan dan syntax tersebut merupakan contoh

penerapan pengaksesan konstruktor.

Sederhananya, konstruktor yaitu  kelas yang dipanggil seperti fungsi

dengan notasi <Class>() .

Agar makin jelas, silakan praktekan kode sederhana berikut:

class Mountain:

pass

mount_everest = Mountain()

print(mount_everest)

# output ➜ <__main__.Mountain object at 0x0000019118A13390>

Class Mountain dideklarasikan tanpa berisi apapun (oleh karena itu keyword

pass digunakan). Kelas tersebut bisa digunakan untuk membuat variabel

object mount_everest dan mount_kilimanjaro dengan cara memanggil

konstruktornya, yaitu Mountain() .

Dalam deklarasi class yang memiliki attribute, constructor wajib di-replace

(atau istilah OOP-nya yaitu  di-override) dengan custom constructor yang

didalamnya berisi deklarasi instance attribute.

Sebagai contoh, class Mountain yang telah dibuat dimodifikasi dengan

ditambahkan tiga buah instance attribute didalamnya yaitu name , region ,

dan elevation .

class Mountain:

def __init__(self):

self.name = ""

self.region = ""

self.elevation = 0

def info(self):

print(f"name: {self.name}")

print(f"region: {self.region}")

print(f"elevation: {self.elevation}m")

mount_everest = Mountain()

mount_everest.name = "Everest"

mount_everest.region = "Asia"

mount_everest.elevation = 8848

mount_everest.info()

# output ↓

#

# name: Everest

# region: Asia

# elevation: 8848m

mount_kilimanjaro = Mountain()

Pada contoh di atas, konstruktor __init__(self) meng-override default

constructor milik class Mountain dan digunakan untuk deklarasi instance

attribute.

A.35.2. Constructor dengan custom

param

Konstruktor dapat didesain untuk memiliki parameter, dan metode ini sangat

umum diterapkan.

Sebagai contoh, pada kode berikut class Mountain konstruktornya

dimodifikasi agar bisa menampung data argument untuk parameter name ,

region , dan elevation .

class Mountain:

def __init__(self, name, region, elevation):

self.name = name

self.region = region

self.elevation = elevation

def info(self):

print(f"name: {self.name}")

print(f"region: {self.region}")

print(f"elevation: {self.elevation}m")

mount_everest = Mountain("Everest", "Asia", 8848)

mount_everest.info()

# output ↓

#

# name: Everest

# region: Asia

# elevation: 8848m

mount_kilimanjaro = Mountain("Kilimanjaro", "Africa", 5895)

Seperti halnya method, parameter pertama konstruktor harus self . Dari sini

bisa disimpulkan berarti penambahan parameter harus dituliskan setelah

self . Bisa dilihat di deklarasi konstruktor class Mountain , disitu ada tiga

buah parameter dideklarasikan setelah self .

A.35.3. Constructor overloading

Overloading merupakan istilah OOP untuk pembuatan banyak konstruktor

dengan jumlah dan tipe parameter berbeda.

Python tidak menyediakan API untuk penerapan constructor overloading,

namun pada praktiknya bisa dicapai dengan hack, misalnya memakai  

opsional/keyword parameter, atau memakai   *args/**kwargs.

• Pembahasan detail mengenai opsional / keyword parameter ada di

chapter Function ➜ Positional, Optional, Keyword Arguments

• Pembahasan detail mengenai args dan kwargs ada di chapter

Function ➜ Args & Kwargs

Contoh constructor overloading memakai   opsional parameter:

class Mountain:

def __init__(self, name = "", region = "", elevation = 0):

self.name = name

self.region = region

self.elevation = elevation

def info(self):

print(f"name: {self.name}")

print(f"region: {self.region}")

print(f"elevation: {self.elevation}m")

Penjelasan:

• Konstruktor class Mountain didesain memiliki 3 buah parameter yang

kesemuanya memiliki nilai default.

• Variabel object mount_everest dibuat dengan dengan mengisi kesemua

parameter konstruktornya.

• Variabel object mount_kilimanjaro dibuat dengan dengan hanya mengisi

dua parameter pertama konstruktor.

• Variabel object mount_aconcagua dibuat dengan dengan mengisi

parameter name dan elevation saja pada pemanggilan konstruktor.

• Variabel object mount_kosciuszko dibuat dengan tanpa diikuti dengan

argument parameter.

Silakan coba explore dengan mempraktekan penggunaan *args / **kwargs

pada konstruktor.

A.35.4. Constructor dengan return typeNone

Constructor dipanggil saat inisialisasi object, maka bisa dibilang bahwa

constructor tersebut selalu mengembalikan tipe data bertipe class dimana

constructor tersebut dideklarasikan.

Dalam pembuatan konstruktor, tidak perlu menuliskan return type maupun

return statement.

Meski demikian, sebenarnya ada 1 lagi bentuk penulisan konstruktor, yaitu

dengan ditambahkan tipe data None dibelakangnya, dan ini diperbolehkan.

Contohnya:

Kode di atas yaitu  ekuivalen dengan kode berikut:

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../class-

constructor

â—‰ Chapter relevan lainnya

• OOP ➜ Class & Object

• OOP ➜ Instance Method

• OOP ➜ Class Method

• OOP ➜ Static Method

• OOP ➜ Abstract Method

• OOP ➜ Data Class

class Mountain:

def __init__(self, name = "", region = "", elevation = 0) -> None:

self.name = name

self.region = region

self.elevation = elevation

class Mountain:

def __init__(self, name = "", region = "", elevation = 0):

self.name = name

self.region = region

self.elevation = elevation

â—‰ Referensi

• https://docs.python.org/3/tutorial/classes.html

A.36. Python OOP ➜

Property Visibility

Visibility atau privacy dalam konteks OOP merujuk pada penentuan apakah

property (baik itu attribute atau method) dapat diakses secara public atau

hanya bisa diakses dari dalam class (private).

Di bab ini, kita akan membahas implementasinya di Python.

A.36.1. Pengenalan visibility/privacy

Python, dari segi API kode yang tersedia, sebenarnya tidak secara eksplisit

mendukung implementasi visibility property instance class. Semua attribute

dan method secara default bersifat public di Python.

Property public berarti property tersebut dapat diakses melalui instance

object atau dari luar block class .

Meskipun demikian, ada beberapa praktik umum untuk menandai bahwa suatu

method atau attribute yaitu  private. Salah satunya yaitu  memakai  

teknik name mangling, di mana nama attribute atau method ditulis dengan

diawali 2 karakter underscore, misalnya __name , __list_items , dan

sejenisnya.

Penamaan tersebut tidak benar-benar membuat visibility property menjadi

private, melainkan hanya sebagai penanda saja. Property sendiri tetap bisa

diakses secara publik.

Mari kita coba praktekan. Pertama siapkan project baru dengan struktur seperti

ini:

Project structure

Package models berisi module company dan product , masing-masing berisi

deklarasi class domain model Company dan Product . Sedangkan file

main.py merupakan file entrypoint program.

Isi kedua tersebut dengan kode berikut:

models/product.py

models/product.py

property-visibility/

│─── models/

| │─── __init__.py

| │─── company.py

| └─── product.py

└─── main.py

class Product:

def __init__(self, name, category):

self.name = name

self.category = category

self.__version = 1.0

class Company:

def __init__(self, name = "", products =[]):

self.name = name

self.products = products

Class Company memiliki 4 buah fungsi:

• Constructor __init__() yang memiliki parameter name dan products .

Argument parameter tersebut datanya disimpan ke attribute.

• Fungsi __print_name() , tugasnya memunculkan isi attribute name . Dari

namanya (yang diawali karakter __ ) bisa disimpulkan bahwa fungsi ini

didesain hanya untuk digunakan secara private (digunakan dalam blok

class saja) dan tidak diperuntukan untuk public.

• Fungsi __print_products() , tugasnya memunculkan isi data produk.

Fungsi ini sama seperti __print_name() yaitu di-desain memiliki visibility

private.

• Method info() yang didalamnya memanggil method __print_name()

dan __print_products() .

Selain yang telah disebutkan di atas, class Company dan Product memiliki 1

property private bernama __version dimana property ini kita isi dengan

informasi versi class.

Selanjutnya, buka main.py , import kedua class tersebut, kemudian buat

beberapa data, lalu print isinya.

main.py

from models import company

from models import product

if __name__ == "__main__":

data = []

c1 = company.Company(name="Microsoft", products=[

Output program:

A.36.2. Property dengan prefix __

Sebelumnya telah disebutkan bahwa prefix __ dalam penerapannya tidak

benar-benar membuat property menjadi private. Silakan test dengan

autocompletion editor, property private masih muncul, menandakan bahwa

property tersebut tidak benar-benar private.

Meskipun demikian, solusi ini cukup efektif untuk memberi petunjuk kepada

programmer bahwa property tersebut tidak didesain untuk konsumsi publik.

Catatan chapter 📑📑

â—‰ Source code praktik

github.com/novalagung/dasarpemrogramanpython-example/../property-

visibility

â—‰ Chapter relevan lainnya

• OOP ➜ Class & Object

• OOP ➜ Instance Attribute & Class Attribute

â—‰ Referensi

• https://docs.python.org/3/tutorial/classes.html#private-variables

A.37. Python OOP ➜

Instance Attribute & Class

Attribute

Pada chapter ini, kita akan belajar lebih dalam tentang attribute suatu class,

jenis-jenisnya, dan penerapannya.

A.37.1. Attributes

Attribute merupakan salah satu property class selain method. Python

mengenal dua jenis attribute yaitu instance attribute (yang sudah kita bahas di

beberapa chapter sebelumnya) dan class attribute.

â—‰ Instance attribute

Instance attribute yaitu  variabel yang terasosiasi dengan instance object, jadi

pengaksesannya harus lewat object. Contoh penerapan instance attribute:

Pada contoh di atas, variabel note merupakan instance attribute milik class

class Pencil:

def __init__(self):

self.note = "A class type to represent a book"

pencil1 = Pencil()

print(f"Object pencil1 note: {pencil1.note}")

# output ➜ Object pencil1 note: A class type to represent a book

Pencil . Ciri khas attribute bisa dilihat dari tempat deklarasinya, yaitu di

dalam konstruktor dan menempel pada variabel self .

Instance attribute terkadang disebut dengan data attribute atau

instance variable. Ketiga istilah tersebut merepresentasikan maksud

yang sama.

â—‰ Class attribute

Class attribute yaitu  variabel yang terasosiasi dengan class yang

pengaksesanya bisa langsung dari class atau bisa juga via object (seperti

pengaksesan instance attribute). Contoh penerapan class attribute:

Berbeda dibanding contoh sebelumnya, kali ini variabel note dideklarasikan

langsung di bawah blok class (tidak di dalam konstruktor) dan tidak

ditempelkan ke variabel self . Cara deklarasi class attribute bisa dibilang

sama seperti deklarasi variabel bisa.

Class attribute bisa diakses langsung dari class contohnya seperti pada kode di

atas, selain itu bisa juga diakses lewat instance object. Contoh:

class Book:

note = "A class type to represent a book"

print(f"Class Book note: {Book.note}")

# output ➜ Class Book note: A class type to represent a book

class Book:

note = "A class type to represent a book"

print(f"Class Book note: {Book.note}")

Class attribute terkadang disebut dengan class variable. Kedua istilah

tersebut merepresentasikan maksud yang sama.

â—‰ Kombinasi instance attribute & class attribute

Instance attribute dan class attribute keduanya bisa digunakan secara

bersamaan dalam satu class yang sama. Penerapannya cukup umum, misalnya

pada kasus dimana ada class yang memiliki 2 kategori attribute. Misalnya pada

class Song berikut, ada attribute yang berasosiasi langsung dengan class

yaitu note & version ; dan ada juga attribute lainnya yang berasosiasi

dengan instance object.

class Song:

note = "A class type to represent a song"

version = 1.0

def __init__(self, name = "", artist = "", album = "", released_year

= 2000):

self.name = name

self.artist = artist

self.album = album

self.released_year = released_year

def info(self):

print(f"Song: {self.name} by {self.artist}")

print(f"Album: {self.album}")

print(f"Released year: {self.released_year}")

songs = [

Song(

name="The Ytse Jam",

artist="Dream Theater",

album="When Dream and Day Unite",

released_year=2004

Output program:

Class attribute biasanya diterapkan untuk menyimpan data yang sifatnya

global dan tidak terpaut ke object, contohnya seperti attribute note dan

version pada class Song di atas.

Berbeda dengan instance attribute yang digunakan untuk menyimpan data

spesifik per object. Bisa dilihat di contoh ada list berisi 2 element yang dibuat

dari class Song . Masing-masing instance object tersebut data attribute-nya

berbeda satu sama lain.

A.37.2. Attribute lookup

Saat suatu instance attribute diakses dari instance object, yang terjadi di balik

layar yaitu  Python melakukan lookup (atau pengecekan) terhadap attribute

dengan urutan sebagai berikut:

1. Jika instance attribute ditemukan, maka Python mengembalikan value

instance attribute.

2. Jika instance attribute yang dicari tidak ditemukan, maka Python

mengembalikan value class attribute.

3. Jika class attribute yang dicari tidak ditemukan, maka error.

Dari kondisi lookup di atas bisa disimpulkan bahwa sewaktu pengaksesan

instance attribute, Python selalu memprioritaskan data yang ada di instance

attribute dibanding property lainnya.

Lalu bagaiamana jika misalnya ada class yang miliki class attribute dan juga

instance attribute yang namanya sama persis? Jawabannya: Python tetap

memprioritaskan nilai instance attribute.

Contoh bisa dilihat pada kode berikut:

Variabel person1 ketika diakses attribute name -nya, yang dikembalikan

yaitu  nilai instance attribute, meskipun sebenarnya class Person juga

memiliki class attribute dengan nama yang sama.

A.37.3. Attribute mutability

â—‰ Perubahan nilai instance attribute

Instance attribute datanya yaitu  menempel ke instance object. Jadinya,

setiap object bisa saja memiliki attribute dengan value berbeda satu sama lain.

class Person:

name = "A person"

def __init__(self, name):

self.name = name

person1 = Person("Noval Agung Prayogo")

print(f"Object person1 name: {person1.name}")

# output ➜ Object person1 name: Noval Agung Prayogo

print(f"Class Person name: {Person.name}")

# output ➜ Class Person name: A person

Dimisalkan ada satu variabel object yang nilai attribute-nya diubah, maka efek

perubahan hanya terjadi di variabel tersebut saja, tidak berefek ke variabel

lain. Agar lebih jelas silakan lihat contoh berikut:

â—‰ Perubahan nilai class attribute dari instance object

Bagaimana jika attri