FA-TOOLS — Header Component
آموزش ارث‌بری (Inheritance) در پایتون با مثال

آموزش ارث‌بری (Inheritance) در پایتون با مثال

رفیق برنامه‌نویس، تا حالا شده بخوای کدهایی که نوشتی رو دوباره و سه‌باره استفاده کنی، بدون اینکه مجبور باشی همه رو از اول بنویسی؟ یا شاید بخوای یه قابلیت جدید به کدهای قبلیت اضافه کنی بدون اینکه ساختار اصلی رو بهم بریزی؟ اگه جوابت مثبته، پس درست اومدی!
ارث‌بری (Inheritance) توی پایتون دقیقاً همون ابزاریه که بهت کمک می‌کنه کدهای تمیزتر، منعطف‌تر و قابل نگهداری بهتری داشته باشی. این مفهوم سنگ بنای برنامه‌نویسی شی‌گراست و بهت اجازه می‌ده از کلاس‌های موجود، کلاس‌های جدیدی بسازی که ویژگی‌ها و رفتارهای کلاس والد رو به ارث می‌برند و می‌تونن قابلیت‌های جدیدی هم بهشون اضافه کنن.

قبل از اینکه غرق دنیای جذاب و پرکاربرد ارث‌بری بشی، حتماً یه سر به ابزارهای کاربردی ما بزن تا کار کدنویسیت رو سریع‌تر و راحت‌تر کنی. کلی ابزار باحال برای پایتون و بقیه زبان‌ها اونجا منتظرته!

برای هر سوال یا مشاوره تخصصی هم می‌تونی همین الان تماس بگیری: 09202232789

🚀 نقشه راه: ارث‌بری در پایتون در یک نگاه 🚀

آموزش ارث‌بری (Inheritance) در پایتون با مثال — تصویر 1

🌟 مفهوم اصلی

  • بازاستفاده از کد (Code Reusability)
  • رابطه “یک نوع از” (Is-A Relationship)
  • کلاس والد (Parent/Base Class)
  • کلاس فرزند (Child/Derived Class)

📚 انواع ارث‌بری

  • تک‌ارث‌بری (Single Inheritance)
  • چندگانه (Multiple Inheritance)
  • چندسطحی (Multilevel Inheritance)
  • سلسله‌مراتبی (Hierarchical Inheritance)
  • ترکیبی (Hybrid Inheritance)

🛠️ مفاهیم کلیدی

  • بازنویسی متد (Method Overriding)
  • تابع super()
  • MRO (Method Resolution Order)
  • isinstance() & issubclass()

✅ چرا و کی استفاده کنیم؟

  • کاهش تکرار کد (DRY Principle)
  • ساختاردهی بهتر برنامه
  • قابلیت نگهداری بالا
  • توسعه‌پذیری آسان

ارث‌بری (Inheritance) چیست و چرا مهمه؟

آموزش ارث‌بری (Inheritance) در پایتون با مثال — تصویر 2

تصور کن یک کلاس داری به اسم `حیوان` که ویژگی‌های مشترک همه حیوانات مثل `نام` و `سن` رو داره و متدهایی مثل `غذا_خوردن()` و `صدا_دادن()` رو پیاده‌سازی می‌کنه. حالا اگه بخوای کلاس‌های دیگه‌ای مثل `سگ` و `گربه` بسازی، نیازی نیست همه اون ویژگی‌ها و متدها رو از اول توی هر کدوم بنویسی. اینجا ارث‌بری به کمکت میاد!

ارث‌بری توی برنامه‌نویسی شی‌گرا (OOP) بهت اجازه می‌ده یک کلاس جدید بسازی که تمام ویژگی‌ها (صفت‌ها) و متدهای یک کلاس دیگه رو به ارث می‌بره. به کلاسی که ویژگی‌هاش رو به ارث می‌ده، کلاس والد (Parent Class یا Base Class) و به کلاسی که ویژگی‌ها رو دریافت می‌کنه، کلاس فرزند (Child Class یا Derived Class) می‌گن.

