برای آشنایی با مبانی آرگومانهای تابع، به مفهوم تابع مراجعه کنید.
اسمهای پارامتر، مانند اسمهای متغیر، باید با یک حرف یا زیرخط شروع شوند و میتوانند شامل حرف، زیرخط یا عدد باشند. اسمهای پارامتر نباید فاصله یا علامت نگارشی داشته باشند.
آرگومانهای موقعیتی مقادیری هستند که به تابع داده میشوند، به همان ترتیبی که پارامترهای متصل به آنها. آرگومانهای موقعیتی را میتوان بهصورت اختیاری با استفاده از اسم پارامترشان هم ارسال کرد:
def concat(greeting, name):
return f"{greeting}{name}"
# Passing data to the function by position.
print(concat("Hello, ", "Lilly"))
#-> Hello, Lilly
# Passing data to the function using the parameter name.
print(concat(name="Glenn", greeting="Hello, "))
#-> Hello, Glenn
اولین فراخوانی concat آرگومانها را بر اساس موقعیت ارسال میکند.
دومین فراخوانی concat آرگومانها را بر اساس اسم ارسال میکند و این امکان را میدهد که موقعیت آنها تغییر کند.
توجه داشته باشید که آرگومانهای موقعیتی نمیتوانند بعد از آرگومانهایی بیایند که بر اساس اسم ارسال شدهاند (که به آنها آرگومانهای کلیدواژهای هم میگویند. نه اینکه با پارامترهای موقعیتی متغیر یا **kwargs اشتباه گرفته شوند).
این مجموعه از آرگومانها:
print(concat(greeting="Hello, ", "Gregor"))
منجر به این خطا میشود:
SyntaxError: positional argument follows keyword argument
الزامیکردن آرگومانهای صرفاً موقعیتی برای فراخوانی تابع، با استفاده از عملگر / در فهرست پارامترها امکانپذیر است:
# Parameters showing a position-only operator.
def concat(greeting, name, /):
return f"{greeting}{name}"
print(concat("Hello, ", "Ginnie"))
#-> Hello, Ginnie
# Call to the function using keyword arguments.
print(concat(name="Franklin", greeting="Hello, "))
Traceback (most recent call last):
print(concat(name="Franklin", greeting="Hello, "))
TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting, name'
آرگومانهای کلیدواژهای هنگام فراخوانی تابع از اسم پارامتر استفاده میکنند. میتوان بهصورت اختیاری با موقعیت هم به آنها اشاره کرد:
def concat(greeting, name):
return f"{greeting}{name}"
# Function call using parameter names as argument keywords.
print(concat(name="Eliza", greeting="Hello, "))
#-> Hello, Eliza
# Function call with positional data as arguments.
print(concat("Hello, ", "Tim"))
#-> Hello, Tim
الزامیکردن آرگومانهای صرفاً کلیدواژهای برای فراخوانی تابع، با استفاده از عملگر * در فهرست پارامترها امکانپذیر است:
# Function definition requiring keyword-only arguments.
def concat(*, greeting, name):
return f"{greeting}{name}"
# Keyword arguments can be in an arbitrary order.
print(concat(name="Kimmie", greeting="Hello, "))
#-> Hello, Kimmie
# Calling the function with positional data raises an error.
print(concat("Hello, ", "Coleen"))
Traceback (most recent call last):
print(concat("Hello, ", "Coleen"))
TypeError: concat() takes 0 positional arguments but 2 were given
مقادیر پیشفرض برای یک یا چند آرگومان را میتوان در فهرست پارامترها مشخص کرد. این کار باعث میشود در صورت نیاز بتوان تابع را با آرگومانهای کمتری فراخوانی کرد. مقادیر پیشفرض را میتوان با فراخوانی تابع همراه با یک مقدار آرگومان جدید بازنویسی کرد، تا مقدار پیشفرض نادیده گرفته شود:
# Function with default argument values.
def concat(greeting, name="you", punctuation="!"):
return f"{greeting}, {name}{punctuation}"
print(concat("Hello"))
#-> Hello, you!
# Overriding the default values
print(concat("Hello", name="Polly", punctuation="."))
#-> Hello, Polly.
اگر نه عملگر / و نه * در تعریف پارامترها استفاده نشوند، آرگومانها میتوانند موقعیتی یا کلیدواژهای باشند.
از طرف دیگر، آرگومانهای موقعیتی-یا-کلیدواژهای را میتوان بین پارامترهای صرفاً موقعیتی در سمت چپ و پارامترهای صرفاً کلیدواژهای در سمت راست قرار داد:
# Position-only argument followed by position-or-keyword, followed by keyword-only.
def concat(greeting, /, name, *, ending):
return f"{greeting}{name}{ending}"
print(concat("Hello, ", "Mark", ending="!"))
#-> Hello, Mark!
print(concat("Hello, ", name="Rachel", ending="!"))
#-> Hello, Rachel!
print(concat(greeting="Hello, ", name="JoJo", ending="!"))
Traceback (most recent call last):
print(concat(greeting="Hello, ", name="JoJo", ending="!"))
TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting'
*argsنمونهکدها اغلب از یک تعریف تابع چیزی شبیه به این استفاده میکنند:
def my_function(*args, **kwargs):
# code snipped
*args اسمی دوقسمتی است که نمایندهی یک tuple با تعداد نامعینی از آرگومانهای موقعیتی جداگانه است، که به آن variadic argument هم میگویند.
args اسمی است که به tuple آرگومانها داده شده، اما میتواند هر اسم معتبر دیگری در Python باشد، مانند my_args، arguments و غیره.
* عملگری است که گروه آرگومانهای جداگانه را به یک tuple تبدیل میکند.
اگر تا به حال یک tuple را باز کرده باشید، ممکن است * در *args برایتان گیجکننده به نظر برسد.
* در تعریف یک پارامتر، بهجای باز کردن یک tuple، یک یا چند آرگومان موقعیتی را به یک tuple تبدیل میکند.
میگوییم که عملگر * سربارگذاریشده است، چون در بافتهای مختلف رفتار متفاوتی دارد.
برای نمونه، * برای ضرب استفاده میشود، برای باز کردن استفاده میشود و برای تعریف تعداد دلخواهی از پارامترهای موقعیتی به کار میرود.
از آنجا که میتوان روی یک tuple پیمایش کرد، args را میتوان به هر تابع دیگری که یک مقدار قابلپیمایش میگیرد فرستاد.
با اینکه *args معمولاً در کنار **kwargs میآید، لازم نیست اینطور باشد:
def add(*args):
# args is passed to the sum function, which iterates over it.
return sum(args)
print(add(1, 2, 3))
#-> 6
اگر *args بعد از یک یا چند آرگومان موقعیتی بیاید، آنگاه *args همان چیزی خواهد بود که بعد از آرگومانهای موقعیتی باقی میماند:
def add(first, *args):
# first will be 1, leaving the values 2 and 3 in *args
return first + sum(args)
print(add(1, 2, 3))
#-> 6
اگر یک یا چند آرگومان پیشفرض بعد از *args تعریف شوند، آنها از مقادیر *args جدا هستند:
def add(first, *args, last=0):
return first + sum(args) + last
print(add(1, 2, 3))
#-> 6
print(add(1, 2, 3, last=4))
#-> 10
# This uses the unpacking operator * to separate the list elements into positional arguments.
# It does not have the same behavior as the * (packing) in *args.
print(add(*[1, 2, 3]))
#-> 6
توجه داشته باشید وقتی آرگومانی از قبل داخل یک iterable است (مانند یک tuple یا list)، لازم است قبل از اینکه به تابعی فرستاده شود که تعداد دلخواهی آرگومان جداگانه میگیرد، باز شود.
این کار با استفاده از * انجام میشود، که همان عملگر باز کردن است.
* در این بافت، ظرف را باز میکند و به عناصر جداگانهاش تجزیه میکند، که سپس به دست *args به یک tuple تبدیل میشوند.
جایی که تنها آرگومانهای موقعیتی وجود دارند، عمل باز کردن باید به همان تعداد آرگومانی منجر شود که پارامترهای صوری تعریف شدهاند.
اگر فهرستی که به add فرستاده میشود باز نشود، برنامه خطا میدهد:
def add(first, *args, last=0):
return first + sum(args) + last
print(add([1, 2, 3]))
Traceback (most recent call last):
print(add([1, 2, 3]))
return first + sum(args) + last
TypeError: can only concatenate list (not "int") to list
**kwargs**kwargs اسمی دوقسمتی است که نمایندهی تعداد نامعینی از آرگومانهای جفت کلید-مقدار جداگانه است.
kwargs اسم گروه آرگومانهاست و میتواند هر اسم دیگری باشد، مانند my_args، arguments و غیره.
** گروه آرگومانهای نامدار را به یک dictionary از جفتهای {argument name: argument value} تبدیل میکند.
از آنجا که میتوان روی یک dictionary پیمایش کرد، kwargs را میتوان به هر تابع دیگری که یک مقدار قابلپیمایش میگیرد فرستاد.
با اینکه **kwargs معمولاً در کنار *args میآید، لازم نیست اینطور باشد:
def add(**kwargs):
return sum(kwargs.values())
print(add(one=1, two=2, three=3))
#-> 6
توجه داشته باشید که متد dict.values() فراخوانی میشود تا روی values دیکشنری kwargs پیمایش شود.
هنگام پیمایش روی یک دیکشنری، بهصورت پیشفرض روی keys پیمایش میشود، بنابراین باید dict.values() را بهصراحت مشخص کرد:
def concat(**kwargs):
# Join concatenates the tuples from `kwargs.items()`
return " ".join((str(item) for item in kwargs.items()))
print(concat(one=1, two=2, three=3))
#-> ('one', 1) ('two', 2) ('three', 3)