آموزش پایتون _ توابع و ماژول‌ها

در این سری از مقالات قصد دارم نکات کلیدی که در زبان پایتون وجود دارد را ارائه کنم. در این مجموعه تلاش شده اطلاعات مختصر و کوتاه باشند و بر مهمترین نکات مورد نیاز تمرکز شود. 

بعد از گذراندن این دوره شما قادر خواهید بود که از هر کتابخانه پایتون استفاده کنید و بسته‌های پایتونی که خودتان نوشته‌اید را اجرا کنید.

عناوین دوره:

  1. مقدمه
  2. نصب و راه‌اندازی
  3. متغیرها و انواع داده
  4. عبارت‌های کنترلی
  5. توابع و ماژول‌ها
  6. هویت اشیاء
  7. مدیریت خطا
  8. برنامه‌نویسی شی‌گرا
  9. بسته‌بندی و انتشار کد

استفاده مجدد از کد، یک بخش بسیار مهم در هر زبان برنامه‌نویسی است. از طرفی افزایش اندازه کد توسعه آنرا سخت‌تر می‌کند. برای موفقیت در یک پروژه برنامه‌نویسی بزرگ رعایت اصول عدم تکرار کد ضروری است. پیش از این با کمک حلقه‌ها به نوعی با روش انجام این کار آشنا شدیم. در این مقاله دو مبحث بسیار مهم دیگر توابع و ماژول‌ها را ارائه خواهیم کرد.

توابع

همانطور که گفته شد توابع تکرار را از کد شما حذف کرده، خوانایی را افزایش داده و فرایند دیباگ و خطایابی را برای شما آسانتر می‌کنند. برای تعریف توابع از کلیدواژه def استفاده می‌شود: 

def my_function():
  print(" This is the first function!")

پس از تعریف تابع تنها کافی است نام تابع خود را فراخوانی کنیم. شما پیش از این نیز با توابعی چون print، و len آشنا شدید.

لازم به ذکر است برای درج توضیح در برنامه‌های خود کافی است به ابتدای جملات خود یک # اضافه کنید. همچنین برای درج توضیح در چندین خط بصورت زیر عمل می‌کنیم:

# This is a single line comment

``` This is a
Multi-line Comment ```

آرگومان‌ها

همواره می‌توان برای تعمیم یک تابع آرگومان‌ها را به آن اضافه کرد. توجه داشته باشید درصورتیکه به آرگومان مقداری پیش فرض دهیم تعیین آن آرگومان اختیاری می‌شود.

def say_hello(my_value = "World"):
  print("Hello " + my_value)
  
  
# Calling function
say_hello()
>> Hello World

say_hello("Python")
>> Hello Python

شما برای هر تعداد از آرگومان‌های یک تابع می‌توانید مقدار پیش‌فرض در نظر بگیرید اما توجه داشته باشید زمانی که یک آرگومان مقدار پیش‌فرض داشته باشد تمامی آرگومان‌های بعد از آن باید مقدار پیش‌فرض داشته باشد. 

def greet(msg = "Good morning!", name):

>> SyntaxError: non-default argument follows default argument

توجه داشته باشید زمانیکه آرگومان‌ها را در فراخوانی یک تابع مقداردهی می‌کنید آرگومان‌ها به همان ترتیبی که در تابع تعریف شده است مقداردهی می‌شوند. اما در پایتون می‌توان با استفاده از نام آرگومان این ترتیب را نیز در نظر نگرفت، برای روشن‌تر شدن این موضوع به مثال زیر توجه کنید:

# 2 keyword arguments
greet(name = "Bruce",msg = "How do you do?")

# 2 keyword arguments (out of order)
greet(msg = "How do you do?",name = "Bruce") 

# 1 positional, 1 keyword argument
greet("Bruce", msg = "How do you do?")

همانند تعریف مقدار پیش‌فرض برای آرگومان‌ها اگر در فراخوانی تابع یک آرگومان به همراه نام آن مقداردهی شود، نباید آرگومان‌های بعد از آن بدون نام مقداردهی شوند

greet(name="Bruce","How do you do?")

>>  SyntaxError: non-keyword arg after keyword arg

args* و kwargs** در پایتون

علاوه بر موارد گفته شده در پایتون این امکان نیز فراهم شده است که تعداد متغیری از آرگومان‌ها را به یک تابع نسبت دهیم.