مهم‌ترین دلیل استفاده از ارث‌بری، بازاستفاده از کد (Code Reusability) و ایجاد یک ساختار منطقی و سلسله‌مراتبی در برنامه هست. با این کار، نه تنها حجم کدنویسی‌ات کمتر میشه، بلکه کدها خواناتر و نگهداری‌شون هم آسون‌تره. اینطوری برنامه تو بیشتر به دنیای واقعی شبیه میشه، جایی که مفاهیم خاص از مفاهیم عمومی‌تر مشتق میشن.

چطور یک کلاس رو به ارث ببریم؟

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


class حیوان:
    def __init__(self, نام):
        self.نام = نام

    def صدا_دادن(self):
        raise NotImplementedError("این متد باید در کلاس فرزند پیاده‌سازی شود")

    def اطلاعات(self):
        return f"نام: {self.نام}"

class سگ(حیوان): # کلاس سگ از حیوان به ارث می‌برد
    def __init__(self, نام, نژاد):
        super().__init__(نام) # فراخوانی سازنده کلاس والد
        self.نژاد = نژاد

    def صدا_دادن(self):
        return "هاپ هاپ!"

    def اطلاعات(self): # بازنویسی متد اطلاعات
        return f"{super().اطلاعات()}, نژاد: {self.نژاد}"

# ساخت نمونه از کلاس‌ها
doggo = سگ("دینگو", "ژرمن شپرد")
print(doggo.اطلاعات())
print(doggo.صدا_دادن())

# خروجی:
# نام: دینگو, نژاد: ژرمن شپرد
# هاپ هاپ!
    

function copyCode(button) {
const codeBlock = button.nextElementSibling.querySelector(‘code’);
const range = document.createRange();
range.selectNode(codeBlock);
window.getSelection().removeAllRanges(); // Clear current selection
window.getSelection().addRange(range); // Select the code
try {
document.execCommand(‘copy’);
button.textContent = ‘کپی شد!’;
setTimeout(() => button.textContent = ‘کپی کد’, 2000);
} catch (err) {
console.error(‘Failed to copy: ‘, err);
button.textContent = ‘خطا در کپی!’;
}
window.getSelection().removeAllRanges(); // Deselect
}

انواع ارث‌بری در پایتون

آموزش ارث‌بری (Inheritance) در پایتون با مثال — تصویر 3

پایتون از چندین نوع ارث‌بری پشتیبانی می‌کنه که هر کدوم کاربردهای خاص خودشون رو دارن. بیا با هم تک تک‌شون رو بررسی کنیم:

۱. تک‌ارث‌بری (Single Inheritance)

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

۲. چندارث‌بری (Multiple Inheritance)

وقتی یک کلاس فرزند از چندین کلاس والد به صورت همزمان ارث می‌بره، بهش چندارث‌بری میگن. این قابلیت خیلی قدرتمنده ولی اگه حواست نباشه، می‌تونه باعث پیچیدگی‌هایی مثل “مسئله الماس” (Diamond Problem) در زبان‌هایی مثل C++ بشه. البته پایتون با مفهوم Method Resolution Order (MRO) این مشکل رو مدیریت می‌کنه. برای اطلاعات بیشتر در مورد مفاهیم پیشرفته پایتون، می‌تونی به بخش اسنیپت‌های پایتون ما سر بزنی.


class پرنده:
    def پرواز_کردن(self):
        return "من پرواز می‌کنم."

class شناگر:
    def شنا_کردن(self):
        return "من شنا می‌کنم."

class پنگوئن(پرنده, شناگر): # پنگوئن از پرنده و شناگر به ارث می‌برد
    def __init__(self, نام):
        self.نام = نام

    def صدا_دادن(self):
        return "جیک جیک!"

    # پنگوئن نمی‌تونه پرواز کنه، پس متد پرواز_کردن رو بازنویسی می‌کنیم.
    def پرواز_کردن(self):
        return "من نمی‌تونم پرواز کنم، ولی رفیقام می‌تونن!"

