Skip to content

12. کلاس‌ها و اشیاء

یک کلاس قالبی است که اشیاء از روی آن ایجاد می‌شوند. به یک شیء، نمونهٔ یک کلاس گفته می‌شود.

Image

توجه: پوشه [shared] در داخل پوشه [Sources Root] پروژه قرار داده شده است.

12.1. اسکریپت [classes_01]: کلاس آبجکت

اسکریپت [classes_01] یک کاربرد منسوخ از کلاس‌ها را نشان می‌دهد:


#یک کلاس
class Objet(object):
    """une classe Objet vide"""


# هر متغیری از نوع [Objet] ممکن است طبق طراحی دارای ویژگی‌ها باشد
obj1 = Objet()
obj1.attr1 = "un"
obj1.attr2 = 100
# شیء را نمایش می‌دهد
print(f"objet1=[{obj1}, {type(obj1)},{id(obj1)},{obj1.attr1},{obj1.attr2}]")
# شیء را تغییر می‌دهد
obj1.attr2 += 100
# شیء را نمایش می‌دهد
print(f"objet1=[{obj1.attr1},{obj1.attr2}]")
#مرجع obj1 را به obj2 اختصاص می‌دهد
obj2 = obj1
# شیء اشاره شده توسط obj2 را تغییر می‌دهد
obj2.attr2 = 0
#هر دو شیء را نمایش می‌دهد – obj1 اکنون به یک شیء تغییر یافته اشاره می‌کند
print(f"objet1=[{obj1.attr1},{obj1.attr2}]")
print(f"objet2=[{obj2.attr1},{obj2.attr2}]")
#obj1 و obj2 به یک شی اشاره می‌کنند
print(f"objet1=[{obj1}, {id(obj1)},{obj1.attr1},{obj1.attr2}]")
print(f"objet2=[{obj2}, {id(obj2)},{obj2.attr1},{obj2.attr2}]")
print(obj1 == obj2)
#نوع نمونه obj1
print(f"type(obj1)={type(obj1)}")
print(f"isinstance(obj1,Objet)={isinstance(obj1, Objet)}, isinstance(obj1,object)={isinstance(obj1, object)}")
#هر نوع در پایتون یک شیء است
print(f"type(4)={type(4)}")
print(f"isinstance(4, int)={isinstance(4, int)}, isinstance(4, object)={isinstance(4, object)}")

