args* به ما این امکان رو میده که به جای تعداد ثابتی ورودی یه تابع بتونه تعداد متغیری ورودی بگیره. برای مثال تابع زیر رو در نظر بگیرید:
def my_sum(a, b): return a + b my_sum(2, 3) # 5
این تابع دو تا عدد رو باهم جمع میکنه و همیشه دو تا ورودی میگیره و اگه بیشتر یا کمتر ورودی بهش بدیم با خطا مواجه میشیم.
فرض کنید به جای دو عدد میخوایم چندتا عدد (که ممکنه در هر بار فراخوانی تابع تعدادشون فرق کنه) رو با هم جمع کنیم. یه راه اینه که تابعمون یه ورودی list بگیره و اعداد توی لیست رو با هم جمع کنه. برای مثال:
def sum_list(nums): sum = 0 for num in nums: sum += num return sum sum_list([2, 3]) # 5 sum_list([2, 3, 5, 8]) # 18
اما راه دیگه اینه که به جای قرار دادن عددهامون توی یه لیست، اونارو مستقیم و به شکل آرگومان به تابعمون بدیم:
def my_sum(*nums): sum = 0 for num in nums: sum += num return sum my_sum(2, 3) # 5 my_sum(2, 3, 5, 8) # 18
چه اتفاقی افتاد؟!
هر تابع میتونه یک ورودی بگیره که قبل از اسمش یه * قرار داره و میتونه هر اسمی داشته باشه مثل: args، argv و … و تمام آرگومانهای اضافی که به تابع داده میشه رو برای ما نگه میداره. (که جنسش از tuple هست).
بیاین یه مثال دیگه ببینیم:
def my_sum(a, *nums): sum = 0 for num in nums: sum += num return sum * a my_sum(10, 2, 3) # 50 my_sum(10, 2, 10, 2) # 140
اولین ورودی تابع بالا یه عدده که در مجموع تمام عددهای ورودی بعدی ضرب میشه. اولین ورودی تابع اجباریه، یعنی نمیتونیم هیچ ورودی به تابع ندیم. اما بقیهی ورودیها اختیاری هستن و به هر تعداد دلخواه میتونیم ورودی به تابع بدیم.
اما حالا فرض کنید که ما یه متغیر از جنس list داریم که تعدادی عدد توش ذخیره شده و میخوایم مجموع این اعداد را محاسبه کنیم. اگه اون متغیر را مستقیم به تابعمون بدیم درست کار نخواهد کرد، چون یه متغیر لیست یه دونه ورودی حساب میشه و تابع ما با لیست مثل یه عدد رفتار خواهد کرد! پس چاره چیست؟
چاره * است!
def my_sum(a, *nums): sum = 0 for num in nums: sum += num return sum * a lst1 = [1, 2, 3, 4] lst2 = [10, 11, 12, 13] my_sum(10, *lst1) # 100 my_sum(10, *lst2) # 460 my_sum(10, *lst1, *lst2) # 560
اگه زمان فراخوانی تابع، قبل از یه متغیر از نوع list یا tuple یه دونه ستاره (*) قرار بدیم باعث میشه عناصر داخل اون لیست یا تاپل به عنوان ورودیهای تابع در نظر گرفته بشن! و حتی میتونیم چند تا از لیست یا تاپلهای ستارهدار رو به ورودی تابع بدیم و همهی عناصر داخل اونها از طریق یه پارامتر شبیه به args* در داخل تابع قابل دسترسی خواهند بود.
kwargs** هم مشابه args* عمل میکنه با این تفاوت که آرگومانهای با کلمهکلیدی رو ذخیره میکنه.
مثال زیر را در نظر بگیرید:
def show_person_info(**kwargs): for key, value in kwargs.items(): print('{} = {}'.format(key, value)) show_person_info(name='Hamidreza', family='Mahdavipanah', age='22') # خروجی: # # family = Mahdavipanah # age = 22 # name = Hamidreza
تابع بالا تعداد دلخواهی از ورودیهای با اسم رو دریافت میکنه و دونه دونه هرکدومشونو همراه با اسم ورودی و مقدار داخلش چاپ میکنه.
نوع دادهی kwargs از جنس dictionary است.
kwargs** میتونه هر نام دیگهای داشته باشه، مهم ** داخل اسمشه.
kwargs** باید تو لیست پارامترهای تابع آخرین پارامتر باشه.
تبدیل دیکشنری به ورودیهای با کلمهکلیدی:
def show_person_info(**kwargs): for key, value in kwargs.items(): print('{} = {}'.format(key, value)) dct = { 'name': 'Hamidreza', 'family': 'Mahdavipanah', 'blog': 'mahdavipanah.com/blog', 'github': 'github.com/mahdavipanah' } show_person_info(**dct) # Output: # # name = Hamidreza # blog = mahdavipanah.com/blog # github = github.com/mahdavipanah # family = Mahdavipanah
پیادهسازی عملکردی شبیه به تابع join در رشتهها با استفاده از args*:
class String(str): def my_join(self, *args): return self.join(args) s = String('') # Python style: s.join(['Hello ', 'world', '!']) # My style: s.my_join('Hello ', 'World', '!') # Both return: 'Hello world!' # Join list of strings using my style of join l = ['Hello ', 'world', '!'] s.my_join(*l) # returns: 'Hello world!'
و اما یه چیز دیگه! تمام آرگونهایی که بعد از args* قرار میگیرن باید از نوع ورودیهای با اسم باشن. حالا اگه خواستیم تابعمون args* نگیره اما از یه جایی به بعد تمام ورودیهاش با اسم باشن باید چیکار کنیم؟
چاره یه علامت ستارهی خالیه:
def my_func(a, b, c, d, *, first_kw_arg, second_kw_arg=True): pass my_func(1, 2, 3, 4) # Error: missing 1 required keyword-only argument: 'first_kw_arg' my_func(1, 2, 3, first_kw_arg=4) # Works fine! my_func(1, 2, 3, first_kw_arg=4, second_kw_arg=False) # Works fine!
ممنون .خیلی مطلب مفید و کاملی بود
عالی بود