آموزش پایتون - محدودکننده‌های دسترسی

محدودکننده‌های دسترسی در پایتون برای محدود کردن دسترسی به اعضای کلاس (یعنی متغیرها و متدها) از خارج کلاس استفاده می‌شوند. سه نوع محدودکننده دسترسی وجود دارد: عمومی (public)، محافظت‌شده (protected) و خصوصی (private).

  • اعضای عمومی − اگر یکی از اعضای کلاس از هر نقطه‌ای در برنامه قابل دسترسی باشد، عمومی محسوب می‌شود.

  • اعضای محافظت‌شده − این اعضا از داخل خود کلاس و همچنین از طریق کلاس‌هایی که از آن کلاس ارث‌بری می‌کنند، قابل دسترسی هستند.

  • اعضای خصوصی − این اعضا فقط از داخل خود کلاس قابل دسترسی هستند.

معمولاً متدها به‌صورت عمومی تعریف می‌شوند و متغیرهای نمونه خصوصی هستند. این ترکیب از متغیرهای نمونه خصوصی و متدهای عمومی، پیاده‌سازی اصل کپسوله‌سازی (encapsulation) را تضمین می‌کند.

محدودکننده‌های دسترسی در پایتون

برخلاف C++ و Java، پایتون از کلمات کلیدی Public، Protected و Private برای مشخص کردن نوع محدودکننده‌های دسترسی استفاده نمی‌کند. به‌طور پیش‌فرض، تمام متغیرها و متدهای یک کلاس در پایتون عمومی هستند.

مثال

در اینجا کلاسی به نام Employee داریم که دارای دو متغیر نمونه به نام‌های name و age است. یک شیء از این کلاس، این دو ویژگی را دارد. ازآنجاکه این ویژگی‌ها عمومی هستند، می‌توان مستقیماً از خارج کلاس به آن‌ها دسترسی داشت.

class Employee:
   'Common base class for all employees'
   def __init__(self, name="Bhavana", age=24):
      self.name = name
      self.age = age

e1 = Employee()
e2 = Employee("Bharat", 25)

print ("Name: {}".format(e1.name))
print ("age: {}".format(e1.age))
print ("Name: {}".format(e2.name))
print ("age: {}".format(e2.age))

خروجی زیر تولید خواهد شد:

Name: Bhavana
age: 24
Name: Bharat
age: 25

پایتون محدودیتی برای دسترسی به هیچ‌یک از متغیرهای نمونه یا متدها اعمال نمی‌کند. بااین‌حال، در پایتون قراردادی وجود دارد که بر اساس آن، برای شبیه‌سازی رفتار محدودکننده‌های دسترسی محافظت‌شده و خصوصی، نام متغیر یا متد را با یک یا دو زیرخط (_) آغاز می‌کنند.

  • برای نشان دادن اینکه یک متغیر نمونه خصوصی است، نام آن را با دو زیرخط آغاز کنید (مانند "__age").
  • برای نشان دادن اینکه یک متغیر نمونه محافظت‌شده است، نام آن را با یک زیرخط آغاز کنید (مانند "_salary").

مثالی دیگر

بیایید کلاس Employee را تغییر دهیم. یک متغیر نمونه دیگر به نام salary اضافه کنید. با قرار دادن دو زیرخط و یک زیرخط در ابتدای نام متغیرهای age و salary، به‌ترتیب آن‌ها را خصوصی و محافظت‌شده کنید.

class Employee:
   def __init__(self, name, age, salary):
      self.name = name # public variable
      self.__age = age # private variable
      self._salary = salary # protected variable
   def displayEmployee(self):
      print ("Name : ", self.name, ", age: ", self.__age, ", salary: ", self._salary)

e1=Employee("Bhavana", 24, 10000)

print (e1.name)
print (e1._salary)
print (e1.__age)

هنگامی که این کد را اجرا کنید، خروجی زیر تولید خواهد شد:

Bhavana
10000
Traceback (most recent call last):
 File "C:\Users\user\example.py", line 14, in <module>
  print (e1.__age)
        ^^^^^^^^
AttributeError: 'Employee' object has no attribute '__age'

پایتون خطای AttributeError را نمایش می‌دهد، زیرا __age خصوصی است و خارج از کلاس در دسترس نیست.

تغییر نام (Name Mangling)

پایتون دسترسی به داده‌های خصوصی را مسدود نمی‌کند؛ بلکه رعایت این اصل را به مسئولیت برنامه‌نویس واگذار می‌کند که کدی ننویسد که از خارج کلاس به این داده‌ها دسترسی داشته باشد. بااین‌حال، همچنان می‌توانید با استفاده از تکنیک تغییر نام در پایتون، به اعضای خصوصی دسترسی پیدا کنید.

تغییر نام (Name Mangling) فرایندی است که در آن نام عضوی که با دو زیرخط آغاز می‌شود، به قالب object._class__variable تغییر می‌کند. در صورت نیاز، همچنان می‌توان از خارج کلاس به آن دسترسی داشت، اما بهتر است از این کار خودداری کنید.