یادداشت‌ها:

  • خطوط ۲–۳: یک کلاس خالی با نام [Objet];
  • خط ۲: کلاس را می‌توان به سه شکل اعلام کرد:
    • class Object;
    • class Object();
    • class Object(object);
  • خط ۳: شکل دیگری از نظر. این مورد که با سه کاما آغاز می‌شود، می‌تواند چندین خط را در بر بگیرد؛
  • خط ۷: نمونه‌سازی کلاس Objet. نتیجه یک نشانی است، همان‌طور که در خطوط ۲۴–۲۶ نشان داده شده است؛
  • خطوط ۸–۹: مقداردهی مستقیم به دو ویژگی شیء؛
  • خط ۱۷: کپی کردن ارجاعات. متغیرهای obj1 و obj2 دو اشارهگر (ارجاع) به یک شیء واحد هستند؛
  • خط ۱۹: شیء اشاره شده توسط [obj2] تغییر می‌کند. از آنجایی که [obj1] و [obj2] به یک شیء اشاره می‌کنند، نمایش‌های اشیاء [obj1, obj2] در خطوط 21 و 22 نشان خواهند داد که شیء مورد اشاره توسط [obj1] تغییر کرده است؛
  • خطوط ۲۴–۲۶: این خطوط برای نشان دادن برابری متغیرهای [obj1] و [obj2] در نظر گرفته شده‌اند. چاپ خط ۲۶ این موضوع را نشان خواهد داد. در این مقایسه، آدرس‌های [obj1] و [obj2] هستند که برابرند؛
  • هر شیء پایتون با یک شماره یکتا که با استفاده از عبارت [id(objet)] به دست می‌آید، شناسایی می‌شود. خطوط 24 و 25 نشان خواهند داد که شماره‌های اشیایی که توسط [obj1] و [obj2] ارجاع شده‌اند یکسان هستند، و بدین ترتیب نشان می‌دهند که این دو ارجاع به یک شی واحد اشاره می‌کنند؛
  • خطوط 27–29: تابع [isinstance(expr,Type)] مقدار بولین True را برمی‌گرداند اگر عبارت [expr] از نوع [Type] باشد. در اینجا خواهیم دید که [obj1] از نوع [Objet] است، که طبیعی به نظر می‌رسد، اما همچنین از نوع [object] نیز هست. کلاس [object] کلاس والد همه کلاس‌های پایتون است. به دلیل ماهیت ارث‌بری کلاس، یک کلاس فرزند F همه ویژگی‌های کلاس والد خود P را دارد، و تابع [isinstance(instance de F, P)] مقدار True را برمی‌گرداند؛
  • خطوط ۳۰–۳۲: نشان می‌دهند که نوع [int] خود یک نوع [object] است. تمام انواع پایتون از کلاس [object] مشتق شده‌اند؛

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_01.py
objet1=[<__main__.Objet object at 0x0000025C3F469BB0>, <class '__main__.Objet'>,2595221838768,un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
objet1=[<__main__.Objet object at 0x0000025C3F469BB0>, 2595221838768,un,0]
objet2=[<__main__.Objet object at 0x0000025C3F469BB0>, 2595221838768,un,0]
True
type(obj1)=<class '__main__.Objet'>
isinstance(obj1,Objet)=True, isinstance(obj1,object)=True
type(4)=<class 'int'>
isinstance(4, int)=True, isinstance(4, object)=True

Process finished with exit code 0

12.2. اسکریپت [classes_02]: کلاس Person

اسکریپت [classes_02] نشان می‌دهد که ویژگی‌های یک کلاس عمومی هستند: می‌توان مستقیماً از خارج کلاس به آن‌ها دسترسی داشت. این یک نمونه دیگر از نحوه استفاده از کلاس است که توصیه نمی‌شود. با این حال، آن را در اینجا آورده‌ایم زیرا گاهی اوقات با این نوع کد مواجه می‌شویم (پایتون این کار را مجاز می‌داند) و بنابراین باید بتوان آن را درک کرد.


#کلاس Person
class Personne:
    # ویژگی‌های کلاس
    # اعلام‌نشده – می‌تواند به‌صورت پویا ایجاد شود

    # متد
    def identité(self: object) -> str:
        #ظاهراً از ویژگی‌های موجود استفاده نمی‌کند
        return f"[{self.prénom},{self.nom},{self.âge}]"


# ---------------------------------- اصلی
#ویژگی‌ها عمومی هستند و می‌توانند به‌صورت پویا ایجاد شوند
# نمونه سازی کلاس
p = Personne()
# ابتدایی‌سازی مستقیم ویژگی‌های کلاس
p.prénom = "Paul"
p.nom = "de la Hûche"
p.âge = 48
#فراخوانی یک متد کلاس
print(f"personne={p.identité()}")
# نوع نمونه p
print(f"type(p)={type(p)}")
print(f"isinstance(Personne)={isinstance(p, Personne)}, isinstance(object)={isinstance(p, object)}")

نکات:

  • خطوط ۲–۹: یک کلاس با یک متد؛
  • خط ۷: هر متد یک کلاس باید به عنوان اولین پارامتر خود، شی self را داشته باشد که به شی فعلی اشاره می‌کند. متد [identité] یک رشته را برمی‌گرداند؛
  • خط ۱۵: نمونه‌سازی یک شیء [Personne]؛
  • خطوط 16–19: نشان می‌دهند که ویژگی‌های شیء می‌توانند به‌صورت پویا ایجاد شوند (آنها در تعریف کلاس وجود ندارند)؛
  • خط ۹: ویژگی‌های کلاس با نشانه [self.attribut] مشخص می‌شوند؛
  • خطوط ۲۳–۲۴ نشان می‌دهند که شیء [p] هم نمونه‌ای از کلاس [Personne] و هم نمونه‌ای از کلاس [object] است؛

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_02.py
personne=[Paul,de la Hûche,48]
type(p)=<class '__main__.Personne'>
isinstance(Personne)=True, isinstance(object)=True

Process finished with exit code 0

12.3. اسکریپت [classes_03]: کلاس Person با یک سازنده

اسکریپت [classes_03] کاربرد استاندارد یک کلاس را نشان می‌دهد:


# کلاس Person
class Personne:
    # سازنده – سه ویژگی را مقداردهی اولیه می‌کند
    def __init__(self: object, prénom: str, nom: str, âge: int):
        # نام: نام شخص
        # نام خانوادگی: نام خانوادگی شخص
        # سن: سن شخص

        self.prénom = prénom
        self.nom = nom
        self.âge = âge

    # ویژگی‌های کلاس را به صورت یک رشته بازمی‌گرداند
    def identité(self: object) -> str:
        return f"[{self.prénom},{self.nom},{self.âge}]"


# ---------------------------------- دست
# یک شیء Person
p = Personne("Paul", "de la Hûche", 48)
# فراخوانی متد
print(f"personne={p.identité()}")

یادداشت‌ها:

  • خط ۴: سازنده کلاس __init__ فراخوانی می‌شود. مانند سایر متدها، اولین پارامتر آن self است؛
  • خط ۲۰: یک شیء Personne با استفاده از سازنده کلاس ایجاد می‌شود؛
  • خطوط ۱۳–۱۵: متد [identité] یک رشته را که نمایانگر محتوای شیء است بازمی‌گرداند؛
  • خط ۲۲: هویت شخص نمایش داده می‌شود؛

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_03.py
personne=[Paul,de la Hûche,48]

Process finished with exit code 0

12.4. اسکریپت [classes_04]: متدهای استاتیک

در پوشه [modules]، کلاس زیر [Utils] (utils.py) را تعریف می‌کنیم:

Image


class Utils:
    # متد استاتیک
    @staticmethod
    def is_string_ok(string: str) -> bool:
        #آیا 'string' یک رشته است
        erreur = not isinstance(string, str)
        if not erreur:
            #آیا رشته خالی است؟
            erreur = string.strip() == ''
        # نتیجه
        return not erreur

یادداشت‌ها

  • خط ۳: انوتیشن [@staticmethod] نشان می‌دهد که متدی که به این صورت انوتیت شده، یک متد کلاس است و نه یک متد نمونه. این امر از آنجایی واضح است که اولین پارامتر متد انوتیت‌شده، کلمه کلیدی [self] نیست. در نتیجه، متد استاتیک به ویژگی‌های شی دسترسی ندارد. به جای نوشتن:
u=Utils()
print(u.is_string_ok("abcd")

می‌نویسیم

print(Utils.is_string_ok("abcd")

از آنجا که ما در بالا [Utils.is_string_ok] را نوشتیم، متد [is_string_ok] به عنوان یک متد کلاس (در این مورد کلاس Utils) شناخته می‌شود. برای این کار، متد [Utils.is_string_ok] باید با کلمه کلیدی [@staticmethod] علامت‌گذاری شود.

متد استاتیک [Utils.is_string_ok] در اینجا برای بررسی اینکه یک قطعه داده یک رشته غیرخالی است، استفاده می‌شود.

اسکریپت [classes_04] از کلاس [Utils] به صورت زیر استفاده می‌کند:


#پیکربندی برنامه
import config

config = config.configure()

#مسیر سیستم پیکربندی شده است – اکنون می‌توان وارداتی انجام داد
from utilitaires import Utils

print(Utils.is_string_ok("  "))
print(Utils.is_string_ok(47))
print(Utils.is_string_ok(" q "))
  • خطوط ۱–۴: از یک اسکریپت پیکربندی استفاده می‌شود؛

اسکریپت پیکربندی [config.py] به شرح زیر است:


def configure():
    import os

    # مسیر فایل پیکربندی
    script_dir = os.path.dirname(os.path.abspath(__file__))

    #مسیرهای مطلق پوشه‌هایی که باید به syspath اضافه شوند
    absolute_dependencies = [
        f"{script_dir}/shared",
        "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages",
        "C:/myprograms/Python38/lib",
        "C:/myprograms/Python38/DLLs"
    ]

    #به‌روزرسانی syspath
    from myutils import set_syspath
    set_syspath(absolute_dependencies)

    # بازگرداندن پیکربندی
    return {}
  • خط ۹: پوشه [shared] به مسیر پایتون (Python Path) اضافه خواهد شد؛

نتیجه اجرای آن به شرح زیر است:

1
2
3
4
5
6
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_04.py
False
False
True

Process finished with exit code 0

12.5. اسکریپت [classes_05]: بررسی‌های اعتبار ویژگی‌ها

اسکریپت [classes_05] مفاهیم جدیدی را معرفی می‌کند:

  • تعریف یک نوع استثنای سفارشی؛
  • تعریف متد [_str_]، که متد هویت پیش‌فرض برای کلاس‌ها است؛
  • تعریف ویژگی‌ها؛

# راه‌اندازی برنامه
import config

config = config.configure()

#مسیر سیستم پیکربندی شده است – اکنون می‌توان وارداتی را انجام داد
from utilitaires import Utils


#یک کلاس استثنای سفارشی مشتق از [BaseException]
class MyException(BaseException):
    # نیازی به اقدام نیست: کلاس خالی
    pass


#کلاس Person
class Personne:
    # سازنده
    def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0):
        # نام: نام شخص
        # نام خانوادگی: نام خانوادگی شخص
        # سن: سن شخص

        # ذخیره‌سازی پارامتر
        # ابتکاری‌سازی از طریق متدهای setter انجام خواهد شد
        self.prénom = prénom
        self.nom = nom
        self.âge = âge

    # متد toString از کلاس
    def __str__(self: object) -> str:
        return f"[{self.__prénom},{self.__nom},{self.__âge}]"

    # گیرنده‌ها
    @property
    def prénom(self) -> str:
        return self.__prénom

    @property
    def nom(self) -> str:
        return self.__nom

    @property
    def âge(self) -> int:
        return self.__âge

    # setterها
    @prénom.setter
    def prénom(self, prénom: str):
        # نام اول نباید خالی باشد
        if Utils.is_string_ok(prénom):
            self.__prénom = prénom.strip()
        else:
            raise MyException("Le prénom doit être une chaîne de caractères non vide")

    @nom.setter
    def nom(self, nom: str):
        # نام اول نباید خالی باشد
        if Utils.is_string_ok(nom):
            self.__nom = nom.strip()
        else:
            raise MyException("Le nom doit être une chaîne de caractères non vide")

    @âge.setter
    def âge(self, âge: int):
        # سن باید یک عدد صحیح ≥ 0 باشد
        erreur = False
        if isinstance(âge, int):
            if âge >= 0:
                self.__âge = âge
            else:
                erreur = True
        else:
            erreur = True
        # خطا؟
        if erreur:
            raise MyException("L'âge doit être un entier >=0")


# ---------------------------------- main
# یک شیء Person
try:
    # مثال‌سازی کلاس Person
    p = Personne("Paul", "de la Hûche", 48)
    # نمایش شیء p
    print(f"personne={p}")
except MyException as erreur:
    # نمایش خطا
    print(erreur)

# یک شیء Person دیگر
try:
    # نمونه سازی کلاس Person
    p = Personne("xx", "yy", "zz")
    # نمایش شیء p
    print(f"personne={p}")
except MyException as erreur:
    # نمایش خطا
    print(erreur)

# یک شیء Person دیگر، این بار بدون پارامتر
try:
    # مثال‌سازی کلاس Person
    p = Personne()
    # نمایش شیء p
    print(f"personne={p}")
except MyException as erreur:
    #نمایش پیام خطا
    print(erreur)

#نمی‌توان به ویژگی‌های خصوصی کلاس __attr دسترسی داشت
p.__prénom = "Gaëlle"
print(f"p.prénom={p.prénom}")
print(f"p.__prénom={p.__prénom}")
p.prénom = "Sébastien"
print(f"p.prénom={p.prénom}")
print(f"p.__prénom={p.__prénom}")

یادداشت‌ها:

  • خطوط ۱۰–۱۳: کلاسی به نام MyException که از کلاس BaseException مشتق شده است (بعداً به این مورد با جزئیات بیشتری خواهیم پرداخت). این کلاس هیچ قابلیت جدیدی به کلاس دوم اضافه نمی‌کند. وجود آن تنها برای ارائه یک استثنای سفارشی است؛
  • خط ۱۹: سازنده برای پارامترهای خود مقادیر پیش‌فرض دارد. بنابراین، عملیات p=Personne() معادل p=Personne("x","y",0) است؛
  • خطوط ۳۴–۴۵: ویژگی‌های کلاس. این‌ها متدهایی هستند که با کلمه کلیدی [@property] علامت‌گذاری شده‌اند. از آن‌ها برای بازگرداندن مقادیر ویژگی‌ها استفاده می‌شود؛
  • خطوط ۴۷–۷۷: متدهای تنظیم‌کننده کلاس. این‌ها متدهایی هستند که با کلمه کلیدی [@attributsetter] علامت‌گذاری شده‌اند. از آن‌ها برای تعیین مقادیر ویژگی‌ها استفاده می‌شود؛
  • خطوط ۴۸–۵۴: متد تنظیم‌کنندهٔ ویژگی [prénom]. این متد هرگاه مقداری برای ویژگی [prénom] تعیین شود، فراخوانی خواهد شد:
p=Personne(…)
p.prénom=valeur

خط ۲ باعث فراخوانی [p.prénom(valeur)] خواهد شد. مزیت استفاده از یک ستر برای تخصیص مقدار به یک ویژگی این است که، از آنجایی که ستر یک تابع است، اعتبار مقدار تخصیص‌یافته به ویژگی را می‌توان بررسی کرد؛

  • خط ۵۱: ما بررسی می‌کنیم که مقداری که به ویژگی [prénom] اختصاص داده شده، یک رشته غیرخالی است. برای این کار، از متد استاتیک [Utils.isStringOk] که قبلاً دیدیم استفاده می‌کنیم؛
  • خط ۵۲: مقدار اختصاص‌یافته به ویژگی [prénom] از فاصله‌های خالی ابتدایی و انتهایی پاک شده و به ویژگی [self.__prénom] اختصاص داده می‌شود. بنابراین، اینجا از ویژگی [prénom] استفاده نشده است. این ویژگی نمی‌توانست به شکل دیگری استفاده شود، زیرا این کار منجر به یک فراخوانی بازگشتی بی‌نهایت می‌شد. می‌توانست از هر نام صفت دیگری استفاده شود. این که از صفت [__prénom] با دو خط تیره در ابتدای شناسگر استفاده شده است، اهمیت ویژه‌ای دارد: صفت‌هایی که با دو خط تیره شروع می‌شوند، خصوصی (private) برای کلاس هستند. این بدان معناست که از خارج کلاس قابل مشاهده نیستند. بنابراین نمی‌توانیم بنویسیم:
p=Personne(…)
p.__prénom=valeur

در واقع، به زودی خواهیم دید که می‌توانید آن را بنویسید، اما این کار نام اول را تغییر نمی‌دهد. این کار چیز دیگری انجام می‌دهد؛

  • خطوط ۵۳–۵۴: اگر مقداری که برای نام اول اختصاص داده شده نادرست باشد، یک استثنا پرتاب می‌شود. به این ترتیب، کد فراخوانی‌کننده متوجه می‌شود که فراخوانی آن نادرست است؛
  • خطوط ۳۵–۳۷: ویژگی [prénom]. این ویژگی هرگاه [p.prénom] در یک عبارت نوشته شود، فراخوانی خواهد شد. سپس متد [p.prénom()] فراخوانی می‌شود. خط ۳۷: مقدار ویژگی [__prénom] بازگردانده می‌شود، زیرا همانطور که دیدیم، متد تنظیم‌کننده ویژگی [prénom] مقدار آن را به ویژگی خصوصی [__prénom] اختصاص می‌دهد؛
  • خطوط ۵۶–۶۲: متد تنظیم‌کننده ویژگی [nom] به روشی مشابه متد تنظیم‌کننده ویژگی [prénom] ساخته شده است. همین امر در مورد متد تنظیم مقدار ویژگی [âge] در خطوط 64–77 نیز صدق می‌کند؛
  • اگرچه ویژگی‌های [prénom, nom, valeur] خودِ صفت‌ها نیستند—که در واقع [__prénom, __nom, __âge] هستند—ما همچنان به آن‌ها به عنوان صفت‌های کلاس اشاره خواهیم کرد، زیرا به همین شکل استفاده می‌شوند؛
  • خطوط ۱۹–۲۸: سازنده کلاس به‌طور ضمنی از متدهای تنظیم‌کننده برای ویژگی‌های [prénom, nom, âge] استفاده می‌کند. در واقع، با نوشتن [self.prénom = prénom] در خط ۲۶، متد [prénom(self, prénom)] به‌طور ضمنی فراخوانی خواهد شد. در این صورت اعتبار پارامتر [prénom] بررسی خواهد شد. همین امر برای دو ویژگی دیگر، [nom, âge] نیز صدق می‌کند؛
  • با این مدل، تخصیص مقادیر نادرست به ویژگی‌های [prénom, nom, âge] کلاس امکان‌پذیر نیست؛
  • خطوط ۳۰–۳۲: تابع __str__ جایگزین متدی می‌شود که قبلاً با نام identité شناخته می‌شد. نام [__str__] (با دو خط تیره در ابتدا و انتها) بی‌اهمیت نیست. بعداً خواهیم دید چرا؛
  • خطوط ۸۳–۸۶: نمونه‌سازی یک شخص، و به دنبال آن نمایش هویت او؛
  • خط ۸۴: نمونه‌سازی؛
  • خط ۸۶: نمایش. این عملیات نیاز دارد که شخص p به صورت یک رشته نمایش داده شود. تفسیرگر پایتون سپس به طور خودکار متد p.__str__() را در صورت وجود فراخوانی می‌کند. این متد همان نقش متد toString() را در جاوا یا در زبان‌های .NET ایفا می‌کند؛
  • خطوط ۸۷–۸۹: رسیدگی به هر استثنای نوع MyException. سپس خطا نمایش داده می‌شود؛
  • خطوط ۹۱–۹۹: همین امر در مورد یک نمونه دوم که با پارامترهای نادرست ایجاد شده است نیز صدق می‌کند؛
  • خطوط ۱۰۲–۱۰۹: همین امر در مورد نمونه سوم از Person که با پارامترهای پیش‌فرض ایجاد شده نیز صدق می‌کند: هیچ پارامتری ارسال نمی‌شود. بنابراین، مقادیر پیش‌فرض این پارامترها در سازنده در اینجا استفاده می‌شوند؛
  • خطوط ۱۱۲–۱۱۷: ما بیان کردیم که ویژگی [__prénom] خصوصی است و بنابراین به طور معمول از خارج کلاس در دسترس نیست. می‌خواهیم این موضوع را بررسی کنیم؛
  • خطوط ۱۱۲–۱۱۴: مقداری به ویژگی [__prénom] اختصاص داده می‌شود، سپس مقادیر ویژگی‌های [__prénom] و [prénom] بررسی می‌شوند که معمولاً باید یکسان باشند؛
  • خطوط ۱۱۵–۱۱۷: عملیات تکرار می‌شود، این بار با مقداردهی اولیه ویژگی [prénom]؛

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_05.py
personne=[Paul,de la Hûche,48]
L'âge doit être un entier >=0
personne=[x,y,0]
p.prénom=x
p.__prénom=Gaëlle
p.prénom=Sébastien
p.__prénom=Gaëlle

Process finished with exit code 0

یادداشت‌ها

  • خطوط ۵–۶: می‌توانیم ببینیم که تخصیص [p.__prénom = "Gaëlle"] مقدار ویژگی [prénom] را در خط ۵ تغییر نداده است؛
  • خطوط ۷–۸: می‌توانیم ببینیم که تخصیص [p.prénom = "Sébastien"] مقدار ویژگی [__prénom] را در خط ۸ تغییر نداده است؛

از این چه می‌توان نتیجه گرفت؟ اینکه عملیات [p.__prénom = "Gaëlle"] احتمالاً یک ویژگی عمومی [__prénom] برای کلاس ایجاد کرده است، اما این ویژگی با ویژگی خصوصی [__prénom] که در داخل آن دستکاری می‌شود، متفاوت است؛

12.6. اسکریپت [classes_06]: افزودن یک متد инициализация شیء

اسکریپت [classes_06] یک متد به کلاس [Personne] اضافه می‌کند:


#پیکربندی برنامه
import config

config = config.configure()

#مسیر سیستم پیکربندی شده است – واردسازی‌ها می‌توانند انجام شوند
from utilitaires import Utils


#یک کلاس استثنای سفارشی مشتق‌شده از [BaseException]
class MyException(BaseException):
    # اقدامی انجام نشده: کلاس خالی
    pass


# کلاس شخص
class Personne:
    # سازنده
    def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0):
        # نام: نام شخص
        # نام خانوادگی: نام خانوادگی شخص
        # سن: سن شخص

        # ذخیره‌سازی پارامتر
        # ابتکاری‌سازی از طریق متدهای setter انجام خواهد شد
        self.prénom = prénom
        self.nom = nom
        self.âge = âge

    # روش اولیهٔ جایگزین
    def init_with_personne(self: object, p: object):
        # شیء فعلی را با فردی به نام p مقداردهی اولیه می‌کند
        self.__init__(p.prénom, p.nom, p.âge)

    # متد toString از کلاس
    def __str__(self: object) -> str:
        return f"[{self.__prénom},{self.__nom},{self.__âge}]"

    # گیرنده‌ها


    # setورها



# ---------------------------------- main
# یک شیء Person
try:
    # نمونه سازی کلاس Person
    p = Personne("Paul", "de la Hûche", 48)
    # نمایش شیء Person
    print(f"personne={p}")
except MyException as erreur:
    # نمایش یک پیام خطا
    print(erreur)

# یک شیء Person دیگر
try:
    # نمادسازی کلاس Person
    p = Personne("xx", "yy", "zz")
    #نمایش شی p
    print(f"p={p}")
except MyException as erreur:
    #نمایش پیام خطا
    print(erreur)

# یک شیء Person دیگر، این بار بدون پارامتر
try:
    # نمونه سازی کلاس Person
    p = Personne()
    #نمایش شیء p
    print(f"p={p}")
except MyException as erreur:
    #نمایش پیام خطا
    print(erreur)

# شئ Person دیگری که با کپی کردن به دست آمده است
try:
    # مثال‌سازی کلاس Person
    p2 = Personne()
    p2.init_with_personne(p)
    #نمایش شیء p2
    print(f"p2={p2}")
except MyException as erreur:
    # نمایش پیام خطا
    print(erreur)

یادداشت‌ها:

  • تفاوت با اسکریپت قبلی در خطوط ۳۰–۳۳ است. متد initWithPersonne اضافه شده است. این متد، کانستراکتور __init__ را فراخوانی می‌کند. برخلاف زبان‌های تایپ‌شده، امکان وجود متدهایی با نام یکسان که با ماهیت پارامترها یا مقادیر بازگشتی‌شان از هم متمایز شوند، وجود ندارد. بنابراین، امکان داشتن چندین سازنده که شیء را از روی پارامترهای مختلف ایجاد کنند، در این مورد یک شیء از نوع Personne، وجود ندارد؛

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_06.py
personne=[Paul,de la Hûche,48]
L'âge doit être un entier >=0
p=[x,y,0]
p2=[x,y,0]

Process finished with exit code 0

12.7. اسکریپت [classes_07]: فهرستی از اشیاء Person

اکنون کلاس‌های [MyException] و [Personne] را در یک ماژول قرار می‌دهیم تا بتوانیم بدون نیاز به کپی کردن کدشان از آن‌ها استفاده کنیم:

Image

هر دو کلاس در ماژول [myclasses.py] بالا قرار خواهند گرفت.

اسکریپت [classes_07] نشان می‌دهد چگونه یک لیست از اشیاء ایجاد کنیم:


# پیکربندی برنامه
import config

config = config.configure()

# مسیر سیستم پیکربندی شده است – اکنون می‌توان وارداتی انجام داد
from myclasses import Personne

# ---------------------------------- اصلی
# ایجاد یک لیست از اشیاء شخص
groupe = [Personne("Paul", "Langevin", 48), Personne("Sylvie", "Lefur", 70)]
# هویت این افراد
for i in range(len(groupe)):
    print(f"groupe[{i}]={groupe[i]}")

یادداشت‌ها:

  • خط ۷: کلاس [Personne] وارد شده است؛
  • خط ۱۱: یک لیست از اشیاء از نوع [Personne];
  • خطوط ۱۳–۱۴: ما این لیست را مرور می‌کنیم تا هر یک از عناصر آن را نمایش دهیم؛
  • خط ۱۴: تابع [print] رشته‌ای را که نمایانگر شیء [groupe[i]] است، نمایش می‌دهد. به طور پیش‌فرض، متد [__str__] این اشیاء فراخوانی خواهد شد؛

نتایج


C:\Users\serge\.virtualenvs\cours-python-v02\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/v-02/classes/01/classes_07.py
groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]

