کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

ادامه مبحث توابع در پایتون

آموزش مباحث بیشتر درباره تعریف توابع در برنامه نویسی پایتون


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

مقادیر پیش فرض آرگومان ها در Python


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

    def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)

این تابع به چندین روش قابل فراخوانی است:

1-تنها ارائه آرگومان اجباری:

    ask_ok('Do you really want to quit?')

2-ارائه یکی از آرگومان های اختیاری:

    ask_ok('OK to overwrite the file?', 2)

3-حتی ارائه همه آرگومان ها :

    ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

). این مثال همچنین کلمه کلیدی in را معرفی می کند. این کلمه کلیدی بررسی می کند که آیا یک دنباله شامل یک مقدار خاص می باشد یا خیر. مقادیر پیش فرض در نقطه تعریف تابع، درون حوزه تعریف، ارزیابی می شوند، بنابراین کد زیر عدد 5 را چاپ می کند.

    i = 5

    def f(arg=i):
        print(arg)
    
    i = 6
    f()

توجه !

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

    def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

و خروجی چاپ شده:

    [1]
    [1, 2]
    [1, 2, 3]

اگر نمی خواهید که پیش فرض بین فراخوانی های پی در پی مشترک باشد، می توانید کد را به صورت زیر بنویسید:

    def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

آرگومان های کلمه کلیدی در Python


همچنین میتوان توابع را با استفاده از آرگومان های کلمه کلیدی به صورت kwarg=value فراخوانی کرد. برای مثال، تابع زیر:

    def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")

یک آرگومان مورد نیاز (voltage) و سه آرگومان اختیاری (state، action و type) را می پذیرد. این تابع را می توان به هر یک از روش های زیر فراخوانی کرد:

    parrot(1000)                                          # 1 positional argument
    parrot(voltage=1000)                                  # 1 keyword argument
    parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
    parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
    parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
    parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword

اما تمامی فراخوانی های زیر نامعتبر خواهند بود:

    parrot()                     # required argument missing
    parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
    parrot(110, voltage=220)     # duplicate value for the same argument
    parrot(actor='John Cleese')  # unknown keyword argument

در یک فراخوانی تابع، آرگومان های کلمه کلیدی باید از آرگومان های مکانی (positional arguments) پیروی کنند. تمامی آرگومان های کلمه کلیدی پاس داده شده، باید مطابق با یکی از آرگومان های پذیرفته شده توسط تابع باشند (برای مثال actor یک آرگومان معتبر برای تابع parrot نیست)، و ترتیب آنها مهم نیست. این مساله شامل آرگومان های غیر اختیاری نیز می شود (برای مثال parrot(voltage=1000) نیز معتبر است) . هیچ آرگومانی بیشتر از یک بار مقدار دریافت نمی کند. در اینجا مثالی وجود دارد که به دلیل همین محدودیت شکست می خورد.

    >> def function(a):
    ...     pass
    ...
    >>> function(0, a=0)
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: function() got multiple values for keyword argument 'a'

زمانی که یک پارامتر رسمی نهایی به صورت **name وجود دارد، یک دیکشنری شامل همه آرگومان های کلمه کلیدی به جز آنهایی که متناظر با یک پارامتر رسمی هستند، دریافت می کند.

ممکن است این با یک پارامتر رسمی به صورت *name (در بخش بعدی توضیح داده می شود) ترکیب شود که فراتر از لیست پارامتر رسمی، یک چندتایی (tuple) شامل آرگومان های مکانی دریافت می کند. (*name باید قبل از *name* رخ دهد.) برای مثال، اگر یک تابع را به صوت زیر تعریف کنیم:

    def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])

به صورت زیر میتواند فراخوانی شود:

    cheeseshop("Limburger", "It's very runny, sir.",
    "It's really very, VERY runny, sir.",
    shopkeeper="Michael Palin",
    client="John Cleese",
    sketch="Cheese Shop Sketch")

و البته خروجی زیر را چاپ می کند:

    -- Do you have any Limburger ?
    -- I'm sorry, we're all out of Limburger
    It's very runny, sir.
    It's really very, VERY runny, sir.
    ----------------------------------------
    shopkeeper : Michael Palin
    client : John Cleese
    sketch : Cheese Shop Sketch

توجه داشته باشید، تطابق ترتیب چاپ آرگومان های کلمه کلیدی با ترتیب ارائه آنها در فراخوانی تابع، تضمین می شود.

پارامترهای خاص در زبان Python


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

    def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
    -----------    ----------     ----------
      |             |                  |
      |        Positional or keyword   |
      |                                - Keyword only
       -- Positional only

که در آن / و * اختیاری هستند. در صورت استفاده، این نمادها بیان کننده نوع و نحوه پارامترهایی است که آرگومان ها توسط آنها به تابع پاس داده شده اند. فقط مکانی، مکانی-یا-کلمه کلیدی، فقط کلمه کلیدی. به پارامترهای کلمه کلیدی با عنوان پارامترهای نامگذاری شده (named parameters) نیز ارجاع داده می شود.