*args (Non-Keyword Arguments)
**kwargs (Keyword Arguments)

سینتکس ویژه args* در تعریف تابع این امکان را به ما می‌دهد تا ما بتوانیم یک لیست با طول متغیر و بدن کلیدواژه از آرگومان‌ها را به یک تابع نسبت دهیم

def myfunc(arg1, *arg2):
  print("first argument: " + arg1)
  for arg in arg2:
    print("next argument through *arg2: " + arg)


myfunc("Hello", "Welcome", "to", "My Python Journey")

>> Hello
>> Welcome
>> to
>> My Python Journey

سینتکس ویژه kwargs** همانند args* عمل می‌کند با این تفاوت که لیست متغیر آرگومان‌ها همراه با کلیدواژه می‌باشند.

def myfunc(**kwargs):
  for key, value in kwargs.items():
    print("%s == %s" %(key, value))
    
    
myfunc(a=1, b=2, c=3)

>> a == 1
>> b == 2
>> c == 3

استفاده همزمان از args* و kwargs** در تعریف آرگومان‌های یک تابع نیز بصورت زیر می‌باشد:

def myFun(*args,**kwargs): 
  print("args: ", args) 
  print("kwargs: ", kwargs) 
	
	
myFun('a','b','c', first="d",secound="e",third="f") 
>> args: ('a','b','c')
>> kwargs: {first: "d", secound: "e", third: "f"}

استفاده از args* و kwargs**  در مقداردهی یک تابع

def myFun(arg1, arg2, arg3): 
    print("arg1:", arg1) 
    print("arg2:", arg2) 
    print("arg3:", arg3) 
    

args = ("a", "b", "c") 
myFun(*args) 
  
kwargs = {"arg1" : "a", "arg2" : "b", "arg3" : "c"}
myFun(**kwargs)

تا به اینجا در مورد نحوه تعریف توابع و ورودی‌های آن در زبان پایتون صحبت شد، در ادامه با سینتکس پایتون برای خروجی گرفتن در توابع آشنا می‌شویم. برای این منظور از کلمه کلیدی return استفاده می‌کنیم.

def my_function(input):
  return input + 2 

همچنین این امکان نیز وجود دارد که با استفاده از tuples چندین خروجی از تابع بگیریم:

def my_function(x,y):
  return x*2, x + y
  

powerA2, sumAB = my_function(2, 3)

>> powerA2 = 4
>> sumAB = 5

 

تمرین شماره 1:

در این تمرین سعی می‌کنیم با توجه با آنچه تا بحال گفته شده تابع فیبوناچی را در پایتون بازنویسی کنیم.

اعداد فیبوناچی: در ریاضیات، سری فیبوناچی (Fibonacci) به دنباله‌ای از اعداد می‌گویند که به ‌صورت زیر تعریف می‌شود:

Image for post
Image for post

غیر از دو عدد اول، اعداد بعدی از جمعِ دو عددِ قبلیِ خود بدست می‌آیند. اولین اعداد این سری عبارت‌اند از:

۰, ۱, ۱, ۲, ۳, ۵, ۸, ۱۳, ۲۱, ۳۴, ۵۵, ...

Image for post
Image for post

قطعه کد فوق را می‌توان بصورت بازگشتی (تابع بازگشتی تابعی است که خود را فراخوانی کند) نیز بازنویسی کرد.

Image for post
Image for post

ماژول‌ها

شما هر قطعه کد پایتونی را می‌توانید به عنوان یک ماژول بسته‌بندی کنید. در جامعه پایتون ماژول‌های بسیار متعددی که هر یک برای هدف خاصی می‌باشد وجود دارد. ماژول قابلیت استفاده مجدد از کد و طراحی سازنده را تقویت می‌کند.

برای وارد کردن یک ماژول که اشیاء متعددی در آن تعریف شده در قطعه کد خود تنها کافی است بصورت زیر عمل کنید:

import my_module

برای دسترسی به یک شی از ماژول که در قطعه کد خود وارد کرده‌اید نیز داریم:

print(my_module.my_object)

همچنین اگر تنها به یک شی از ماژول درون کد خود نیاز دارید بصورت زیر تعریف می‌شود:

from my_module import my_object

print(my_object)

همچنین می‌توان تمام اشیاء را بصورت زیر در کد خود وارد کنید:

from my_module import *