Process finished with exit code 0

12.8. اسکریپت [classes_08]: ایجاد کلاسی مشتق‌شده از کلاس Person

در ماژول [myclasses]، کلاس زیر [Enseignant] را تعریف می‌کنیم:


#کلاس معلم
class Enseignant(Personne):
    # سازنده
    def __init__(self, prénom: str = "x", nom: str = "x", âge: int = 0, discipline: str = "x"):
        # نام: نام شخص
        # نام خانوادگی: نام خانوادگی شخص
        # سن: سن شخص
        # موضوع: موضوع تدریس‌شده

        # ابتدایی‌سازی والد
        Personne.__init__(self, prénom, nom, âge)
        # حروف اختصاری دیگر
        self.discipline = discipline

    # toString
    def __str__(self) -> str:
        return f"enseignant[{super().__str__()},{self.discipline}]"

    # ویژگی‌ها
    @property
    def discipline(self) -> str:
        return self.__discipline

    @discipline.setter
    def discipline(self, discipline: str):
        # موضوع باید یک رشته غیرخالی باشد
        if Utils.is_string_ok(discipline):
            self.__discipline = discipline
        else:
            raise MyException("La discipline doit être une chaîne de caractères non vide")
  • خط ۲: کلاس Enseignant را به‌عنوان یک کلاس مشتق از کلاس Personne اعلام می‌کند. یک کلاس مشتق تمام ویژگی‌های (صفت‌ها و متدها) کلاس والد خود را به‌علاوه ویژگی‌های خود دارد؛
  • خط ۱۳: کلاس [Enseignant] یک ویژگی جدید [discipline] را تعریف می‌کند؛
  • خط ۱۱: سازنده کلاس مشتق Enseignant باید سازنده کلاس والد Personne را فراخوانی کند و پارامترهای مورد انتظار آن را به آن ارسال نماید؛
  • خط 17: تابع [super()] کلاس والد را برمی‌گرداند. در اینجا، تابع [__str__] از کلاس والد فراخوانی می‌شود؛
  • خطوط ۱۹–۳۰: گتر و ستر برای ویژگی جدید [discipline] تعریف شده‌اند؛

