Scope در پایتون چیست؟

در پایتون، Scope یا «محدوده دسترسی» مشخص می‌کند که یک متغیر در کدام قسمت از برنامه قابل استفاده است. یادگیری Scope یکی از مفاهیم مهم در کار با متغیرها و توابع پایتون است.

اگر بدانیم یک متغیر در چه محدوده‌ای ساخته شده است، بهتر می‌توانیم رفتار برنامه را درک کنیم و از خطاهای مربوط به متغیرها جلوگیری کنیم.

Scope در پایتون چیست؟

Scope محدوده‌ای از برنامه است که در آن می‌توانیم به یک متغیر دسترسی داشته باشیم.

برای مثال، متغیری که داخل یک تابع ساخته می‌شود معمولاً فقط در همان تابع قابل دسترسی است.

def greet():
    name = "Ali"
    print(name)

greet()

# print(name)  # خطا

در این مثال، متغیر name داخل تابع ساخته شده است؛ بنابراین یک متغیر محلی یا Local Variable محسوب می‌شود.

انواع Scope در پایتون

به صورت ساده، در پایتون با چند محدوده مهم روبه‌رو هستیم:

Scope توضیح
Local متغیری که داخل یک تابع ایجاد می‌شود.
Enclosing محدوده تابع بیرونی در توابع تو در تو.
Global متغیری که در سطح اصلی فایل تعریف شده است.
Built-in نام‌ها و توابع داخلی خود پایتون.

Local Scope چیست؟

وقتی متغیری داخل یک تابع تعریف شود، آن متغیر معمولاً دارای Local Scope است.

def calculate():
    price = 100
    tax = 10

    print(price + tax)

calculate()

در این مثال، متغیرهای price و tax فقط در محدوده تابع calculate() قابل استفاده هستند.

نکته: تعریف متغیر داخل تابع باعث می‌شود آن متغیر به صورت محلی در همان محدوده ایجاد شود.

Global Scope چیست؟

اگر یک متغیر خارج از توابع و در سطح اصلی فایل پایتون تعریف شود، معمولاً دارای Global Scope است.

language = "Python"

def show_language():
    print(language)

show_language()

print(language)

در این مثال، متغیر language در سطح اصلی برنامه تعریف شده و تابع می‌تواند مقدار آن را بخواند.

تفاوت Local و Global

ویژگی Local Global
محل تعریف داخل تابع خارج از تابع
محدوده دسترسی محدوده تابع سطح کلی برنامه
استفاده خارج از تابع معمولاً امکان‌پذیر نیست قابل دسترسی است

وقتی نام متغیرها یکسان باشد چه اتفاقی می‌افتد؟

ممکن است یک متغیر Global و یک متغیر Local نام یکسانی داشته باشند. در این حالت، داخل تابع متغیر محلی اولویت دارد.

name = "Ali"

def show_name():
    name = "Reza"
    print(name)

show_name()

print(name)

خروجی:

Reza
Ali

داخل تابع مقدار Reza استفاده شده است؛ اما خارج از تابع مقدار Global یعنی Ali باقی می‌ماند.

کلمه کلیدی global

اگر بخواهیم داخل یک تابع مقدار یک متغیر Global را تغییر دهیم، می‌توانیم از کلمه کلیدی global استفاده کنیم.

count = 0

def increase():
    global count
    count += 1

increase()
increase()

print(count)

خروجی:

2
نکته مهم: استفاده زیاد از متغیرهای Global می‌تواند خوانایی و نگهداری برنامه را سخت‌تر کند. در پروژه‌های واقعی بهتر است تا حد امکان طراحی برنامه را طوری انجام دهیم که وابستگی به Globalها کم باشد.

چرا بدون global نمی‌توانیم مقدار Global را تغییر دهیم؟

اگر داخل تابع برای یک نام مقدار جدیدی قرار دهیم، پایتون آن نام را به عنوان یک متغیر محلی در نظر می‌گیرد.

score = 10

def change_score():
    score = 20
    print(score)

change_score()

print(score)

خروجی:

20
10

متغیر داخل تابع یک متغیر Local جدید است و متغیر Global تغییر نکرده است.

Enclosing Scope چیست؟

وقتی یک تابع داخل تابع دیگری تعریف شود، تابع داخلی می‌تواند به متغیرهای تابع بیرونی دسترسی داشته باشد. این محدوده را می‌توان Enclosing Scope نامید.

def outer():

    message = "Hello"

    def inner():
        print(message)

    inner()

outer()

تابع inner() متغیر message را از تابع بیرونی دریافت می‌کند.

کلمه کلیدی nonlocal

اگر بخواهیم مقدار متغیر تابع بیرونی را از داخل تابع داخلی تغییر دهیم، می‌توانیم از nonlocal استفاده کنیم.

def outer():

    count = 0

    def inner():
        nonlocal count
        count += 1
        print(count)

    inner()
    inner()

outer()

خروجی:

1
2

Built-in Scope چیست؟

پایتون تعدادی نام و تابع داخلی دارد که در بسیاری از برنامه‌ها بدون تعریف مجدد قابل استفاده هستند.