آرگومان های مکانی یا کلمه کلیدی در زبان Python


: اگر / و * در تعریف تابع حضور نداشته باشد، ممکن است آرگومان ها توسط مکان یا کلمه کلیدی به یک تابع پاس داده شوند.

>

پارامترهای فقط مکانی در زبان Python


اگر به جزییات بیشتر توجه کنیم، می بینیم که می شود برخی از پارامترهای خاص را به صورت فقط مکانی علامت گذاری کرد.

اگر پارامترها فقط مکانی باشد، ترتیب آنها مهم است، و پارامترها نمی توانند با کلمه کلیدی پاس داده شوند. پارامترهای فقط مکانی قبل از / (forward-slash) قرار میگیرد. از / برای جدا کردن منطقی پارامترهای فقط مکانی از سایر پارامترها استفاده می شود. اگر هیچ / در تعریف تابع وجود نداشته باشد، پس هیچ پارامتر فقط مکانی نیز وجود ندارد. پارامترهایی که پس از / می آیند می توانند مکانی-یا-کلمه کلیدی یا فقط کلمه کلیدی باشند.

آرگومان های فقط کلمه کلیدی در زبان Python


برای علامت گذاری پارامترها به عنوان فقط کلمه کلیدی، نمایش پارامترها باید توسط آرگومان کلمه کلیدی پاس داده شود. به این منظور یک * را قبل از اولین پارامتر فقط کلمه کلیدی در لیست آرگومان ها قرار دهید.

مثال های تابع در Python


: تعریف توابع در مثال های زیر را ببینید و به علامت های / و * خوب توجه کنید:

    >>> def standard_arg(arg):
    ...     print(arg)
    ...
    >>> def pos_only_arg(arg, /):
    ...     print(arg)
    ...
    >>> def kwd_only_arg(*, arg):
    ...     print(arg)
    ...
    >>> def combined_example(pos_only, /, standard, *, kwd_only):
    ...     print(pos_only, standard, kwd_only)

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

    >>> standard_arg(2)
    2
    
    >>> standard_arg(arg=2)
    2

در تابع دوم، pos_only_arg ، با توجه به وجود یک / در تعریف تابع، تابع فقط به استفاده از پارامترهای مکانی محدود شده است.

    >>> pos_only_arg(1)
    1
    
    >>> pos_only_arg(arg=1)
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: pos_only_arg() got an unexpected keyword argument 'arg'

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

    >>> kwd_only_arg(3)
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
    
    >>> kwd_only_arg(arg=3)
    3

و آخرین مورد از هر سه قرارداد فراخوانی در همان تعریف تابع استفاده می کند.

    >>> combined_example(1, 2, 3)
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: combined_example() takes 2 positional arguments but 3 were given
    
    >>> combined_example(1, 2, kwd_only=3)
    1 2 3
    
    >>> combined_example(1, standard=2, kwd_only=3)
    1 2 3
    
    >>> combined_example(pos_only=1, standard=2, kwd_only=3)
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: combined_example() got an unexpected keyword argument 'pos_only'

در انتها، این تعریف تابع که احتمال تضاد بین آرگومان مکانی name و **kwds که name را با عنوان کلید دارد، در نظر بگیرید:

    def foo(name, **kwds):
    return 'name' in kwds

از آنجایی که کلمه کلیدی 'name' همیشه به اولین پارامتر متصل است، احتمال هرگونه فراخوانی که True را باز گرداند وجود ندارد. برای مثال:

    >>> foo(1, **{'name': 2})
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: foo() got multiple values for argument 'name'
    >>>

اما در صورت استفاده از / (آرگومان های فقط مکانی)، این احتمال ممکن است رخ دهد، زیرا name را یک آرگومان مکانی و ‘name’ را به عنوان کلید در آرگومان های کلمه کلیدی مجاز می داند.

    def foo(name, /, **kwds):
    return 'name' in kwds
>>> foo(1, **{'name': 2})
True

به بیان دیگر، می توان از نام های پارامترهای فقط مکانی، بدون ابهام در **kwds استفاده کرد.

recap در زبان برنامه نویسی Python


موارد استفاده، تعیین کننده این است که در تعریف تابع از کدام پارامترها استفاده کنیم.

    def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):


به عنوان راهنما:

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

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

3- برای API از فقط مکانی استفاده کنید، تا در صورت تغییر نام پارامتر در آینده، از اعمال تغییرات در API جلوگیری شود.


لیست های آرگومان اختیاری در زبان برنامه نویسی Python


در انتها، کم استفاده ترین گزینه این است که مشخص کنید یک تابع می تواند با تعداد اختیاری از آرگومان ها فراخوانی شود. این آرگومان ها در یک چندتایی (tuple) قرار می گیرند

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

    def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))

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

    >>> def concat(*args, sep="/"):
    ...     return sep.join(args)
    ...
    >>> concat("earth", "mars", "venus")
    'earth/mars/venus'
    >>> concat("earth", "mars", "venus", sep=".")
    'earth.mars.venus'