اسکریپت [classes_08] از کلاس [Enseignant] به صورت زیر استفاده می‌کند:


# برنامه پیکربندی شده است
import config

config = config.configure()

# مسیر سیستم پیکربندی شده است – اکنون می‌توان واردات را انجام داد
from myclasses import Personne, Enseignant

# ---------------------------------- اصلی
# ایجاد آرایه‌ای از اشیاء Person و کلاس‌های مشتق
groupe = [Enseignant("Paul", "Langevin", 48, "anglais"), Personne("Sylvie", "Lefur", 70)]
# هویت این افراد
for i in range(len(groupe)):
    print(f"groupe[{i}]={groupe[i]}")

یادداشت‌ها:

  • خط ۷: کلاس‌های [Personne] و [Enseignant] که در فایل [myclasses.py] تعریف شده‌اند، وارد می‌شوند؛
  • خطوط ۱۱–۱۴: یک گروه از افراد تعریف می‌شود که هویت آن‌ها سپس نمایش داده می‌شود؛

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_08.py
groupe[0]=enseignant[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]

Process finished with exit code 0

12.9. اسکریپت [classes_09]: کلاس دوم مشتق‌شده از کلاس Person

اسکریپت [classes_09] کلاس [Etudiant] را معرفی می‌کند که از کلاس [Personne] مشتق شده است. این کلاس در ماژول [myclasses] به صورت زیر تعریف شده است:


