تابع map در پایتون چیست؟ آشنایی با متد آن و نکات
در زبان برنامهنویسی پایتون، تابع map یکی از ابزارهای قدرتمند و پرکاربرد برای کار با توابع و لیستها به شمار میرود. این تابع به شما اجازه میدهد تا یک تابع خاص را بر روی تمامی عناصر یک لیست یا هر نوع دیگری از قابلتکرارها اعمال کنید و نتایج را در قالب یک آبجکت map بازگردانید. این رویکرد نه تنها کد را خواناتر و کوتاهتر میکند، بلکه به بهبود کارایی برنامه نیز کمک میکند.
در این مقاله، ابتدا با مفهوم و عملکرد تابع map آشنا میشویم و سپس به نحوه استفاده از آن در موقعیتهای مختلف میپردازیم. همچنین نکات و ترفندهایی برای بهرهگیری بهتر از این تابع را بررسی خواهیم کرد. از جمله موضوعاتی که در این مقاله پوشش داده میشود، میتوان به مزایا و معایب استفاده از map، مقایسه آن با لیست کامپرهنشنها و نکات بهینهسازی اشاره کرد. هدف ما ارائه یک راهنمای جامع برای درک و استفاده موثر از تابع map در پایتون است، تا بتوانید کدهای تمیزتر و بهینهتری بنویسید.
کدنویسی به سبک تابعی در پایتون
در برنامهنویسی تابعی، محاسبات با ترکیب توابعی که ورودی میگیرند و یک یا چند نتیجه مشخص برمیگردانند، انجام میشود. این توابع، ورودیهای خود را تغییر نمیدهند و حالت برنامه را تغییر نمیدهند. فقط نتیجه یک محاسبه را ارائه میدهند. این نوع توابع به عنوان توابع خالص شناخته میشوند.
برنامههایی که به سبک تابعی نوشته میشوند، از چند جهت آسانتر هستند:
- توسعه دادن: چون هر تابع را میتوانید جداگانه بنویسید و استفاده کنید.
- دیباگ و تست کردن: چون میتوانید توابع را جداگانه تست و دیباگ کنید بدون اینکه نیازی به بررسی کل برنامه داشته باشید.
- فهمیدن: چون نیازی به مدیریت تغییرات حالت در سراسر برنامه ندارید.
در برنامهنویسی تابعی، از لیستها، آرایهها و دیگر iterableها برای نمایش دادهها استفاده میشود و مجموعهای از توابع بر روی این دادهها عملیات انجام میدهند و آنها را تغییر میدهند. سه تکنیک رایج برای پردازش دادهها به سبک تابعی وجود دارد:
- Map (نگاشت): اعمال یک تابع تبدیلی به یک iterable برای تولید یک iterable جدید. هر آیتم در iterable جدید با اعمال تابع بر روی آیتمهای iterable اصلی تولید میشود.
- Filter (فیلتر کردن): اعمال یک تابع بولی به یک iterable برای تولید یک iterable جدید. آیتمهای جدید شامل مواردی هستند که تابع بولی برای آنها مقدار true برگرداند.
- Reduce (کاهش): اعمال یک تابع کاهشی به یک iterable برای تولید یک مقدار نهایی.
در سال 1993، جامعه پایتون درخواست ویژگیهای برنامهنویسی تابعی داشتند مانند توابع ناشناس، map، filter و reduce. این ویژگیها به لطف مشارکت اعضای جامعه به پایتون اضافه شدند و اکنون جزء اصلی برنامهنویسی تابعی در پایتون هستند.
در این آموزش، شما با یکی از این ویژگیها، یعنی تابع ()map، آشنا خواهید شد. همچنین خواهید آموخت که چگونه از list comprehensions و generator expressions برای دستیابی به قابلیتهای مشابه ()map به روشی خوانا و پایتونیک استفاده کنید.
شروع به کار با ()map در پایتون گاهی اوقات ممکن است نیاز داشته باشید که یک عملیات مشابه را روی تمام آیتمهای یک iterable ورودی انجام دهید تا یک iterable جدید بسازید. روش سریع و معمول برای این کار استفاده از یک حلقه for در پایتون است. اما میتوانید این مسئله را بدون استفاده از یک حلقه صریح با استفاده از تابع ()map نیز حل کنید.
در بخشهای زیر، شما یاد میگیرید که چگونه ()map کار میکند و چگونه میتوانید از آن برای پردازش و تغییر iterables بدون استفاده از حلقه استفاده کنید.
درک ()map
تابع ()map روی آیتمهای یک iterable (یا چندین iterable) ورودی حلقه میزند و یک iterator بازمیگرداند که نتیجه اعمال یک تابع تبدیلی به هر آیتم در iterable ورودی اصلی است.
طبق مستندات پایتون، ()map یک شیء تابع و یک iterable یا چندین iterable را به عنوان آرگومان میگیرد و یک iterator بازمیگرداند که آیتمهای تغییر یافته را بر حسب نیاز تولید میکند. امضای تابع به این صورت تعریف شده است: ()map تابع را به هر آیتم در iterable اعمال میکند و یک iterator جدید بازمیگرداند که آیتمهای تغییر یافته را به صورت تقاضا تولید میکند. تابع میتواند هر تابع پایتونی باشد که تعداد آرگومانهای برابر با تعداد iterables شما به ()map پاس دادهاید، میگیرد.
اولین آرگومان ()map یک تابع تبدیلی است. به عبارت دیگر، این تابعی است که هر آیتم اصلی را به یک آیتم جدید (تغییر یافته) تبدیل میکند. اگرچه مستندات پایتون این آرگومان را function مینامند، اما میتواند هر callable پایتونی باشد. این شامل توابع داخلی، کلاسها، متدها، توابع lambda و توابع تعریف شده توسط کاربر میشود.
عملیاتی که ()map انجام میدهد معمولاً به عنوان mapping شناخته میشود زیرا هر آیتم در یک iterable ورودی را به یک آیتم جدید در یک iterable خروجی نگاشت میکند. برای انجام این کار، ()map یک تابع تبدیلی را به تمام آیتمهای iterable ورودی اعمال میکند.
مثال کاربردی
فرض کنید شما نیاز دارید یک لیست از مقادیر عددی بگیرید و آن را به یک لیست که حاوی مربع هر عدد در لیست اصلی است تبدیل کنید. در این حالت، میتوانید از یک حلقه for استفاده کنید و چیزی شبیه به این کد بنویسید:
numbers = [1, 2, 3, 4, 5]
squared = []
for num in numbers:
squared.append(num ** 2)
print(squared)
وقتی این حلقه را روی لیست numbers اجرا میکنید، یک لیست از مقادیر مربعشده دریافت میکنید. حلقه for روی لیست numbers میچرخد و عملیات توان را روی هر مقدار اعمال میکند و در نهایت مقادیر نتیجه را در لیست squared ذخیره میکند.
شما میتوانید همین نتیجه را بدون استفاده از یک حلقه صریح با استفاده از ()map به دست آورید:
def square(num):
return num ** 2
numbers = [1, 2, 3, 4, 5]
squared = list(map(square, numbers))
print(squared)
تابع ()square یک تابع تبدیلی است که یک عدد را به مقدار مربعشده آن نگاشت میکند. فراخوانی ()map تابع ()square را به همه مقادیر در لیست numbers اعمال میکند و یک iterator بازمیگرداند که مقادیر مربعشده را تولید میکند. سپس با استفاده از ()list روی ()map یک شیء لیست حاوی مقادیر مربعشده ایجاد میکنید.
حتما دانلود کنید: فیلم های صفر تا صد پایتون
مزایای استفاده از ()map
استفاده از map() چند مزیت دارد:
- کارایی بالاتر: ()map در C نوشته شده و بهینهسازی شده است، بنابراین حلقه داخلی آن میتواند کارآمدتر از یک حلقه for معمولی در پایتون باشد.
- مصرف حافظه کمتر: با استفاده از یک حلقه for، شما نیاز دارید که کل لیست را در حافظه سیستم ذخیره کنید. اما با ()map، آیتمها بر حسب نیاز تولید میشوند و در هر لحظه تنها یک آیتم در حافظه سیستم قرار دارد.
مثال دیگر
فرض کنید نیاز دارید که تمام آیتمهای یک لیست را از رشته به عدد صحیح تبدیل کنید. برای این کار، میتوانید از ()map به همراه تابع ()int استفاده کنید:
str_nums = ["1", "2", "3", "4", "5"]
int_nums = list(map(int, str_nums))
print(int_nums)
تابع ()map تابع ()int را به هر مقدار در لیست str_nums اعمال میکند. از آنجایی که ()map یک iterator بازمیگرداند (یک شیء map) نیاز است که ()list را فراخوانی کنید تا بتوانید iterator را مصرف کرده و آن را به یک شیء لیست تبدیل کنید. توجه داشته باشید که در این فرآیند، لیست اصلی تغییر نمیکند.
استفاده از `()map` با انواع مختلف توابع
شما میتوانید از هر نوع فراخوان قابل استفاده در پایتون با `()map` استفاده کنید. تنها شرط این است که فراخوان بتواند یک آرگومان بگیرد و یک مقدار مشخص و مفید بازگرداند. به عنوان مثال، میتوانید از کلاسها، نمونههایی که متد خاصی به نام `()__call__` پیادهسازی کردهاند، متدهای نمونه، متدهای کلاس، متدهای استاتیک و توابع استفاده کنید.
برخی از توابع داخلی وجود دارند که میتوانید با `()map` استفاده کنید. به مثالهای زیر توجه کنید:
>>> numbers = [-2, -1, 0, 1, 2]
>>> abs_values = list(map(abs, numbers))
>>> abs_values
[2, 1, 0, 1, 2]
>>> list(map(float, numbers))
[-2.0, -1.0, 0.0, 1.0, 2.0]
>>> words = ["Welcome", "to", "Real", "Python"]
>>> list(map(len, words))
[7, 2, 4, 6]
شما میتوانید هر تابع داخلی را با `()map` استفاده کنید، به شرطی که تابع یک آرگومان بگیرد و یک مقدار بازگرداند.
دانلود کنید: ۴ جزوه عالی pdf آموزش پایتون
یک الگوی رایج که هنگام استفاده از `()map` مشاهده خواهید کرد، استفاده از تابع `lambda` به عنوان اولین آرگومان است. توابع `lambda` زمانی که نیاز دارید یک تابع مبتنی بر بیان به `()map` بدهید، بسیار مفید هستند. به عنوان مثال، میتوانید مثال مقدارهای مربع را با استفاده از تابع `lambda` به این شکل پیادهسازی کنید:
>>> numbers = [1, 2, 3, 4, 5]
>>> squared = map(lambda num: num ** 2, numbers)
>>> list(squared)
[1, 4, 9, 16, 25]
توابع `lambda` زمانی که صحبت از استفاده از `()map` میشود، بسیار مفید هستند. آنها میتوانند به عنوان اولین آرگومان برای `()map` عمل کنند. شما میتوانید از توابع `lambda` همراه با `()map` برای پردازش و تبدیل سریع لیستهای قابل تکرار خود استفاده کنید.
پردازش چندین لیست قابل تکرار ورودی با `()map`
اگر چندین لیست قابل تکرار را به `()map` بدهید، تابع تبدیل باید به تعداد همان لیستهای ورودی آرگومان بپذیرد. هر بار اجرای `()map` یک مقدار از هر لیست به عنوان آرگومان به تابع داده میشود. تکرار زمانی متوقف میشود که کوتاهترین لیست به پایان برسد.
به مثال زیر که از تابع `()pow` استفاده میکند توجه کنید:
>>> first_it = [1, 2, 3]
>>> second_it = [4, 5, 6, 7]
>>> list(map(pow, first_it, second_it))
[1, 32, 729]
تابع `()pow` دو آرگومان x و y میگیرد و x به توان y را بازمیگرداند. در اولین تکرار، x برابر 1، y برابر 4 و نتیجه برابر 1 خواهد بود. در دومین تکرار، x برابر 2، y برابر 5 و نتیجه برابر 32 و همینطور ادامه دارد. لیست نهایی تنها به اندازه کوتاهترین لیست است که در این مورد `first_it` است.
آموزش کامل هوش مصنوعی: آموزش هوش مصنوعی از صفر تا صد با 14 درس+ جزوه
این تکنیک به شما اجازه میدهد دو یا چند لیست قابل تکرار از مقادیر عددی را با استفاده از انواع مختلف عملیات ریاضی ترکیب کنید. در اینجا چند مثال که از توابع `lambda` برای انجام عملیات ریاضی مختلف بر روی چندین لیست ورودی استفاده میکند آورده شده است:
>>> list(map(lambda x, y: x - y, [2, 4, 6], [1, 3, 5]))
[1, 1, 1]
>>> list(map(lambda x, y, z: x + y + z, [2, 4], [1, 3], [7, 8]))
[10, 15]
در مثال اول، شما از عمل تفریق برای ترکیب دو لیست از سه آیتم استفاده میکنید. در مثال دوم، مقادیر سه لیست را با هم جمع میکنید.
مقایسه تابع map با لیست کامپرهنشنها:
خوانایی و صراحت:
- map: استفاده از تابع map معمولاً نیازمند تعریف یک تابع جداگانه یا استفاده از توابع ناشناس مانند lambda است. این میتواند برای افراد ناآشنا با این سبک برنامهنویسی کمی گیجکننده باشد.
- لیست کامپرهنشنها: لیست کامپرهنشنها خوانایی بهتری دارند و بهراحتی میتوانند عملیات تکرار و تغییر را در یک خط کوتاه و مستقیم بیان کنند. این ویژگی آنها را برای بسیاری از برنامهنویسان قابلفهمتر میکند.
کارایی:
- map: تابع map به طور معمول کمی سریعتر از لیست کامپرهنشنها است، چرا که از توابع کامپایل شده C در پسزمینه استفاده میکند. این تفاوت در کارایی معمولاً در پردازشهای بزرگتر مشهودتر است.
- لیست کامپرهنشنها: اگرچه لیست کامپرهنشنها ممکن است کمی کندتر باشند، اما به دلیل خوانایی بهتر معمولاً در برنامههایی که نیاز به اجرای کد در مقیاس بزرگ ندارند، ترجیح داده میشوند.
نوع بازگشتی:
- map: تابع map یک آبجکت map بازمیگرداند که قابل تکرار (iterable) است و باید برای دسترسی به عناصر آن، به نوع دیگری مانند لیست یا تاپل تبدیل شود.
- لیست کامپرهنشنها: لیست کامپرهنشنها بهطور مستقیم یک لیست بازمیگردانند که دسترسی به عناصر آن بلافاصله امکانپذیر است.
تمرین های برنامه نویسی پایتون+ مثال برنامه نویسی پایتون
نکات بهینهسازی:
- انتخاب ابزار مناسب: برای بهبود کارایی و خوانایی کد، بهتر است که در مواقع نیاز به اعمال یک تابع بر روی تمامی عناصر یک لیست و بازگرداندن نتیجه به صورت یک لیست جدید، از لیست کامپرهنشنها استفاده کنید. اما در شرایطی که به یک تکرارگر (iterator) نیاز دارید و نیازی به داشتن یک لیست کامل نیست، استفاده از تابع map میتواند بهینهتر باشد.
- استفاده از توابع از پیش تعریف شده: به جای استفاده از توابع ناشناس (lambda)، میتوان از توابع از پیش تعریف شده یا ماژولهای کتابخانهای استفاده کرد. این کار علاوه بر بهبود خوانایی کد، ممکن است منجر به بهینهسازی کارایی شود.
- استفاده از filter: در شرایطی که نیاز به اعمال یک شرط خاص بر روی عناصر لیست دارید، ترکیب map با filter میتواند مفید باشد. filter نیز مانند map یک تکرارگر بازمیگرداند و میتواند عناصر لیست را بر اساس یک تابع شرطی، فیلتر کند.
- استفاده از generator expression: اگر به یک لیست کامل نیاز ندارید و فقط به یک تکرارگر سبکتر و بهینهتر نیاز دارید، استفاده از generator expression به جای لیست کامپرهنشنها میتواند موثر باشد. generator expression ها منابع کمتری مصرف میکنند و در محیطهایی با محدودیت حافظه مفید هستند.
دوتابع کاربردی دیگه: Functools در پایتون و تابع def در پایتون
با در نظر گرفتن این نکات و مقایسهها، انتخاب صحیح بین map و لیست کامپرهنشنها میتواند به بهبود کیفیت کد و عملکرد برنامه کمک کند.
در این آموزش، روشهای مختلف استفاده از تابع ()map در پایتون را یاد گرفتیم. حالا میتوانید از ()map با تابع خود، تابع lambda و با هر تابع داخلی دیگری استفاده کنید. همچنین میتوانید ()map را با توابعی که نیاز به چندین لیست قابل تکرار دارند، پیادهسازی کنید. امیدواریم که این مطلب برای شما مفید بوده باشد.