پینگو = پنگوئن("پینگو")
print(f"{پینگو.نام}: {پینگو.صدا_دادن()}")
print(f"{پینگو.نام}: {پینگو.پرواز_کردن()}")
print(f"{پینگو.نام}: {پینگو.شنا_کردن()}")

# خروجی:
# پینگو: جیک جیک!
# پینگو: من نمی‌تونم پرواز کنم، ولی رفیقام می‌تونن!
# پینگو: من شنا می‌کنم.
    

۳. چندسطحی (Multilevel Inheritance)

توی این مدل، یک کلاس از کلاسی ارث می‌بره که خودش از کلاس دیگری به ارث برده. یعنی یک زنجیره ارث‌بری داریم: A -> B -> C.


class وسیله_نقلیه:
    def __init__(self, برند):
        self.برند = برند

    def حرکت(self):
        return f"{self.برند} در حال حرکت است."

class ماشین(وسیله_نقلیه):
    def __init__(self, برند, مدل):
        super().__init__(برند)
        self.مدل = مدل

    def بوق_زدن(self):
        return "بوق بوق!"

class خودرو_برقی(ماشین): # خودرو_برقی از ماشین (که خودش از وسیله_نقلیه ارث برده) ارث می‌برد
    def __init__(self, برند, مدل, ظرفیت_باتری):
        super().__init__(برند, مدل)
        self.ظرفیت_باتری = ظرفیت_باتری

    def شارژ_کردن(self):
        return f"{self.مدل} با ظرفیت باتری {self.ظرفیت_باتری} kWh در حال شارژ شدن است."

تسلا = خودرو_برقی("تسلا", "مدل S", 100)
print(تسلا.حرکت())
print(تسلا.بوق_زدن())
print(تسلا.شارژ_کردن())

# خروجی:
# تسلا در حال حرکت است.
# بوق بوق!
# مدل S با ظرفیت باتری 100 kWh در حال شارژ شدن است.
    

۴. سلسله‌مراتبی (Hierarchical Inheritance)

توی این نوع، یک کلاس والد داریم که چندین کلاس فرزند از اون به ارث می‌برن. یعنی ساختاری شبیه به درخت ایجاد میشه.


class شخص:
    def __init__(self, نام):
        self.نام = نام

    def معرفی(self):
        return f"سلام، من {self.نام} هستم."

class دانشجو(شخص): # دانشجو از شخص ارث می‌برد
    def __init__(self, نام, شماره_دانشجویی):
        super().__init__(نام)
        self.شماره_دانشجویی = شماره_دانشجویی

    def تحصیل(self):
        return f"{self.نام} در حال تحصیل است."

class کارمند(شخص): # کارمند هم از شخص ارث می‌برد
    def __init__(self, نام, کد_پرسنلی):
        super().__init__(نام)
        self.کد_پرسنلی = کد_پرسنلی

    def کار_کردن(self):
        return f"{self.نام} در حال انجام وظیفه است."

علی = دانشجو("علی", "987654")
زهرا = کارمند("زهرا", "12345")

print(علی.معرفی())
print(علی.تحصیل())
print(زهرا.معرفی())
print(زهرا.کار_کردن())

# خروجی:
# سلام، من علی هستم.
# علی در حال تحصیل است.
# سلام، من زهرا هستم.
# زهرا در حال انجام وظیفه است.
    

۵. ترکیبی (Hybrid Inheritance)

این نوع ترکیبی از دو یا چند نوع ارث‌بری بالاست. مثلاً می‌تونی یک کلاس داشته باشی که هم از دو کلاس دیگه (چندارث‌بری) و هم از یک کلاس دیگه که خودش والد اون دو کلاس (چندسطحی) هست، ارث ببره. مدیریت این نوع ارث‌بری نیاز به دقت بیشتری داره.

جدول مقایسه‌ای: انواع ارث‌بری

نوع ارث‌بری توضیح مختصر
تک‌ارث‌بری یک فرزند از یک والد
چندارث‌بری یک فرزند از چند والد
چندسطحی زنجیره‌ای از ارث‌بری (A -> B -> C)
سلسله‌مراتبی چندین فرزند از یک والد
ترکیبی ترکیبی از انواع بالا