#کلاس دانشجو
class Etudiant(Personne):
    # سازنده
    def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0, formation: str = "x"):
        Personne.__init__(self, prénom, nom, âge)
        self.formation = formation

    # toString
    def __str__(self: object) -> str:
        return f"étudiant[{super().__str__()},{self.formation}]"

    # ویژگی‌ها
    @property
    def formation(self) -> str:
        return self.__formation

    @formation.setter
    def formation(self, formation: str):
        # دوره باید یک رشتهٔ غیرخالی باشد
        if Utils.is_string_ok(formation):
            self.__formation = formation
        else:
            raise MyException("La formation doit être une chaîne de caractères non vide")

اسکریپت [classes_09] از کلاس [Etudiant] به شرح زیر استفاده می‌کند:


# برنامه پیکربندی شده است
import config

config = config.configure()

#مسیر سیستم پیکربندی شده است – اکنون می‌توان واردات را انجام داد
from myclasses import Personne, Enseignant, Etudiant

# ---------------------------------- اصلی
#ایجاد آرایه‌ای از اشیاء Person و کلاس‌های مشتق
groupe = [Enseignant("Paul", "Langevin", 48, "anglais"), Personne("Sylvie", "Lefur", 70),
          Etudiant("Steve", "Boer", 22, "iup2 qualité")]