در مثال ما، نام متغیر نمونه خصوصی "__name" با تغییر به قالب زیر دستخوش تغییر می‌شود:

obj._class__privatevar

بنابراین، برای دسترسی به مقدار متغیر نمونه "__age" در شیء "e1"، نام آن را به "e1._Employee__age" تغییر دهید.

دستور print() را در برنامه بالا به شکل زیر تغییر دهید:

print (e1._Employee__age)

اکنون مقدار 24، یعنی سن شیء e1، چاپ می‌شود.

شیء Property در پایتون

کتابخانه استاندارد پایتون دارای تابع داخلی property() است. این تابع یک شیء از نوع property برمی‌گرداند که به‌عنوان واسطی برای دسترسی به متغیرهای نمونه یک کلاس پایتون عمل می‌کند.

اصل کپسوله‌سازی در برنامه‌نویسی شیءگرا ایجاب می‌کند که دسترسی به متغیرهای نمونه محدود و خصوصی باشد. پایتون سازوکار کارآمدی برای این منظور ندارد. تابع property() راهکاری جایگزین ارائه می‌دهد.

تابع property() از متدهای دریافت‌کننده (getter)، تنظیم‌کننده (setter) و حذف‌کننده (delete) که در یک کلاس تعریف شده‌اند، برای ایجاد یک شیء property برای آن کلاس استفاده می‌کند.

نحو

property(fget=None, fset=None, fdel=None, doc=None)

پارامترها

  • fget − یک متد نمونه که مقدار یک متغیر نمونه را بازیابی می‌کند.

  • fset − یک متد نمونه که مقداری را به یک متغیر نمونه اختصاص می‌دهد.

  • fdel − یک متد نمونه که یک متغیر نمونه را حذف می‌کند.

  • fdoc − رشته توضیحی مربوط به ویژگی.

این تابع با استفاده از متدهای دریافت‌کننده و تنظیم‌کننده، شیء property را برمی‌گرداند.

متدهای دریافت‌کننده و تنظیم‌کننده (Getter و Setter)

متد دریافت‌کننده، مقدار یک متغیر نمونه را بازیابی می‌کند و معمولاً نام آن به شکل get_varname است. در مقابل، متد تنظیم‌کننده مقداری را به یک متغیر نمونه اختصاص می‌دهد و نام آن به شکل set_varname تعریف می‌شود.

مثال

بیایید متدهای دریافت‌کننده get_name() و get_age() و متدهای تنظیم‌کننده set_name() و set_age() را در کلاس Employee تعریف کنیم.

class Employee:
   def __init__(self, name, age):
      self.__name = name
      self.__age = age

   def get_name(self):
      return self.__name
   def get_age(self):
      return self.__age
   def set_name(self, name):
      self.__name = name
      return
   def set_age(self, age):
      self.__age=age

e1=Employee("Bhavana", 24)
print ("Name:", e1.get_name(), "age:", e1.get_age())
e1.set_name("Archana")
e1.set_age(21)
print ("Name:", e1.get_name(), "age:", e1.get_age())

خروجی زیر تولید خواهد شد:

Name: Bhavana age: 24
Name: Archana age: 21

متدهای دریافت‌کننده و تنظیم‌کننده می‌توانند مقدار متغیرهای نمونه را بازیابی یا تنظیم کنند. تابع property() از این متدها برای افزودن اشیای property به‌عنوان ویژگی‌های کلاس استفاده می‌کند.

ویژگی name به شکل زیر تعریف می‌شود:

name = property(get_name, set_name, "name")

به همین ترتیب، می‌توانید ویژگی age را اضافه کنید:

age = property(get_age, set_age, "age")

مزیت شیء property این است که می‌توانید از آن برای بازیابی مقدار متغیر نمونه مرتبط با آن و همچنین اختصاص مقدار جدید به آن استفاده کنید.

برای مثال،

print (e1.name) displays value of e1.__name
e1.name = "Archana" assigns value to e1.__age

مثال

برنامه کامل همراه با اشیای property و نحوه استفاده از آن‌ها در ادامه آمده است:

class Employee:
   def __init__(self, name, age):
      self.__name = name
      self.__age = age

   def get_name(self):
      return self.__name
   def get_age(self):
      return self.__age
   def set_name(self, name):
      self.__name = name
      return
   def set_age(self, age):
      self.__age=age
      return
   name = property(get_name, set_name, "name")
   age = property(get_age, set_age, "age")

e1=Employee("Bhavana", 24)
print ("Name:", e1.name, "age:", e1.age)

e1.name = "Archana"
e1.age = 23
print ("Name:", e1.name, "age:", e1.age)

خروجی زیر تولید خواهد شد:

Name: Bhavana age: 24
Name: Archana age: 23

پیشرفت مطالعه: وضعیت خوانده‌شدن این درس فقط در همین مرورگر ذخیره می‌شود؛ بدون نیاز به حساب کاربری.