باز کردن لیست های آرگومان در Python


: موقعیت برعکس آن زمانی رخ می دهد که آرگومان ها در شرایط فعلی درون یک لیست یا چندتایی (tuple) قرار دارند اما برای یک فراخوانی تابع که نیاز به آرگومان های مکانی مجزا دارد، باید تفکیک شوند.

برای مثال، تابع داخلی range() آرگومان های شروع و پایان مجزا می خواهد. اگر پارامترها به صورت مجزا در دسترس نباشند، فراخوانی تابع را با عملگر * بنویسید تا آرگومان ها را از درون لیست یا چندتایی خارج و تفکیک کند.

    >>> list(range(3, 6))            # normal call with separate arguments
    [3, 4, 5]
    >>> args = [3, 6]
    >>> list(range(*args))            # call with arguments unpacked from a list
    [3, 4, 5]

به همین ترتیب، دیکشنری ها نیز می توانند با استفاده از عملگر ** آرگومان های کلمه کلیدی را ارائه کنند.

    >>> def parrot(voltage, state='a stiff', action='voom'):
    ...     print("-- This parrot wouldn't", action, end=' ')
    ...     print("if you put", voltage, "volts through it.", end=' ')
    ...     print("E's", state, "!")
    ...
    >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
    >>> parrot(**d)
    -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

آموزش عبارات لامبدا (lambda) در Python


با استفاده از کلمه کلیدی lambda میتوان توابع بی نام کوچک ساخت. این تابع حاصل جمع دو آرگومان خود را باز می گرداند: lambda a, b: a+b. در هر جایی که اشیای تابع مورد نیاز باشند میتوان از توابع لامبدا استفاده کرد. از لحاظ نحوی آنها به یک عبارت محدود شده اند. از نظر معنایی، آنها تنها نگارش شیرینی برای تعریف توابع عادی هستند. همانند تعریف توابع تو در تو ، توابع لامبدا می توانند از حوزه در بر گیرنده، به متغیر ها ارجاع دهند:

    >>> def make_incrementor(n):
    ...     return lambda x: x + n
    ...
    >>> f = make_incrementor(42)
    >>> f(0)
    42
    >>> f(1)
    43

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

    >>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
    >>> pairs.sort(key=lambda pair: pair[1])
    >>> pairs
    [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

رشته های مستندات(documentation strings): در Python


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

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

اولین خط غیر خالی پس از اولین خط رشته، مشخص کننده مقدار فرو رفتگی برای کل رشته مستندات است. (از آنجایی که عموما خط اول، مجاور نقل قول شروع (opening quotes) رشته است، نمی توان از خط اول استفاده کرد، بنابراین فرو رفتگی در حروف رشته مشخص نخواهد بود.) سپس فضای خالی برابر با این فرو رفتگی از ابتدای همه خطوط رشته حذف می شود. خطوطی که کمتر فرورفته شده اند نباید رخ دهند، اما در صورت وقوع، تمام فضای خالی منتهی به آنها باید حذف شوند. پس از بسط tab ها (معمولا 8 فاصله) برابری فضاهای خالی باید بررسی شوند. در اینجا مثالی از docstring چند خطی داریم:

    >>> def my_function():
    ...     """Do nothing, but document it.
    ...
    ...     No, really, it doesn't do anything.
    ...     """
    ...     pass
    ...
    >>> print(my_function.__doc__)
    Do nothing, but document it.
    
        No, really, it doesn't do anything.

نماد گذاری های تابع در Python


نماد گذاری های تابع، اطلاعات فوق داده کاملا اختیاری درباره انواع استفاده شده، توسط توابع تعریف شده توسط کاربر است.

). نمادها در ویژگی __annotations__ تابع به عنوان یک دیکشنری ذخیره می شود و روی سایر بخش های تابع هیچ تاثیری ندارد. نمادهای پارامتر توسط یک دو نقطه (:) پس از نام پارامتر تعریف می شود، و به دنبال آن یک عبارت ارزیابی مقدار نماد ارائه می شود. نمادهای بازگشت داده شده توسط یک حرف -> تعریف می شود، و به دنبال آن یک عبارت بین لیست پارامترها و دو نقطه مشخص کننده انتهای عبارت def ارائه می شود. مثال زیر یک آرگومان مکانی، یک آرگومان کلمه کلیدی و نماد مقدار بازگشتی را دارد:

    >>> def f(ham: str, eggs: str = 'eggs') -> str:
    ...     print("Annotations:", f.__annotations__)
    ...     print("Arguments:", ham, eggs)
    ...     return ham + ' and ' + eggs
    ...
    >>> f('spam')
    Annotations: {'ham': , 'return': , 'eggs': }
    Arguments: spam eggs
    'spam and eggs'

1403/05/28 2966 808
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...