محدوده متغیرها و پارامترها
در این درس تفاوت متغیر محلی و سراسری را میفهمید، با global و ثابتها کار میکنید و پارامترهای پیشفرض و آرگومانهای کلیدی را به کار میبرید.
آنچه در این درس میآموزید
- تفاوت متغیر محلی و سراسری را تشخیص دهید و پیشبینی کنید
- از کلمه کلیدی global درست و کمیاب استفاده کنید
- پارامتر پیشفرض و آرگومان کلیدی را در تعریف و فراخوانی به کار ببرید
فهرست مطالب
تابع در درس قبل مثل یک کارگر خوب بود؛ اما یک راز را نگفتیم: تابع دنیای خودش را دارد. متغیری که داخل تابع میسازید، بیرون آن وجود ندارد و برعکس. فهمیدن این مرزها — بهعلاوه پذیرش هوشمندانه ورودیها — تفاوت تابعِ شکننده و تابعِ مطمئن است.
متغیر محلی؛ دنیای خصوصی تابع
متغیری که داخل تابع ساخته میشود محلی (Local) است: از لحظه تعریف تا پایان همان فراخوانی زندگی میکند و بعد میمیرد:
message = "outside"
def show():
message = "inside"
print(message)
show()
print(message)inside outside
دو متغیر مستقل ساخته شده است: یکی داخل تابع و یکی بیرونش. تخصیص داخل تابع، متغیر بیرونی را لمس نکرد؛ وقتی show تمام شد، متغیر محلیاش از بین رفت و print(message) بیرونی را دید. این ایزولهبودن ویژگی است، نه محدودیت: هر تابع میتواند بدون ترس از دستاندازی به بقیه برنامه، متغیرهای خودش را داشته باشد.
خواندن و نوشتن متغیر سراسری
متغیر بیرون همه توابع، سراسری (Global) است. خواندنش از داخل تابع آزاد است؛ مثالی که همه در برنامههای واقعی دیده میشود — ثابت پیکربندی:
TAX_RATE = 9 # tax percentage
def with_tax(price):
return price * (100 + TAX_RATE) / 100
print(f"{with_tax(2500000):,.0f} toman")2,725,000 toman
تابع TAX_RATE را فقط میخواند؛ نامی که محلی پیدا نشد، بیرون جستوجو میشود. اما نوشتن سراسری از داخل تابع، بدون اعلام، مجاز نیست: تخصیص counter = counter + 1 داخل تابع، متغیر محلی تازهای میسازد و خطای UnboundLocalError میدهد. اگر واقعاً لازم بود متغیر سراسری را عوض کنید، کلمه کلیدی global را اعلام میکنید:
counter = 0
def increase():
global counter
counter += 1
increase()
increase()
print(counter)2
پارامتر پیشفرض
تابع میتواند برای پارامترش مقدار پیشفرض بگذارد؛ آرگومانی که نیاید، پیشفرض استفاده میشود:
def order(tea, sugar=1, saffron=False):
label = f"Tea {tea}"
if sugar > 0:
label += f" with {sugar} sugar cubes"
if saffron:
label += " and saffron"
return label
print(order("Lahijan"))
print(order("Garmsar", sugar=0, saffron=True))Tea Lahijan with 1 sugar cubes Tea Garmsar and saffron
در فراخوانی اول، فقط چای مشخص شد؛ sugar پیشفرض ۱ گرفت و saffron پیشفرض False ماند. در فراخوانی دوم، سفارشدهنده هر دو را عوض کرد. پارامترهای پیشفرض API تابع را دوستانه میکنند: حالت رایج با کمترین تایپ انجام میشود و حالتهای خاص هم در دسترس میمانند.
آرگومان کلیدی؛ فراخوانی با نام
در فراخوانی دوم مثال قبل، آرگومانها با نامشان داده شدند: sugar=0. به این میگویند آرگومان کلیدی (Keyword Argument) و دو مزیت دارد: ترتیب مهم نیست و خواننده میفهمد هر مقدار مال کدام پارامتر است. برای دیدن خطر حالت مقابل، فراخوانی مکانی را روی همین تابع امتحان کنید:
print(order("Kashan", True))Tea Kashan with True sugar cubes
اینجا True مال کدام پارامتر است؟ بدون مراجعه به تعریف تابع، حدس زدن دشوار است؛ و اتفاق افتاده هم بیمعناست: True بهجای sugar نشسته و خودش در جمله چاپ شده. نسخه با نام صریح، هم خواناتر است و هم خطای ترتیب را از ریشه میبرد:
print(order("Kashan", saffron=True))Tea Kashan with 1 sugar cubes and saffron
قاعده عملی: آرگومانهای اجباری به شکل مکانی، بقیه با نام. ضمناً میتوانید پیشفرض و کلیدی را ترکیب کنید؛ آنچه نباید فراموش شود، آرگومانهای بدون پیشفرض هستند که همیشه باید داده شوند.
تمرینها
تمرین
تمرین ۱ — محاسبه تخفیف
تابعی به نام discount بنویسید که قیمت بگیرد و درصد تخفیف با پیشفرض ۱۰ داشته باشد و قیمت نهایی را برگرداند. آن را یکبار بدون درصد و یکبار با درصد ۲۰ برای قیمت ۵۰۰۰۰۰ صدا بزنید و هر دو نتیجه را چاپ کنید.
# Write your code hereنمایش راهحل
def discount(price, percent=10):
return price * (100 - percent) / 100
print(discount(500000))
print(discount(500000, 20))450000.0 400000.0
::: :::
خلاصه
- متغیر محلی فقط داخل تابع خودش زندگی میکند و با پایان فراخوانی از بین میرود.
- خواندن متغیر سراسری از داخل تابع آزاد است؛ نوشتنش نیاز به اعلام
globalدارد. - ثابتهای سراسری با حروف بزرگ مثل
TAX_RATEرایج و بیخطرند؛ متغیر سراسری تغییرپذیر نه. - پارامتر پیشفرض، فراخوانی حالت رایج را ساده میکند و آرگومان کلیدی، فراخوانی را خوانا و مستقل از ترتیب میکند.
- ساختار تغییرپذیر هرگز مقدار پیشفرض پارامتر نیست؛ جای آن
Noneبگذارید.
توابع میتوانند توابع دیگر را صدا بزنند؛ حتی میتوانند خودشان را صدا بزنند. در درس بعدی با بازگشتی، یکی از زیباترین و مرموزترین ایدههای برنامهنویسی، آشنا میشوید.