انتقال تعداد دلخواهی نشان‌وند

گاهی از تعداد نشان‌وندهایی که یک تابع نیاز دارد، از پیش اطّلاع ندارید. خوشبختانه پایتون این امکان را می‌دهد که تابع تعداد دلخواهی نشان‌وند را هنگام فراخوانی دریافت کند.

برای مثال تابعی را در نظر بگیرید که پیتزا درست می‌کند. این تابع به تعداد مواد روی پیتزا نیاز دارد ولی شما از پیش نمی‌دانید که فرد چه تعدادی از این مواد را درخواست می‌کند. تابع مثال زیر یک پارامتر دارد، *toppings، امّا این پارامترها تمام نشان‌وندهایی را که در خط فراخوانی ارائه می‌شود، جمع‌آوری می‌کند:

1
2
3
4
5
6
def make_pizza(*toppings):
    """Print the list of toppings that have been requested."""
    print(toppings)

make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

علامت ستاره در نام پارامتر *toppings به پایتون می‌گوید که یک چندتایی به نام toppings درست کن و تمام مقدارهایی را که دریافت می‌شود درونِ آن قرار بده. خروجیِ تولیدشده با فراخوانی print() در بدنه‌ی تابع نشان می‌دهد که پایتون می‌تواند فراخوانیِ تابع را با یک یا سه مقدار مدیریّت کند و با فراخوانی‌های مختلف یک جور برخورد می‌کند. توجّه کنید که پایتون نشان‌وندها را در یک چندتایی قرار می‌دهد، حتّی اگر تابع تنها یک مقدار ورودی داشته باشد:

1
2
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')

اکنون می‌توانیم print() را با یک حلقه جایگزین کنیم که در مواد روی پیتزا می‌چرخد و پیتزایی را که سفارش داده شده توصیف می‌کند:

1
2
3
4
5
6
7
8
def make_pizza(*toppings):
    """Summarize the pizza we are about to make."""
    print("\nMaking a pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

تابع چه یک مقدارِ ورودی بگیرد چه سه مقدار، پاسخِ متناسبی می‌دهد:

1
2
3
4
5
6
7
Making a pizza with the following toppings:
- pepperoni

Making a pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese

این شکلِ دستوری صرف نظر از تعداد نشان‌وندهایی که تابع دریافت کرده، کار می‌کند.

ترکیب کردن نشان‌وندهای مکان‌دار و اختیاری

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

برای مثال اگر تابع به پارامتری برای اندازه‌ی پیتزا هم نیاز داشته باشد، باید آن را پیش از پارامتر *toppings بیاوریم:

1
2
3
4
5
6
7
8
def make_pizza(size, *toppings):
    """Summarize the pizza we are about to make."""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")

make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

پایتون در تعریفِ تابع، اوّلین مقداری را که دریافت می‌کند به پارامتر size نسبت می‌دهد. تمام مقدارهای دیگر که پس از آن می‌آیند در چندتایی toppings ذخیره می‌شوند. فراخوانی‌های این تابع ابتدا شامل نشان‌وندی برای اندازه‌ی پیتزا هستند و پس از هر تعداد مواد روی پیتزا که مورد نیاز باشد، به تابع ارسال می‌شود.

اکنون هر پیتزا یک اندازه و تعدادی مواد دلخواه دارد و هر بخش اطّلاعات در جای مناسب خود چاپ می‌شود که نمایانگر اندازه در ابتدا و سپس مواد روی پیتزاست:

1
2
3
4
5
6
7
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
نکته
شما اغلب پارامتری عمومی به نام *args می‌بینید که تمام نشان‌وندهای مکان‌دار مانند این را جمع‌آوری می‌کند.

به‌کارگیری نشان‌وندهای کلیدواژه‌ای اختیاری

گاهی می‌خواهید تعدادی نشان‌وند اختیاری را بپذیرید امّا از پیش نمی‌دانید که چه نوع اطّلاعاتی قرار است به تابع ارسال شود. در این مورد می‌توانید تابع‌هایی بنویسید که هر تعداد جفت کلید-مقدار را که هنگام فراخوانی ارائه شود، بپذیرد. یک نمونه هنگام ساختن نمایه‌ی کاربری است: شما می‌دانید که اطّلاعاتی در مورد یک کاربر دریافت می‌کنید امّا مطمئن نیستید آن‌ها از چه نوعی هستند. تابع build_profile() در مثال زیر همیشه نام و نام خانوادگی را دریافت می‌کند، امّا تعداد دلخواهی نشان‌وند کلیدواژه‌ای را هم می‌پذیرد:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def build_profile(first, last, **user_info):
    """Build a dictionary containing everything we know about a user."""
    user_info['first_name'] = first
    user_info['last_name'] = last
    return user_info

user_profile = build_profile('albert', 'einstein',
    location='princeton',
    field='physics')
print(user_profile)

تعریف build_profile() انتظار دارد که نام و نام خانوادگی وارد شود و سپس اجازه می‌دهد که کاربر هر تعداد جفتِ نام-مقدار که بخواهید وارد کند. دو علامت ستاره پشت **user_info به پایتون می‌گوید که یک دیکشنری خالی به نام user_info بسازد و تمام جفت نام-مقدارهایی که دریافت می‌کند در آن قرار دهد. داخل تابع می‌توانید همانند هر دیکشنری دیگری، به جفت‌های کلید-مقدار user_info دسترسی داشته باشید.

در بدنه‌ی build_profile() همواره نام و نام خانوادگی را به دیکشنری user_info اضافه می‌کنیم زیرا دو دانسته را از کاربر دریافت می‌کنیم (۱) امّا باید آن‌ها را در دیکشنری قرار دهیم. سپس دیکشنری user_info را به خط فراخوانی تابع برمی‌گردانیم.

تابع build_profile() را فراخوانی می‌کنیم، نام 'albert'، نام خانوادگی 'einstein' و دو جفت کلید-مقدارِ location='princeton' و field='physics' را به آن انتقال می‌دهیم. profile برگردانده شده را به user_profile نسبت می‌دهیم و آن را چاپ می‌کنیم:

1
2
{'location': 'princeton', 'field': 'physics',
 'first_name': 'albert', 'last_name': 'einstein'}

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

نکته
اغلب به پارامتری به نام **kwargs برمی‌خورید که برای جمع‌آوری نشان‌وندهای کلیدواژه‌ای نامشخّص استفاده می‌شود.

خودآزمایی

۸-۱۲. ساندویچ‌ها: تابعی بنویسید که لیستی از مواد دلخواه داخل ساندویچ را از فرد بگیرد. تابع باید یک پارامتر داشته باشد که تمام مواردی را که در فراخوانی تابع ارائه می‌شود جمع‌آوری کند و خلاصه‌ای از ساندویچی که سفارش داده می‌شود، چاپ کند. تابع را سه بار فرابخوانید و هر بار تعداد متفاوتی نشان‌وند استفاده کنید.

۸-۱۳. نمایه‌ی کاربری: از نسخه‌ای از user_profile.py در صفحه‌ی *** شروع کنید. با فراخوانی تابع build_profile() برای خود نمایه‌ای بسازید که شامل نام و نام خانوادگی و سه جفت کلید-مقدار باشد که شما را توصیف می‌کند.

۸-۱۴. خودروها: تابعی بنویسید که اطّلاعات پیرامون یک خودرو را در یک دیکشنری ذخیره می‌کند. تابع باید همیشه نام سازنده و مدل خودرو را دریافت کند. پس از آن باید تعداد دلخواهی نشان‌وند کلیدواژه‌ای دریافت کند. تابع را با اطّلاعات الزامی و دو جفت نام-مقدار دیگر فرابخوانید، مانند یک رنگ یا ویژگی سفارشی. تابع شما باید با فراخوانی زیر کار کند:

1
car = make_car('subaru', 'outback', color='blue', tow_package=True)

دیکشنری برگشتی از تابع را چاپ کنید تا مطمئن شوید که اطّلاعات به درستی ذخیره شده‌اند.