مفاهیم پیشرفته‌تر در ارث‌بری

بازنویسی متد (Method Overriding)

وقتی یک متد در کلاس فرزند، همون اسم و تعداد پارامترهای یک متد در کلاس والد رو داره، بهش میگن بازنویسی متد. این یعنی کلاس فرزند می‌تونه رفتار یک متد رو که از والد به ارث برده، تغییر بده و مخصوص خودش کنه. همونطور که توی مثال `سگ` دیدی، متد `صدا_دادن()` رو بازنویسی کردیم.

استفاده از super()

تابع super() بهت این امکان رو میده که به متدها و صفات کلاس والد (یا به طور دقیق‌تر، به متدهای کلاس بعدی در MRO) دسترسی پیدا کنی. این کار مخصوصاً برای فراخوانی سازنده کلاس والد (__init__) توی کلاس فرزند خیلی مفیده تا مطمئن بشی که بخش مربوط به والد هم به درستی مقداردهی اولیه میشه.

نکته مهم: وقتی از super() برای فراخوانی __init__ استفاده می‌کنی، نیازی به ارسال self نیست، چون super() خودش این کار رو مدیریت می‌کنه.


class والد:
    def __init__(self, نام):
        self.نام = نام
        print(f"سازنده والد: {self.نام}")

    def نمایش_پیام(self):
        return "من یک والد هستم."

class فرزند(والد):
    def __init__(self, نام, سن):
        super().__init__(نام) # فراخوانی سازنده والد
        self.سن = سن
        print(f"سازنده فرزند: {self.نام}, {self.سن} ساله")

    def نمایش_پیام(self):
        # فراخوانی متد نمایش_پیام از والد و اضافه کردن به آن
        پیام_والد = super().نمایش_پیام()
        return f"{پیام_والد} و من یک فرزند هستم."

بچه = فرزند("سام", 5)
print(بچه.نمایش_پیام())

# خروجی:
# سازنده والد: سام
# سازنده فرزند: سام, 5 ساله
# من یک والد هستم. و من یک فرزند هستم.
    

Method Resolution Order (MRO)

MRO ترتیبی رو مشخص می‌کنه که پایتون متدها و صفات رو در سلسله‌مراتب ارث‌بری جستجو می‌کنه. این مفهوم مخصوصاً توی چندارث‌بری مهم میشه. پایتون از یک الگوریتم به نام C3 linearization برای تعیین MRO استفاده می‌کنه که اطمینان حاصل می‌کنه ترتیب جستجو منطقی و بدون ابهام باشه. می‌تونی MRO هر کلاسی رو با استفاده از `__mro__` یا تابع `mro()` ببینی:


class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

print(D.__mro__)
# خروجی:
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    

توابع isinstance() و issubclass()

این دو تابع خیلی کاربردی هستن برای اینکه بفهمی یک شیء از چه نوعی هست یا یک کلاس، فرزند کلاس دیگه هست یا نه.

  • isinstance(object, classinfo): بررسی می‌کنه که آیا `object` یک نمونه (instance) از `classinfo` (یا زیرکلاس‌های آن) هست یا نه.
  • issubclass(class, classinfo): بررسی می‌کنه که آیا `class` یک زیرکلاس (subclass) از `classinfo` هست یا نه.


class وسیله_نقلیه: pass
class ماشین(وسیله_نقلیه): pass
class دوچرخه(وسیله_نقلیه): pass

my_car = ماشین()
my_bike = دوچرخه()

print(isinstance(my_car, ماشین))      # True
print(isinstance(my_car, وسیله_نقلیه)) # True
print(isinstance(my_bike, ماشین))     # False

print(issubclass(ماشین, وسیله_نقلیه)) # True
print(issubclass(دوچرخه, ماشین))    # False
print(issubclass(ماشین, object))    # True (همه کلاس‌ها از object ارث می‌برند)
    

چه زمانی از ارث‌بری استفاده کنیم؟

