تا

تابع در Python

{one: "۱ تمرین", other: "%{count} تمرین"}

درباره‌ی تابع

یک function بلوکی از کد سازمان‌یافته و قابل استفاده‌ی مجدد است که برای انجام کاری مشخص به کار می‌رود. Functions ماژولاریتی بهتری برای برنامه‌ی شما و میزان بالایی از استفاده‌ی مجدد از کد فراهم می‌کنند. Python نیز مانند سایر زبان‌های برنامه‌نویسی، توابع داخلی (print، map و غیره) دارد که به‌راحتی در دسترس‌اند. شما همچنین می‌توانید توابع خودتان را تعریف کنید. به این‌ها user-defined functions می‌گویند. توابع می‌توانند کار ساده‌ای مانند چاپ یک پیام در کنسول انجام دهند یا بسیار پیچیده باشند.

برای اجرای کد داخل یک تابع، باید تابع را فراخوانی کنید؛ این کار با نوشتن اسم تابع و سپس پرانتز [()] انجام می‌شود. داده‌ها، که به آن‌ها arguments می‌گویند، با قرار گرفتن داخل پرانتز به تابع ارسال می‌شوند. تعریف یک تابع می‌تواند صفر یا چند parameters داشته باشد. پارامترها تعیین می‌کنند که تابع چه آرگومان‌هایی را می‌پذیرد. یک پارامتر تعیین می‌کند چه نوعی از آرگومان باید ارسال شود. آرگومان همان مقدار واقعی است که هنگام فراخوانی تابع ارسال می‌شود. توابع بسته به آرگومان‌هایی که به پارامترها ارسال می‌شوند، می‌توانند کارهای مختلفی انجام دهند.

یک تابع همچنین می‌تواند با استفاده از کلیدواژه‌ی return مقداری را برگرداند. مقداری که تابع برمی‌گرداند، return value نامیده می‌شود. مقدار بازگشتی به فراخوان تابع برگردانده می‌شود.

ساخت

در پایتون، توابع با کلیدواژه‌ی def ساخته می‌شوند. پس از تعریف تابع، اسم تابع و پرانتز [()] می‌آید. داخل پرانتز، پارامترها با کاما از هم جدا می‌شوند. پس از پرانتز بسته، از دونقطه (:) برای جدا کردن امضای تابع از بدنه‌ی تابع استفاده می‌شود.

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

def function_name(parameter1, parameter2, ...):
    # function body
    return parameter1 + parameter2

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

def function_name():
    # function body
    pass

توجه کنید که تابع به بدنه نیاز دارد، حتی اگر بدنه هیچ کاری نکند؛ در غیر این صورت، تلاش برای اجرای برنامه خطای تورفتگی تولید می‌کند:

>>> def my_bodyless_func():
...      

File ~/temp.py:1
    
    ^
IndentationError: expected an indented block

فراخوانی یک تابع

برای فراخوانی یک تابع، از اسم تابع و سپس پرانتز [()] استفاده کنید. پارامترهایی که به تابع ارسال می‌شوند، داخل پرانتز و با کاما از هم جدا قرار می‌گیرند.

تابع زیر را در نظر بگیرید:

def greet():
    print("Hello")

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

>>> greet()
Hello

پارامترها و آرگومان‌هایشان

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

بیایید تابعی به اسم add تعریف کنیم که دو عدد را با هم جمع می‌کند:

def add(first, second):
    print(first + second)

پارامترهای first و second تعیین می‌کنند که تابع add چه آرگومان‌هایی را می‌پذیرد. (لازم به ذکر است که واژه‌های parameter و argument اغلب به‌جای هم به کار می‌روند، هرچند به‌طور نادقیق.) وقتی تابع فراخوانی می‌شود، آرگومان‌ها به تابع ارسال می‌شوند. باید برای هر دو پارامتر آرگومان ارسال کنیم، در غیر این صورت TypeError ایجاد می‌شود.

>>> add(2, 3)
5

# Function can be called multiple times, with different parameters
>>> add(4, 3)
7
>>> add(5, 6)
11

