Foto: Chris RiedPada artikel ini, Anda akan memahami apa itu paradigma fungsional dan bagaimana menggunakan pemrograman fungsional dengan Python. Anda juga akan belajar tentang
abstraksi daftar dan pemahaman daftar lainnya.
Paradigma fungsional
Dalam paradigma imperatif, Anda menulis sebuah program dengan menentukan urutan tindakan yang kemudian dilakukan. Pada saat ini, status (
kira-kira Penerjemah: variabel, array, dll. ) Berubah. Misalnya, biarkan variabel A menyimpan nilai 5, nanti Anda mengubah nilai variabel ini. Anda menggunakan variabel sehingga nilainya berubah.
Dalam paradigma fungsional, Anda tidak memberi tahu komputer apa yang harus dilakukan, melainkan menentukan sifat tindakan itu sendiri. Apa pembagi umum terbesar dari suatu angka, hasil perhitungan dari 1 ke n, dll.
Oleh karena itu, variabel tidak berubah. Setelah variabel diinisialisasi, nilainya disimpan selamanya (perhatikan bahwa dalam bahasa fungsional murni mereka bahkan tidak disebut variabel). Oleh karena itu, dalam paradigma fungsional, fungsi tidak memiliki
efek samping . Efek samping dapat didefinisikan sebagai momen di mana suatu fungsi mengubah sesuatu di luar batasnya. Lihatlah sebuah contoh:
a = 3 def some_func(): global a a = 5 some_func() print(a)
Hasil dari eksekusi kode ini adalah 5. Dalam pemrograman fungsional, mengubah variabel dilarang, dan mengubah fungsi sesuatu di luar batas mereka juga. Semua fungsi dapat dilakukan adalah untuk menghitung / memproses sesuatu dan mengembalikan hasilnya.
Sekarang, Anda mungkin berpikir: βTidak ada variabel, tidak ada efek samping? Kenapa itu bagus? " Pertanyaan yang sangat bagus.
Jika suatu fungsi telah dipanggil dua kali dengan parameter yang sama, jelas itu akan mengembalikan hasil yang sama. Jika Anda telah mempelajari sesuatu tentang
fungsi matematika , maka Anda akan menghargai kesempatan ini. Ini disebut transparansi tautan atau transparansi referensial. Karena fungsi tidak memiliki efek samping, jika Anda mengembangkan program perhitungan, Anda dapat mempercepat proses eksekusi. Jika program mengetahui bahwa func (2) adalah 3, kita dapat mengingat ini. Ini mencegah fungsi dipanggil lagi ketika kita sudah tahu hasilnya.
Biasanya, dalam pemrograman fungsional, loop tidak digunakan. Rekursi digunakan. Rekursi adalah konsep matematika, pada kenyataannya, itu berarti "memberi makan sesuatu kepada diri sendiri." Dalam fungsi rekursif, fungsi itu sendiri menyebut dirinya peran sub-fungsi. Berikut adalah contoh fungsi rekursif dengan Python:
def factorial_recursive(n):
Beberapa bahasa pemrograman
malas . Ini berarti mereka menghitung semuanya pada saat terakhir. Misalkan jika kode harus mengeksekusi 2 + 2, program fungsional akan menghitung hasilnya hanya ketika hasilnya diperlukan. Kita akan belajar tentang kemalasan Python sedikit kemudian.
Peta
Untuk memahami peta, Anda harus terlebih dahulu berurusan dengan wadah yang dapat diubah. Ini adalah wadah tempat Anda bisa "pergi". Ini sering daftar atau array, tetapi ada banyak wadah seperti itu di Python. Anda bahkan dapat membuat wadah sendiri dengan memperkenalkan
metode sihir . Metode-metode ini, seperti API, membantu objek menjadi lebih pythonic. Ada 2 metode seperti itu untuk membuat objek dapat diubah:
class Counter: def __init__(self, low, high):
Metode sulap pertama adalah "___iter__" atau dunder (digarisbawahi ganda oleh garis bawah) iter mengembalikan objek iterable, ini sering digunakan pada awal loop. Dunder next (__next__) mengembalikan objek berikutnya.
Lihat ini:
for c in Counter(3, 8): print(c)
Hasil Eksekusi:
3
4
5
6
7
8
Dalam Python, iterator adalah objek yang hanya memiliki metode __iter__. Ini berarti bahwa Anda dapat mengakses tempat sel-sel objek (wadah), tetapi Anda tidak bisa "berjalan" melaluinya. Beberapa objek hanya memiliki metode __next__ yang indah, tanpa metode __iter__ ajaib, misalnya, atur (lebih banyak tentang itu nanti). Pada artikel ini, kita akan membahas segala sesuatu yang berhubungan dengan objek yang dapat diubah.
Sekarang kita tahu apa itu objek yang dapat diubah, mari kembali ke fungsi peta. Fungsi ini memungkinkan kita untuk menerapkan aksi beberapa fungsi lainnya ke setiap elemen dalam wadah yang diulang. Kami ingin menerapkan fungsi ke setiap elemen dalam daftar, ini dimungkinkan untuk hampir semua wadah yang dapat diubah. Peta, membutuhkan dua argumen: fungsi yang akan diterapkan, dan wadah (daftar, dll.).
map(function, iterable)
Misalkan kita memiliki daftar dengan elemen-elemen berikut:
[1, 2, 3, 4, 5]
Dan kami ingin mengkuadratkan setiap elemen, ini bisa dilakukan seperti ini:
x = [1, 2, 3, 4, 5] def square(num): return num*num print(list(map(square, x)))
Fungsi fungsional dalam Python malas. Jika kita tidak menambahkan "daftar ()", fungsi akan menyimpan deskripsi wadah (daftar), dan bukan daftar itu sendiri. Kami secara langsung perlu memberi tahu Python untuk mengonversikan ini ke daftar.
Agak aneh untuk berpindah dari definisi yang tidak malas ke definisi yang malas begitu tiba-tiba. Anda akan terbiasa jika Anda berpikir lebih dalam cara fungsional daripada keharusan.
Fungsi penulisan, misalnya, "kuadrat (num)" adalah normal, tetapi tidak sepenuhnya benar. Apakah kita perlu mendeklarasikan seluruh fungsi hanya untuk menggunakannya di peta? Ini dapat disederhanakan dengan memperkenalkan fungsi lambda (anonim).
Ekspresi Lambda
Ekspresi Lambda adalah fungsi dalam satu baris, misalnya, di sini adalah ekspresi lambda yang mengkuadratkan angka yang dihasilkan:
square = lambda x: x * x
Dan, jalankan ini:
>>> square(3)
9
Aku bisa mendengarmu. "Brandon, di mana argumennya?" Tentang apa semua ini? Ini bukan seperti fungsi. "
Ya, ini bisa membingungkan, tetapi bisa dijelaskan. Di baris ini, kami menetapkan sesuatu ke variabel "kuadrat". Bagian ini:
lambda x: x * x
Memberitahu Python bahwa kita menggunakan fungsi lambda, dan inputnya bernama x. Semuanya setelah titik dua adalah apa yang akan terjadi pada input, dan kami akan secara otomatis mendapatkan hasilnya nanti.
Untuk program kami dalam bentuk one-line, Anda perlu melakukan ini:
x = [1, 2, 3, 4, 5] print(list(map(lambda num: num * num, x)))
Jadi, dalam ungkapan lambda, argumennya ada di sebelah kiri, dan tindakan atas mereka ada di kanan. Ini sedikit berantakan, tidak ada yang menyangkal. Yang benar adalah bahwa ada sesuatu di dalamnya, untuk menulis kode fungsional seperti itu. Selain itu, sangat keren untuk mengonversi fungsi menjadi satu baris.
Kurangi
Reduce adalah fungsi yang mengubah wadah yang dapat diubah menjadi satu hal. Artinya, perhitungan dibuat yang mengubah daftar menjadi satu nomor. Ini terlihat seperti ini:
reduce(function, list)
Kita dapat (dan sering akan) menggunakan fungsi lambda sebagai argumen fungsi.
Jika kita ingin melipatgandakan semua angka dalam daftar, ini bisa dilakukan seperti ini:
product = 1 x = [1, 2, 3, 4] for num in x: product = product * num
Dan dengan mengurangi akan terlihat seperti ini:
from functools import reduce product = reduce((lambda x, y: x * y),[1, 2, 3, 4])
Hasilnya akan sama, tetapi kode lebih pendek dan dengan pengetahuan pemrograman fungsional untuk menggunakannya lebih akurat.
Saring
Fungsi filter mengambil wadah yang dapat diulang dan memfilternya sesuai dengan aturan yang diberikan (juga fungsi).
Biasanya dibutuhkan fungsi dan daftar sebagai input. Kemudian itu berlaku fungsi untuk setiap elemen dalam daftar, jika fungsi mengembalikan Benar, tidak ada yang terjadi, dan jika Salah, elemen dihapus dari daftar.
Sintaks:
filter(function, list)
Mari kita lihat contoh tanpa menggunakan filter:
x = range(-5, 5) new_list = [] for num in x: if num < 0: new_list.append(num)
Bersama dengan filter:
x = range(-5, 5) all_less_than_zero = list(filter(lambda num: num < 0, x))
Fungsi Orde Tinggi
Fungsi tingkat tinggi dapat menggunakan fungsi sebagai argumen dan mengembalikannya. Contoh sederhana akan terlihat seperti ini:
def summation(nums): return sum(nums) def action(func, numbers): return func(numbers) print(action(summation, [1, 2, 3]))
Atau sebuah contoh bahkan lebih sederhana:
def rtnBrandon(): return "brandon" def rtnJohn(): return "john" def rtnPerson(): age = int(input("What's your age?")) if age == 21: return rtnBrandon() else: return rtnJohn()
Ingat sebelumnya saya mengatakan bahwa pemrograman fungsional nyata tidak menggunakan variabel. Fungsi tingkat tinggi memungkinkan ini. Anda tidak perlu menyimpan variabel di suatu tempat jika Anda melewatkan informasi melalui "terowongan" fungsi yang panjang.
Semua fungsi dalam Python adalah objek kelas satu. Objek kelas pertama didefinisikan seperti itu, yang sesuai dengan satu atau lebih dari parameter berikut:
- Menciptakan siklus tugas
- Ditugaskan ke variabel atau item dalam struktur data
- Diberikan sebagai argumen fungsi
- Kembali sebagai hasil dari eksekusi fungsi
Jadi semua fungsi dalam Python adalah objek kelas satu, dan dapat digunakan sebagai fungsi tingkat tinggi.
Aplikasi sebagian
Penggunaan sebagian (juga interupsi) agak aneh, tetapi sangat keren. Anda dapat memanggil fungsi tanpa menggunakan semua argumen yang diberikan. Mari kita lihat sebuah contoh. Kami ingin membuat fungsi yang membutuhkan 2 argumen, basis dan derajat, dan mengembalikan basis yang diangkat ke kekuasaan, tampilannya seperti ini:
def power(base, exponent): return base ** exponent
Sekarang kita perlu membuat fungsi terpisah untuk mengkuadratkan, dan menghitungnya menggunakan fungsi daya:
def square(base): return power(base, 2)
Berhasil, tetapi bagaimana jika kita ingin membuat angka? Atau di tingkat 4? Haruskah Anda menulis fungsi seperti itu selamanya? Tentu saja bisa. Tapi programmer malas. Jika Anda mengulangi hal yang sama beberapa kali, mungkin ada cara untuk melakukannya lebih cepat dan berhenti melakukan pengulangan. Aplikasi sebagian dapat digunakan di sini. Mari kita lihat contoh fungsi daya menggunakan aplikasi parsial:
from functools import partial square = partial(power, exponent=2) print(square(2))
Bukankah itu keren? Kita dapat memanggil fungsi yang membutuhkan 2 argumen, hanya menggunakan 1, dan menentukan apa yang akan menjadi argumen sendiri.
Anda juga dapat menggunakan loop untuk mensimulasikan fungsi daya yang akan bekerja dengan kubus hingga kekuatan 1000.
from functools import partial powers = [] for x in range(2, 1001): powers.append(partial(power, exponent = x)) print(powers[0](3))
Pemrograman fungsional tidak cocok dengan kanon pythonic
Anda mungkin telah memperhatikan bahwa banyak hal yang ingin kita lakukan dalam pemrograman fungsional berkisar pada daftar. Selain mengurangi fungsi dan aplikasi parsial, semua fungsi yang Anda lihat menghasilkan daftar. Guido (pencipta Python`a) tidak suka hal-hal fungsional dalam Python`e, karena Python memiliki metode sendiri dalam membuat daftar.
Jika Anda menulis "impor ini" di konsol, Anda akan mendapatkan:
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one β and preferably only one β obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea β let's do more of those!
Ini adalah Python Zen. Ini adalah ayat tentang apa artinya menjadi seorang pythonist. Bagian yang menarik bagi kami adalah:
Seharusnya ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukannya.
Seharusnya hanya ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukan sesuatu.
Dalam Python, peta dan filter dapat melakukan hal yang sama seperti abstraksi daftar (
tautan ). Ini melanggar salah satu aturan Python-Zen, jadi ini bagian dari pemrograman fungsional bukan "pythonic".
Hal-hal selanjutnya untuk dibicarakan adalah fungsi lambda. Dalam Python, fungsi lambda adalah fungsi normal. Dan sebenarnya itu adalah gula sintaksis. Kedua bagian ini melakukan hal yang sama:
foo = lambda a: 2 def foo(a): return 2
Fungsi standar mungkin masih sama dengan fungsi lambda, tetapi tidak sebaliknya. Fungsi Lambda tidak bisa sama dengan yang biasa.
Ini adalah komentar kecil tentang mengapa pemrograman fungsional tidak cukup cocok dengan ideologi pythonic. Sebelumnya, saya menyebutkan abstraksi daftar (
juga daftar inklusi ), sekarang mari kita bicarakan.
Daftar abstraksi
Saya sudah mengatakan bahwa semua yang dapat dilakukan dengan menggunakan peta dan filter dapat dilakukan dengan menggunakan abstraksi daftar. Pada bagian ini kita akan membahasnya.
Daftar abstraksi adalah cara untuk membuat daftar dengan Python. Sintaks:
[function for item in iterable]
Mari kita kuadratkan setiap item dalam daftar, misalnya:
print([x * x for x in [1, 2, 3, 4]])
Oke, kita bisa melihat bagaimana menerapkan fungsi ke setiap elemen daftar. Bagaimana kita menyiasati filter? Lihatlah kode ini:
x = range(-5, 5) all_less_than_zero = list(filter(lambda num: num < 0, x)) print(all_less_than_zero)
Sekarang gunakan daftar abstraksi:
x = range(-5, 5) all_less_than_zero = [num for num in x if num < 0]
Daftar abstraksi mendukung ekspresi kondisional dari jenis ini. Anda tidak perlu lagi menggunakan sejuta fungsi untuk mendapatkan sesuatu. Bahkan, jika Anda mencoba melakukan sesuatu dengan daftar, ada kemungkinan lebih bersih dan lebih mudah dicapai dengan abstraksi daftar.
Bagaimana jika kita ingin menguadratkan setiap elemen daftar yang di bawah nol. Dengan fungsi lambda, memetakan dan memfilter, akan terlihat seperti ini:
x = range(-5, 5) all_less_than_zero = list(map(lambda num: num * num, list(filter(lambda num: num < 0, x))))
Entri ini tidak rasional dan tidak terlalu sederhana. Menggunakan abstraksi daftar, akan terlihat seperti ini:
x = range(-5, 5) all_less_than_zero = [num * num for num in x if num < 0]
Daftar abstraksi hanya baik, cukup aneh, untuk daftar. Peta dan penyaringan bekerja untuk setiap wadah yang dapat diubah, jadi apa yang salah? .. Ya, Anda dapat menggunakan abstraksi untuk setiap wadah yang dapat diubah yang Anda temui.
Abstraksi lainnya
Anda dapat menerapkan abstraksi untuk setiap wadah yang dapat diubah.
Setiap wadah yang dapat diubah dapat dibuat menggunakan abstraksi. Dimulai dengan versi 2.7, Anda bahkan dapat membuat kamus (tabel hash).
Jika sesuatu adalah wadah yang dapat diubah, maka sesuatu dapat dihasilkan. Mari kita lihat contoh terakhir menggunakan set. Jika Anda tidak tahu apa set, maka lihat
artikel ini yang ditulis oleh saya juga. Singkatnya:
- Set adalah wadah elemen, elemen di dalamnya tidak diulang
- Ketertiban tidak penting
Seperti yang mungkin Anda perhatikan, set, seperti kamus, menggunakan kurung kurawal. Python sangat pintar. Dia akan menebak apakah Anda menggunakan abstraksi kamus atau abstraksi set`a, berdasarkan apakah Anda menentukan parameter tambahan untuk kamus atau tidak. Jika Anda ingin tahu lebih banyak tentang abstraksi, baca
ini . Jika tentang abstraksi dan generasi, maka yang
ini .
Ringkasan
Pemrograman fungsional sangat bagus. Kode fungsional dapat berupa bersih atau tidak terlalu. Beberapa pythonis hardcore tidak menerima paradigma fungsional dalam Python. Anda harus menggunakan apa yang Anda inginkan dan apa yang cocok untuk Anda.
Halaman penulis