از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
برنامه نویسی تابعی در پایتون
سرفصلهای مطلب
معرفی
برنامه نویسی تابعی یک الگوی برنامه نویسی محبوب است که از نزدیک با مبانی ریاضی علوم کامپیوتر مرتبط است. در حالی که هیچ تعریف دقیقی از اینکه چه چیزی یک زبان کاربردی را تشکیل می دهد وجود ندارد، ما آنها را زبان هایی می دانیم که از توابع برای تبدیل داده ها استفاده می کنند.
پایتون یک زبان برنامه نویسی تابعی نیست اما برخی از مفاهیم آن را در کنار سایر پارادایم های برنامه نویسی گنجانده است. با پایتون، نوشتن کد به سبک عملکردی آسان است، که ممکن است بهترین راه حل را برای کار در دست ارائه دهد.
مفاهیم برنامه نویسی تابعی
زبان های کاربردی هستند اعلامی زبان ها، آنها به کامپیوتر می گویند که چه نتیجه ای می خواهند. این معمولاً در تضاد است امری ضروری زبان هایی که به کامپیوتر می گویند برای حل یک مشکل چه مراحلی را باید بردارد. پایتون معمولاً به صورت دستوری کدگذاری میشود، اما در صورت لزوم میتواند از سبک اعلامی استفاده کند.
برخی از ویژگی های پایتون تحت تأثیر قرار گرفت هاسکل، یک زبان برنامه نویسی کاملا کاربردی است. برای درک بهتر زبان کاربردی، اجازه دهید به ویژگیهایی در Haskell که به عنوان ویژگیهای کاربردی و مطلوب در نظر گرفته میشوند نگاهی بیندازیم:
- توابع خالص – عوارض جانبی ندارند، یعنی حالت برنامه را تغییر نمی دهند. با توجه به ورودی یکسان، یک تابع خالص همیشه همان خروجی را تولید می کند.
- تغییرناپذیری – داده ها را نمی توان پس از ایجاد تغییر داد. برای مثال ایجاد a را در نظر بگیرید
List
با 3 آیتم و ذخیره آن در یک متغیرmy_list
. اگرmy_list
تغییر ناپذیر است، شما نمی توانید موارد جداگانه را تغییر دهید. شما باید تنظیم کنیدmy_list
به یک جدیدList
اگر می خواهید از مقادیر مختلف استفاده کنید. - توابع مرتبه بالاتر – توابع می توانند توابع دیگر را به عنوان پارامتر بپذیرند و توابع می توانند توابع جدید را به عنوان خروجی برگردانند. این به ما اجازه میدهد تا از اعمال خود انتزاع کنیم و در رفتار کدمان انعطافپذیری به ما میدهد.
Haskell همچنین از طریق بارگذاری تنبل خود بر تکرارکننده ها و مولدهای پایتون تأثیر گذاشته است، اما این ویژگی برای یک زبان کاربردی ضروری نیست.
برنامه نویسی تابعی در پایتون
بدون هیچ ویژگی یا کتابخانه خاصی پایتون، میتوانیم کدنویسی را به روشی کاربردیتر شروع کنیم.
توابع خالص
اگر میخواهید توابع خالص باشند، مقدار ورودی یا هر دادهای که خارج از محدوده تابع وجود دارد را تغییر ندهید.
این باعث می شود عملکردی که ما می نویسیم آزمایش شود. از آنجایی که وضعیت هیچ متغیری را تغییر نمیدهد، هر بار که تابع را با ورودی یکسان اجرا میکنیم، تضمین میکنیم که خروجی یکسانی را دریافت کنیم.
بیایید یک تابع خالص برای ضرب اعداد در 2 ایجاد کنیم:
def multiply_2_pure(numbers):
new_numbers = ()
for n in numbers:
new_numbers.append(n * 2)
return new_numbers
original_numbers = (1, 3, 5, 10)
changed_numbers = multiply_2_pure(original_numbers)
print(original_numbers)
print(changed_numbers)
لیست اصلی از numbers
بدون تغییر هستند، و ما به هیچ متغیر دیگری خارج از تابع ارجاع نمی دهیم، بنابراین خالص است.
تغییرناپذیری
تا به حال یک اشکالی داشته اید که در آن تعجب کنید که چگونه متغیری که روی 25 تنظیم کرده اید تبدیل شده است None
? اگر آن متغیر تغییرناپذیر بود، خطا در جایی که متغیر در حال تغییر بود پرتاب میشد، نه جایی که مقدار تغییر یافته قبلاً روی نرمافزار تأثیر گذاشته بود – root علت اشکال را می توان زودتر پیدا کرد.
پایتون برخی از انواع داده های تغییرناپذیر را ارائه می دهد که یکی از محبوب ترین آنها است Tuple
. بیایید تاپل را با یک لیست مقایسه کنیم که قابل تغییر است:
mutable_collection = ('Tim', 10, (4, 5))
immutable_collection = ('Tim', 10, (4, 5))
print(mutable_collection(2))
print(immutable_collection(2))
mutable_collection(1) = 15
immutable_collection(1) = 15
خطایی که مشاهده خواهید کرد این است: TypeError: 'tuple' object does not support item assignment
.
حال، یک سناریوی جالب وجود دارد که در آن a Tuple
ممکن است به نظر یک شیء قابل تغییر باشد. به عنوان مثال، اگر بخواهیم لیست را تغییر دهیم immutable_collection
از جانب (4, 5)
به (4, 5, 6)
، می توانید کارهای زیر را انجام دهید:
immutable_collection(2).append(6)
print(immutable_collection(2))
این کار می کند زیرا a List
یک شیء قابل تغییر است. بیایید سعی کنیم لیست را به دوباره تغییر دهیم (4, 5)
.
immutable_collection(2) = (4, 5)
همانطور که انتظار داشتیم شکست می خورد. در حالی که می توانیم محتویات یک شیء قابل تغییر را در a تغییر دهیم Tuple
، نمی توانیم مرجع را به شیء قابل تغییر ذخیره شده در حافظه تغییر دهیم.
توابع مرتبه بالاتر
به یاد بیاورید که توابع مرتبه بالاتر یا یک تابع را به عنوان آرگومان می پذیرند یا یک تابع را برای پردازش بیشتر برمی گردانند. بیایید نشان دهیم که چقدر ساده می توان هر دو را در پایتون ایجاد کرد.
تابعی را در نظر بگیرید که یک خط را چندین بار چاپ می کند:
def write_repeat(message, n):
for i in range(n):
print(message)
write_repeat('Hello', 5)
اگر بخواهیم 5 بار در یک فایل بنویسیم، یا 5 بار پیام را وارد کنیم، چه؟ به جای نوشتن 3 تابع مختلف که همه حلقه هستند، می توانیم 1 تابع مرتبه بالاتر بنویسیم که آن توابع را به عنوان آرگومان می پذیرد:
def hof_write_repeat(message, n, action):
for i in range(n):
action(message)
hof_write_repeat('Hello', 5, print)
import logging
hof_write_repeat('Hello', 5, logging.error)
حال تصور کنید که ما وظیفه داریم توابعی ایجاد کنیم که اعداد را در یک لیست با 2، 5 و 10 افزایش می دهند. بیایید با مورد اول شروع کنیم:
def add2(numbers):
new_numbers = ()
for n in numbers:
new_numbers.append(n + 2)
return new_numbers
print(add2((23, 88)))
در حالی که نوشتن پیش پا افتاده است add5
و add10
توابع، بدیهی است که آنها به همان صورت عمل می کنند: حلقه زدن لیست و اضافه کردن افزایش دهنده. بنابراین به جای ایجاد بسیاری از توابع افزایشی مختلف، 1 تابع مرتبه بالاتر ایجاد می کنیم:
def hof_add(increment):
def add_increment(numbers):
new_numbers = ()
for n in numbers:
new_numbers.append(n + increment)
return new_numbers
return add_increment
add5 = hof_add(5)
print(add5((23, 88)))
add10 = hof_add(10)
print(add10((23, 88)))
توابع سفارش بالاتر به کد ما انعطاف پذیری می دهد. با انتزاع توابع اعمال شده یا برگردانده شده، کنترل بیشتری بر رفتار برنامه خود به دست می آوریم.
پایتون چند توابع داخلی مفید برای مرتبه بالاتر ارائه می دهد که کار با دنباله ها را بسیار آسان تر می کند. ما ابتدا به عبارات لامبدا نگاه می کنیم تا بهتر از این توابع داخلی استفاده کنیم.
عبارات لامبدا
عبارت لامبدا یک تابع ناشناس است. وقتی توابعی را در پایتون ایجاد می کنیم، از آن استفاده می کنیم def
کلمه کلیدی و نام گذاری آن عبارات لامبدا به ما این امکان را می دهند که یک تابع را خیلی سریعتر تعریف کنیم.
بیایید یک تابع سفارش بالاتر ایجاد کنیم hof_product
که تابعی را برمی گرداند که یک عدد را در یک مقدار از پیش تعریف شده ضرب می کند:
def hof_product(multiplier):
return lambda x: x * multiplier
mult6 = hof_product(6)
print(mult6(6))
عبارت لامبدا با کلمه کلیدی شروع می شود lambda
به دنبال آرگومان های تابع. بعد از کولون، کدی است که لامبدا برگردانده است. این توانایی برای ایجاد توابع “روی the go” بهشدت هنگام کار با عملکردهای مرتبه بالاتر استفاده میشود.
در مورد عبارات لامبدا چیزهای بیشتری وجود دارد که اگر اطلاعات بیشتری می خواهید، در مقاله توابع لامبدا در پایتون به آنها می پردازیم.
توابع سفارش بالاتر داخلی
پایتون برخی از توابع مرتبه بالاتر رایج را از زبان های برنامه نویسی تابعی پیاده سازی کرده است که پردازش اشیاء تکرارپذیر مانند لیست ها و تکرار کننده ها را بسیار آسان تر می کند. به دلایل کارایی فضا/حافظه، این توابع یک را برمیگردانند iterator
به جای یک لیست
نقشه
را map
تابع به ما اجازه می دهد تا یک تابع را برای هر عنصر در یک شی تکرار شونده اعمال کنیم. برای مثال، اگر لیستی از نامها داشتیم و میخواستیم یک تبریک به رشتهها اضافه کنیم، میتوانیم کارهای زیر را انجام دهیم:
names = ('Shivani', 'Jason', 'Yusef', 'Sakura')
greeted_names = map(lambda x: 'Hi ' + x, names)
print(greeted_names)
for name in greeted_names:
print(name)
فیلتر کنید
را filter
تابع هر عنصر را در یک شیء تکرارپذیر با تابعی که یکی را برمی گرداند، آزمایش می کند True
یا False
، فقط مواردی را که ارزیابی می کنند حفظ کنید True
. اگر لیستی از اعداد داشتیم و می خواستیم اعدادی را که بر 5 بخش پذیر هستند نگه داریم، می توانیم موارد زیر را انجام دهیم:
numbers = (13, 4, 18, 35)
div_by_5 = filter(lambda num: num % 5 == 0, numbers)
print(list(div_by_5))
ترکیب کردن map
و filter
از آنجایی که هر تابع یک تکرارکننده را برمیگرداند و هر دو اشیاء تکرارپذیر را میپذیرند، میتوانیم از آنها برای دستکاری دادههای واقعاً گویا استفاده کنیم!
arbitrary_numbers = map(lambda num: num ** 3, filter(lambda num: num % 3 == 0, range(1, 21)))
print(list(arbitrary_numbers))
بیان در arbitrary_numbers
را می توان به 3 قسمت تقسیم کرد:
range(1, 21)
یک شیء تکرارپذیر است که اعداد 1، 2، 3، 4… 19، 20 را نشان می دهد.filter(lambda num: num % 3 == 0, range(1, 21))
یک تکرار کننده برای دنباله اعداد 3، 6، 9، 12، 15 و 18 است.- هنگامی که آنها توسط مکعب می شوند
map
عبارت ما می توانیم یک تکرار کننده برای دنباله اعداد 27، 216، 729، 1728، 3375 و 5832 دریافت کنیم.
فهرست درک
یکی از ویژگی های محبوب پایتون که به طور برجسته در زبان های برنامه نویسی کاربردی ظاهر می شود، درک لیست است. مانند map
و filter
توابع، درک لیست به ما امکان می دهد داده ها را به روشی مختصر و رسا اصلاح کنیم.
بیایید نمونه های قبلی خود را با آن امتحان کنیم map
و filter
با درک لیست به جای:
names = ('Shivani', 'Jan', 'Yusef', 'Sakura')
greeted_names = ('Hi ' + name for name in names)
print(greeted_names)
یک لیست اساسی از این قالب پیروی می کند: (نتیجه for
عنصر مفرد in
لیست-نام).
اگر میخواهیم اشیاء را فیلتر کنیم، باید از آن استفاده کنیم if
کلمه کلیدی:
numbers = (13, 4, 18, 35)
div_by_5 = (num for num in numbers if num % 5 == 0)
print(div_by_5)
arbitrary_numbers = (num ** 3 for num in range(1, 21) if num % 3 == 0)
print(arbitrary_numbers)
هر map
و filter
عبارت را می توان به صورت درک لیست بیان کرد.
برخی از چیزهایی که باید در نظر بگیرید
به خوبی شناخته شده است که خالق پایتون، Guido van Rossum، قصد نداشت پایتون ویژگی های کاربردی داشته باشد، اما از برخی از مزایای معرفی آن به زبان قدردانی کرد. او تاریخچه ویژگی های زبان برنامه نویسی کاربردی را در یکی از خود مورد بحث قرار داد پست های وبلاگ. در نتیجه، پیاده سازی های زبان برای ویژگی های برنامه نویسی تابعی بهینه نشده اند.
علاوه بر این، جامعه توسعه دهندگان پایتون استفاده از مجموعه وسیعی از ویژگی های برنامه نویسی کاربردی را تشویق نمی کند. اگر برای جامعه جهانی پایتون کد مینوشتید تا بررسی شود، به جای استفاده از فهرست، درک مطلب را مینویسید map
یا filter
. همانطور که توابع خود را نامگذاری می کنید، لامبدا به حداقل ممکن استفاده می شود.
در مفسر پایتون خود وارد کنید import this
و “ذن پایتون” را خواهید دید. پایتون عموماً کد را تشویق می کند که به واضح ترین شکل ممکن نوشته شود. در حالت ایدهآل، همه کدها باید به یک روش نوشته شوند – جامعه فکر نمیکند که باید به سبک Functional باشد.
نتیجه
برنامه نویسی تابعی یک الگوی برنامه نویسی با نرم افزاری است که عمدتاً از توابع پردازش داده ها در طول اجرای آن تشکیل شده است. اگرچه یک تعریف واحد از برنامهنویسی تابعی وجود ندارد، ما توانستیم برخی از ویژگیهای برجسته را در زبانهای تابعی بررسی کنیم: توابع خالص، تغییرناپذیری و توابع مرتبه بالاتر.
پایتون به ما این امکان را می دهد که به سبک عملکردی و اعلانی کدنویسی کنیم. حتی از بسیاری از ویژگیهای کاربردی رایج مانند Lambda Expressions و map
و filter
کارکرد.
با این حال، جامعه پایتون استفاده از تکنیکهای برنامهنویسی تابعی را در همه زمانها در نظر نمیگیرد. با این حال، ما راههای جدیدی برای حل مسائل یاد گرفتهایم و در صورت نیاز میتوانیم با استفاده از بیانگر برنامهنویسی تابعی، مسائل را حل کنیم.
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-25 01:01:03