این امکان نیز وجود دارد که برای هر شی که از ماژول وارد می‌کنید یک نام انتخاب کنید:

from my_module import my_object as my_var

print(my_var)

در ادامه نکاتی را در مورد توابع که در برنامه نویسی پایتون می‌تواند مورد استفاده قرار بگیرند، ارائه می‌کنیم.

lambda

در پایتون علاوه بر def که برای تعریف تابع استفاده می‌شود می‌توان از سینتکس lambda استفاده کرد. توابع تعریف شده با این روش در یک خط بیان می‌شوند و برای موارد ساده‌تر کاربرد دارد:

Syntax: variable = lambda arguments: expression
Image for post
Image for post

map & filter

این دو تابع کاربردی بر روی لیست‌ها عمل می‌کنند. تابع map یک تابع و یک لیست را به عنوان آرگومان می‌گیرد و یک لیست که بر روی هر کدام از عناصر آن تابع عمل کرده است بازمی‌گرداند:

Image for post
Image for post

تابع filter نیز به عنوان آرگومان یک تابع بولی (تابعی که یک مقدار true یا false را بازگرداند) و یک لیست می‌گیرد و با حذف مواردی از لیست که خروجی تابع false بوده، لیست را فیلتر می‌کند:

Image for post
Image for post

در مثال فوق از سینتکس lambda در تعریف تابع استفاده شده است.

توجه داشته باشید که خروجی تابع filter و map یک کلاس است لذا برای نمایش نتیجه از تابع list استفاده شده است. در مقالات بعدی حتما در مورد کلاس‌ها صحبت خواهیم کرد.

دو کلید میانبر بسیار کمکی در jupyter notebook، کلید Tab که هنگام نوشتن کد در صورت وجود، پیشنهادهایی را برای شما لیست می‌کند و ترکیب Shift + Tab که درصورت وجود داکیومنت راهنمای هر شی را نمایش می‌دهد، است. 

Image for post
Image for post

Generator

توابع مولد (Generator) همانند توابع معمولی در پایتون عمل می‌کنند با این تفاوت که بجای return از کلمه کلیدی yield استفاده می‌شود. Generatorها مانند لیست‌ها یا tuples، خاصیت تکرارپذیری دارند. برخلاف لیست‌ها، نمی‌توان آن‌ها را ایندکس کرد، اما هنوز هم می‌توانند از طریق حلقه‌ها تکرار شوند.

به خاطر این واقعیت که Generator در هر زمان تنها یک مورد را تولید می‌کند در نتیجه محدودیت حافظه لیست را ندارد. در حقیقت، آن‌ها می‌توانند نامحدود باشند!

Image for post
Image for post

Decorators

همانطور که پیش‌تر اشاره شد توابع در پایتون یک شی محسوب می‌شوند لذا خاصیت‌های یک شی را دارند. یعنی می‌توان آن‌ها در یک متغیر ذخیره کرد، یا به عنوان آرگومان به تابع دیگری ارجاع داد، درون تابع دیگری تعریف کرد و غیره. براساس همین خاصیت است که ابزارهای مانند Decorators وجود دارند. 

Decorators می‌توانند کارکرد توابع را بهبود بخشند به این ترتیب که شما می‌توانید یک تابع را درون تابع دیگر توسعه دهید.

def my_decorator(func):
	def inner():
		print("This is before function execution") 
 
        func() 
  
        print("This is after function execution")
    
    return inner

def my_function():
   	print("Hello World!")
   	
   	
decorated_function = my_decorator(my_function())
decorated_function()

>> output:
This is before function execution
Hello World!
This is after function execution

همچنین این قابلیت وجود دارد که با کاراکتر @ خاصیت یک decorator را به یک تابع نسبت داد:

def my_decorator(func):
	def inner():
		print("This is before function execution") 
 
        func() 
  
        print("This is after function execution")
    
    return inner

@my_decorator
def my_function():
   	print("Hello World!")
   	
   	
my_function()

>> output:
This is before function execution
Hello World!
This is after function execution

به مثال زیر توجه کنید:

Image for post
Image for post

یک تابع می‌تواند چندین decorator داشته باشد


در این مقاله در مورد دو مبحث مهم توابع و ماژول‌ها در پایتون صحبت شد در مقاله بعدی با مفهوم هویت اشیاء (Object Identity) آشنا خواهیم شد.