# هویت‌های این افراد
for personne in groupe:
    #نمایش یک شخص
    print(personne)

یادداشت‌ها:

  • این اسکریپت مشابه مورد قبلی است.

نتایج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_09.py
enseignant[[Paul,Langevin,48],anglais]
[Sylvie,Lefur,70]
étudiant[[Steve,Boer,22],iup2 qualité]

Process finished with exit code 0

12.10. اسکریپت [classes_10]: ویژگی [__dict__]

اسکریپت [classes_10] دارای ویژگی [__dict__] است که از این پس به طور مکرر از آن استفاده خواهیم کرد:


# پیکربندی برنامه
import config

config = config.configure()

# مسیر سیستم پیکربندی شده است – اکنون می‌توان عملیات واردسازی را انجام داد
from myclasses import Etudiant

# ---------------------------------- اصلی
# ایجاد یک دانش‌آموز
étudiant=Etudiant("Steve", "Boer", 22, "iup2 qualité")
# واژه‌نامه ویژگی‌ها
print(étudiant.__dict__)

توضیحات

  • خطوط ۱–۴: برنامه پیکربندی شده است؛
  • خط ۷: کلاس [Etudiant] وارد می‌شود؛
  • خط ۱۱: ایجاد یک شیء دانشجو؛
  • خط ۱۳: از متد از پیش تعریف شده [__dict__] استفاده می‌شود (۲ کاراکتر زیرخط‌دار قبل و بعد از شناسه)؛

نتایج به شرح زیر است:

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_10.py
{'_Personne__prénom': 'Steve', '_Personne__nom': 'Boer', '_Personne__âge': 22, '_Etudiant__formation': 'iup2 qualité'}

Process finished with exit code 0
  • خط ۲: یک دیکشنری به دست می‌آید که کلیدهای آن، ویژگی‌های شیء هستند که با نام کلاسی که به آن تعلق دارند، پیش‌وند شده‌اند. ما از این دیکشنری برای ایجاد یک پل ارتباطی بین شیء و دیکشنری استفاده خواهیم کرد؛