ارث‌بری ابزاری قدرتمنده، اما مثل هر ابزار دیگه‌ای، باید بدونی کی و کجا ازش استفاده کنی. اگه رابطه “یک نوع از” (Is-A relationship) بین کلاس‌ها برقرار باشه، ارث‌بری بهترین انتخابه. مثلاً “یک سگ، یک نوع حیوان است” یا “یک ماشین، یک نوع وسیله نقلیه است”.

  • کاهش تکرار کد: ویژگی‌ها و رفتارهای مشترک رو توی کلاس والد قرار بده.
  • ساختاردهی بهتر: برنامه‌ات رو به صورت سلسله‌مراتبی و منطقی سازماندهی کن.
  • قابلیت نگهداری و توسعه‌پذیری: اگه نیاز به تغییر توی یک ویژگی مشترک داشتی، فقط کافیه اون رو توی کلاس والد عوض کنی و همه کلاس‌های فرزند از اون تغییر بهره‌مند میشن. برای توسعه قابلیت‌های جدید هم کافیه کلاس فرزند جدید بسازی.

گاهی اوقات به جای ارث‌بری، ترکیب (Composition) گزینه بهتریه، مخصوصاً اگه رابطه “شامل یک” (Has-A relationship) باشه. مثلاً “یک ماشین شامل یک موتور است” (نه “یک موتور، یک نوع ماشین است”). انتخاب بین ارث‌بری و ترکیب یکی از چالش‌های طراحی شی‌گراست.

عیب‌یابی سریع: مشکلات رایج در ارث‌بری پایتون و راه‌حل‌ها

خب، رفیق! ارث‌بری خیلی کاربردیه، ولی گاهی اوقات ممکنه به مشکلاتی بربخوری. بیا چندتا از رایج‌ترینشون رو بررسی کنیم و ببینیم چطور میشه ازشون سر درآورد:

مشکل ۱: فراموشی فراخوانی super().__init__()

سناریو: کلاس فرزندت رو می‌سازی، اما متد __init__ کلاس والد رو فراخوانی نمی‌کنی. نتیجه‌اش میشه اینکه صفات تعریف شده توی والد، توی کلاس فرزند مقداردهی نمیشن و با `AttributeError` مواجه میشی.

راه‌حل: همیشه، اگه کلاس والد متد __init__ داره و نیاز به مقداردهی اولیه داره، توی سازنده کلاس فرزندت super().__init__(...) رو فراخوانی کن.


class والد:
    def __init__(self, x):
        self.x = x

class فرزند(والد):
    def __init__(self, x, y):
        # super().__init__(x) # فراموش شده!
        self.y = y

# مشکل ساز:
# f = فرزند(10, 20)
# print(f.x) # AttributeError: 'فرزند' object has no attribute 'x'

# راه‌حل درست:
class فرزند_درست(والد):
    def __init__(self, x, y):
        super().__init__(x) # حتماً اینو بنویس!
        self.y = y

f_correct = فرزند_درست(10, 20)
print(f_correct.x) # خروجی: 10
        

مشکل ۲: درک نکردن MRO در چندارث‌بری

سناریو: توی چندارث‌بری، اگه چندین والد متدی با نام یکسان داشته باشن، ممکنه ندونی پایتون کدوم رو فراخوانی می‌کنه. این می‌تونه منجر به رفتارهای غیرمنتظره بشه.

راه‌حل: همیشه از ClassName.__mro__ یا ClassName.mro() استفاده کن تا ترتیب جستجوی پایتون رو بفهمی. پایتون متدها رو به ترتیب MRO جستجو می‌کنه و اولین متدی که پیدا کنه رو فراخوانی می‌کنه.


class A:
    def greet(self): return "سلام از A"
class B(A):
    def greet(self): return "سلام از B"
class C(A):
    def greet(self): return "سلام از C"
class D(B, C):
    pass

d_obj = D()
print(D.__mro__)
# خروجی: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
print(d_obj.greet()) # با توجه به MRO، B قبل از C میاد.
# خروجی: سلام از B
        

مشکل ۳: سوء استفاده از ارث‌بری به جای ترکیب

سناریو: گاهی اوقات توسعه‌دهنده‌ها بدون اینکه رابطه “Is-A” برقرار باشه، از ارث‌بری استفاده می‌کنن. مثلاً اگه “یک ماشین شامل یک موتور است” (Has-A)، نباید موتور رو از ماشین به ارث برد. این کار باعث میشه سلسله‌مراتب کلاس‌ها غیرمنطقی و شکننده بشن.

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


# مثال غلط (ارث‌بری نامناسب):
# class موتور:
#     def استارت(self): return "موتور روشن شد"
# class ماشین(موتور): # غلط: ماشین یک نوع موتور نیست!
#     def حرکت(self): return f"{self.استارت()} و ماشین حرکت کرد."

# راه‌حل درست با ترکیب:
class موتور:
    def استارت(self): return "موتور روشن شد"

class ماشین:
    def __init__(self):
        self.موتور = موتور() # ترکیب: ماشین یک موتور دارد (Has-A)

    def حرکت(self):
        return f"{self.موتور.استارت()} و ماشین حرکت کرد."

my_car = ماشین()
print(my_car.حرکت())
# خروجی: موتور روشن شد و ماشین حرکت کرد.
        

پرسش‌های متداول (FAQ) درباره ارث‌بری در پایتون

آیا پایتون از چندارث‌بری پشتیبانی می‌کند؟

بله، پایتون به طور کامل از چندارث‌بری پشتیبانی می‌کند. یعنی یک کلاس می‌تواند از چندین کلاس والد به صورت همزمان ارث ببرد.

MRO چیست و چرا مهمه؟

MRO (Method Resolution Order) ترتیبی است که پایتون متدها و صفات را در سلسله‌مراتب ارث‌بری جستجو می‌کند. این ترتیب مخصوصاً در چندارث‌بری حیاتی است تا از ابهامات جلوگیری کند و تضمین کند متد صحیح فراخوانی می‌شود.

آیا super() همیشه به کلاس والد مستقیم اشاره می‌کند؟

نه دقیقاً! super() به کلاس والد مستقیم اشاره نمی‌کند، بلکه به کلاس بعدی در MRO (Method Resolution Order) اشاره می‌کند. این تفاوت در چندارث‌بری خودش رو نشون میده و باعث انعطاف‌پذیری بیشتر میشه.

تفاوت بین ارث‌بری و ترکیب (Composition) چیست؟

ارث‌بری رابطه “Is-A” (یک نوع از) را نشان می‌دهد، مثلاً “سگ، یک نوع حیوان است”. ترکیب رابطه “Has-A” (شامل یک) را نشان می‌دهد، مثلاً “ماشین، شامل یک موتور است”. باید بر اساس منطق رابطه‌ای که بین کلاس‌ها وجود دارد، انتخاب کنی.

آیا میشه از متدها و صفات خصوصی (Private) کلاس والد در کلاس فرزند استفاده کرد؟

در پایتون، مفهوم “کاملاً خصوصی” مثل بعضی زبان‌ها وجود نداره. با این حال، صفات و متدهای پیشوندی با دو آندرسکور (__) برای “نام‌پردازش (name mangling)” استفاده می‌شوند که دسترسی مستقیم به آن‌ها از خارج از کلاس رو سخت‌تر می‌کنه و به عنوان یک قرارداد برای خصوصی بودن تلقی میشه. اما همچنان می‌شه به روش‌هایی به اون‌ها دسترسی پیدا کرد، هرچند معمولاً توصیه نمیشه.

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

برای دیدن اسنیپت‌ها و کدهای آماده پایتون، اینجا کلیک کن و برای کدهای CSS، اینجا. همچنین می‌تونی به بخش کلی اسنیپت‌های ما یا حتی اسنیپت‌های مربوط به وردپرس سر بزنی.
ما کلی کد و راهنمایی برای HTML و JS هم داریم که می‌تونی از اسنیپت‌های HTML و اسنیپت‌های JS استفاده کنی.

کدنویسیت پر از خلاقیت!

Table of Contents

آخرین نوشته‌ها