print("Python")

numbers = [1, 2, 3]

print(len(numbers))
print(max(numbers))

توابعی مانند print()، len() و max() از امکانات داخلی پایتون هستند.

قانون LEGB در پایتون

پایتون برای پیدا کردن یک نام، محدوده‌ها را با ترتیب مشخصی بررسی می‌کند. این ترتیب با نام LEGB شناخته می‌شود.

L = Local
محدوده فعلی تابع

E = Enclosing
محدوده تابع بیرونی

G = Global
محدوده کلی فایل

B = Built-in
نام‌های داخلی پایتون

بنابراین وقتی پایتون با نامی مثل name روبه‌رو می‌شود، برای پیدا کردن آن ابتدا محدوده Local را بررسی می‌کند، سپس Enclosing، بعد Global و در نهایت Built-in.

یک مثال برای درک LEGB

name = "Global"

def outer():

    name = "Enclosing"

    def inner():

        name = "Local"

        print(name)

    inner()

outer()

چون متغیر name در محدوده Local وجود دارد، مقدار Local چاپ می‌شود.

اشتباه رایج در Scope

یکی از اشتباهات رایج این است که تصور کنیم متغیری که داخل یک تابع ساخته شده، در تمام برنامه قابل استفاده است.

def create_user():
    username = "admin"

create_user()

print(username)

این کد خطا ایجاد می‌کند، زیرا username در محدوده محلی تابع ساخته شده است.

Scope و پارامترهای تابع

پارامترهای یک تابع نیز در محدوده همان تابع قرار دارند.

def greet(name):
    message = "Hello " + name
    print(message)

greet("Ali")

در این مثال، هم name و هم message در محدوده تابع قرار دارند.

Scope و حلقه‌ها

برخلاف بعضی زبان‌های برنامه‌نویسی، در پایتون یک حلقه for به تنهایی Scope جدیدی ایجاد نمی‌کند.

for i in range(3):
    print(i)

print(i)

در این مثال، متغیر i بعد از پایان حلقه نیز در همان محدوده قابل دسترسی است.

Scope و شرط if

بلوک‌های شرطی مانند if نیز به تنهایی یک Local Scope جدید ایجاد نمی‌کنند.

if True:
    message = "Python"

print(message)

متغیر message در این مثال بعد از شرط نیز قابل دسترسی است.

چه زمانی از global استفاده کنیم؟

کلمه کلیدی global کاربرد مشخصی دارد، اما بهتر است بدون نیاز از آن استفاده نکنیم.

در برنامه‌های بزرگ، استفاده زیاد از وضعیت Global می‌تواند وابستگی بین قسمت‌های مختلف برنامه را بیشتر کند. معمولاً استفاده از پارامترهای تابع و برگرداندن مقدار با return ساختار قابل کنترل‌تری ایجاد می‌کند.

روش بهتر به جای Global Variable

در بسیاری از مواقع می‌توانیم مقدار را به تابع ارسال کنیم و نتیجه را با return دریافت کنیم.

def increase(number):
    return number + 1

score = 10

score = increase(score)

print(score)

این روش باعث می‌شود تابع ورودی و خروجی مشخصی داشته باشد.

تمرین عملی Scope

تمرین:

برنامه‌ای بنویسید که یک متغیر Global به نام counter داشته باشد.

سپس تابعی به نام increase() بسازید که مقدار counter را یک واحد افزایش دهد.

تابع را سه بار اجرا کنید و مقدار نهایی را چاپ کنید.

پاسخ تمرین

counter = 0

def increase():
    global counter
    counter += 1

increase()
increase()
increase()

print(counter)

خروجی:

3

جمع‌بندی Scope در پایتون

Scope مشخص می‌کند یک نام یا متغیر در چه محدوده‌ای قابل دسترسی است.

دو کلمه کلیدی مهم در این موضوع نیز global و nonlocal هستند.

درک قانون LEGB به شما کمک می‌کند بفهمید پایتون هنگام پیدا کردن یک متغیر چه محدوده‌هایی را بررسی می‌کند.

سؤالات متداول

Scope در پایتون چیست؟

Scope محدوده‌ای است که یک متغیر یا نام در آن قابل دسترسی است.

Local Scope چیست؟

محدوده‌ای است که معمولاً برای متغیرهای تعریف‌شده داخل یک تابع ایجاد می‌شود.

Global Scope چیست؟

محدوده سطح اصلی فایل است که متغیرهای تعریف‌شده خارج از توابع معمولاً در آن قرار می‌گیرند.

global در پایتون چه کاربردی دارد؟

با global می‌توان داخل یک تابع به نام Global اشاره کرد و مقدار آن را تغییر داد.

nonlocal چه کاربردی دارد؟

nonlocal برای اشاره به متغیری در محدوده تابع بیرونی در توابع تو در تو استفاده می‌شود.

مطالب مرتبط

آموزش متغیرها در پایتون آموزش توابع در پایتون آموزش برنامه‌نویسی شیءگرا در پایتون آموزش محیط مجازی در پایتون مسیر کامل آموزش پایتون