# Passing an incorrect number of parameters will raise a `TypeError`
>>> add(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add() missing 1 required positional argument: 'second'

>>> add(2, 3, 4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add() takes 2 positional arguments but 3 were given

مقدار بازگشتی

مقدار بازگشتی مقداری است که به فراخوان تابع برگردانده می‌شود. یک return value می‌تواند هر نوع داده‌ای باشد، از جمله توابع یا کلاس‌های دیگر. فراخوان تابع می‌تواند از آن برای انجام عملیات بیشتر استفاده کند. اگر تابعی صریحاً return value را تعریف نکند، مفسر Python مقدار None را برمی‌گرداند.

بیایید تابعی به اسم add تعریف کنیم:

def add(first, second):
    return first + second

می‌توانیم مقدار بازگشتی را در یک متغیر ذخیره کنیم و سپس آن را چاپ کنیم:

>>> result = add(2, 3)
>>> print(result)
5
# Type of result is `int`
>>> type(result)
<class 'int'>

# We can also perform operations on the return value
>>> result * 2
10

# A function without an explicit return value will return `None`
>>> def log(message):
    print(message)

# Hello is printed because of print(message), but return value is `None`
>>> return_value = log("Hello")
Hello
>>> return_value
None

استفاده از return بلافاصله از تابع خارج می‌شود و مقدار را به فراخوان برمی‌گرداند.

>>> def show(first, second):
    print(first)
    return first
    print(second)

# second never gets printed, because the function exits after the return statement
>>> show(1, 2)
1

ماژولاریتی

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

فرض کنید برنامه‌ای باید کارهای زیر را انجام دهد:

  • محاسبه‌ی مساحت یک دایره
  • محاسبه‌ی مساحت یک مستطیل
  • محاسبه‌ی مساحت یک مثلث

می‌توانیم برنامه را به بخش‌های کوچک‌تر تقسیم کنیم.

def circle_area(radius):
    return 3.14 * radius * radius

def rectangle_area(length, breadth):
    return length * breadth

def triangle_area(base, height):
    return 0.5 * base * height

حالا می‌توانیم توابع را به ترتیبی که می‌خواهیم فراخوانی کنیم.

>>> circle_area(2)
12.56
>>> triangle_area(2, 3)
3.0
>>> rectangle_area(2, 3)
6
>>> rectangle_area(1, 2) + circle_area(2) + triangle_area(1, 2)
15.56

حوزه‌ی متغیرها

اگر متغیری (یا اسمی) داخل یک تابع تعریف شود، فقط داخل حوزه‌ی تابع (یا فضای نام محلی) قابل دسترسی خواهد بود، حتی اگر متغیری با همان اسم بیرون از حوزه‌ی تابع وجود داشته باشد.

متغیرهایی که بیرون از تابع و در سطح ماژول تعریف می‌شوند، در فضای نام سراسری در نظر گرفته می‌شوند. متغیرهایی که بیرون از یک تابع اما داخل یک تابع یا کلاس دربرگیرنده تعریف می‌شوند، در فضای نام غیرمحلی قرار دارند.

Python هنگام اجرای برنامه، برای تعیین اسم متغیرها از LEGB Rule (Local، Enclosing، Global، Built-in) استفاده می‌کند:

۱. جست‌وجو در فضای نام محلی (یا تابع). ۲. اگر اسمی در فضای نام محلی پیدا نشد، جست‌وجو در فضای نام دربرگیرنده (یا غیرمحلی). ۳. اگر اسم در فضای نام غیرمحلی/دربرگیرنده پیدا نشد، جست‌وجو در فضای نام سراسری (سطح ماژول). ۴. اگر اسم در فضای نام سراسری پیدا نشد، جست‌وجو در فضای نام داخلی (برنامه یا سراسری پایتون).

اگر اسم همچنان نامشخص بماند، Python خطای NameError exception را ایجاد می‌کند.

# Global namespace.
general_favorite = "apples"


def alices_favorite():
   # Local namespace.  
   favorite = "cherries"
   
   # This works because Python will eventually find general_favorite in the global namespace.
   # Python will find 'print' in the built-in namespace.
   print(f'Alice has always liked {favorite}, but most people like {general_favorite}.')

   
def our_favorite_fruits():
    # Enclosing or nonlocal namespace.
    yours = "peaches"
    
    def my_favorite():
        # Local namespace.
        mine = "pears"
        
        # This works because Python will eventually find 'yours' in the enclosing/nonlocal namespace.
        print(f'My favorite is {mine}, but you like {yours} instead.')
        
        # This works because Python will eventually find 'general_favorite' in the global namespace.
        print(f'Everyone seems to like {general_favorite}')
    
    # This function is in the local namespace of the 'our_favorite_fruits' function.  
    my_favorite()

    
# This will raise NameError: name 'favorite' is not defined, because the variable favorite is local to alices_favorite.
print(favorite)

اگر بخواهیم اسم متغیری را بیرون از حوزه‌ی محلی تابع قابل دسترسی کنیم (یا متغیری را که بیرون از حوزه‌ی تابع تعریف شده تغییر دهیم)، باید از کلیدواژه‌های global یا nonlocal استفاده کنیم.

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

کلیدواژه‌ی nonlocal به Python علامت می‌دهد که متغیر را در فضای نام غیرمحلی یا دربرگیرنده جست‌وجو یا ایجاد کند. از آن زمانی استفاده می‌شود که تابعی داخل تابع یا کلاس دیگری تودرتو باشد و به متغیرها و حوزه‌ی تابع بیرونی نیاز داشته باشد.

توابع به عنوان اشیای درجه‌یک

در پایتون، توابع را می‌توان به متغیرها نسبت داد و به عنوان آرگومان به توابع دیگر فرستاد. می‌توان از آن‌ها به عنوان مقدار بازگشتی استفاده کرد. توابع را همچنین می‌توان در یک دنباله (list، tuple و غیره) یا به عنوان مقدار در یک dict قرار داد. توابع را هر جایی که هر شیء دیگری به کار می‌رود، می‌توان به کار برد. این به آن دلیل است که توابع اشیای درجه‌یک هستند. به همین دلیل، ویژگی‌های خاصی با خود دارند و حتی می‌توانند دریافت و تنظیم ویژگی‌های سفارشی خودشان را تعریف کنند.

# print is a function

# A function can be assigned to a variable.
>>> function_as_variable = print
>>> function_as_variable("Hello")
Hello
>>> type(fake_print)
<class 'builtin_function_or_method'>

# Functions can be passed as an argument to another function.
>>> def check_print(func):
    func("Hello")
>>> check_print(print)
Hello

# Function can be used as an item in a sequence.
>>> my_list = [print, "Hello"]
>>> my_list[0]("Hello")
Hello

# Functions can be used as a value in a dictionary.
>>> my_dict = {"key": print}
>>> my_dict["key"]("Hello")
Hello

# Functions can be returned from a function.
>>> def return_func():
    return print
>>> return_func()("Hello")
Hello

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

def outer():
    num = 10
    
    # This is a nested, or "inner" function.
    def inner():
        print(num)
    
    # Outer function calling inner function
    inner()

تابع داخلی می‌تواند به متغیر num که در تابع بیرونی تعریف شده دسترسی داشته باشد.

>>> outer()
10

ویژگی‌های خاص

توابع در پایتون ویژگی‌های خاصی دارند. برخی از آن‌ها عبارت‌اند از:

  • __name__: اسم تابع
  • __doc__: رشته‌ی مستندات تابع
  • __module__: ماژولی که تابع در آن تعریف شده
  • __globals__: دیکشنری متغیرهای سراسری در تابع
  • __code__: شیء کدی که دستورهای تابع را در خود دارد
>>> def add(first, second):
      return first + second

# Function name
>>> print.__name__
'print'
>>> len.__name__
'len'
>>> add.__name__
'add'

# Function documentation
>>> abs.__doc__
'Return the absolute value of the argument.'

# Module
>>> len.__module__
'builtins'
>>> add.__module__
'__main__'

فهرست کامل ویژگی‌های تابع را می‌توانید در Python DataModel ببینید.

ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود