کلاسها کمی نحو جدید، سه نوع شیء جدید و برخی معانی جدید معرفی میکنند.
سادهترین شکل تعریف کلاس این شکل است:
class ClassName:
.
.
.
تعریفهای کلاس، مانند تعریفهای تابع (دستورات def) باید قبل از اینکه هر اثری داشته باشند اجرا شوند. در عمل، عبارات داخل یک تعریف کلاس معمولاً تعریفهای تابع هستند، اما عبارات دیگر مجاز و گاهی مفید هستند.
وقتی وارد یک تعریف کلاس میشوید، فضای نام جدیدی ایجاد شده و به عنوان دامنه محلی استفاده میشود — بنابراین تمام اختصاصهای به متغیرهای محلی وارد این فضای نام جدید میشوند. به طور خاص، تعریفهای تابع نام تابع جدید را اینجا متصل میکنند.
وقتی یک تعریف کلاس به طور عادی (از طریق انتها) ترک شود، یک شیء کلاس ایجاد میشود. این در واقع یک بستهبندی دور محتوای فضای نام ایجاد شده توسط تعریف کلاس است. دامنه محلی اصلی بازسازی میشود و شیء کلاس در اینجا به نام کلاس داده شده در سربرگ تعریف کلاس متصل میشود.
اشیاء کلاس از دو نوع عملیات پشتیبانی میکنند: مراجعات ویژگی و نمونهسازی.
مراجعات ویژگی از نحو استاندارد مورد استفاده برای تمام مراجعات ویژگی در پایتون استفاده میکنند: obj.name. نامهای ویژگی معتبر تمام نامهایی هستند که در فضای نام کلاس هنگام ایجاد شیء کلاس وجود داشتند. پس اگر تعریف کلاس این شکل را داشته باشد:
class MyClass:
"""یک مثال ساده از کلاس"""
i = 12345
def f(self):
return 'hello world'
سپس MyClass.i و MyClass.f مراجعات ویژگی معتبر هستند که به ترتیب یک عدد صحیح و یک شیء تابع برمیگردانند. ویژگیهای کلاس همچنین میتوانند اختصاص داده شوند، بنابراین میتوانید مقدار MyClass.i را با اختصاص تغییر دهید. __doc__ نیز یک ویژگی معتبر است که رشته مستندات متعلق به کلاس را برمیگرداند: "یک مثال ساده از کلاس".
نمونهسازی کلاس از نماد تابع استفاده میکند. فقط فرض کنید شیء کلاس یک تابع بدون آرگومان است که یک نمونه جدید از کلاس برمیگرداند. به عنوان مثال (با فرض کلاس بالا):
x = MyClass()
یک نمونه جدید از کلاس ایجاد میکند و این شیء را به متغیر محلی x اختصاص میدهد.
عملیات نمونهسازی ("فراخوانی" یک شیء کلاس) یک شیء خالی ایجاد میکند. بسیاری از کلاسها دوست دارند اشیایی با نمونههای سفارشیشده برای یک حالت اولیه خاص ایجاد کنند. بنابراین یک کلاس میتواند یک متد ویژه به نام __init__() تعریف کند:
def __init__(self):
self.data = []
وقتی یک کلاس متد __init__() تعریف میکند، نمونهسازی کلاس به طور خودکار __init__() را برای نمونه جدید ایجاد شده فراخوانی میکند. پس در این مثال، یک نمونه جدید و مقداردهی اولیه شده میتواند با x = MyClass() به دست آید.
البته، متد __init__() میتواند برای انعطافپذیری بیشتر آرگومانهایی داشته باشد. در آن صورت، آرگومانهای داده شده به عملگر نمونهسازی کلاس به __init__() منتقل میشوند:
>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5)
حالا با اشیاء نمونه چه میتوانیم بکنیم؟ تنها عملیاتی که اشیاء نمونه درک میکنند مراجعات ویژگی هستند. دو نوع نام ویژگی معتبر وجود دارد: ویژگیهای داده و متدها.
ویژگیهای داده معادل «متغیرهای نمونه» در Smalltalk و «اعضای داده» در C++ هستند. ویژگیهای داده نیازی به اعلان ندارند؛ مانند متغیرهای محلی، وقتی برای اولین بار اختصاص داده شوند ظاهر میشوند. به عنوان مثال، اگر x نمونه MyClass ایجاد شده در بالا باشد، کد زیر مقدار 16 را چاپ میکند، بدون اینکه ردی بگذارد:
x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2
print(x.counter)
del x.counter
نوع دیگر مرجع ویژگی نمونه یک متد است. متد تابعی است که «تعلق به» یک شیء دارد.
نامهای متد معتبر یک شیء نمونه به کلاس آن بستگی دارد. طبق تعریف، تمام ویژگیهای کلاس که اشیاء تابع هستند متدهای متناظر نمونههای آن را تعریف میکنند. پس در مثال ما، x.f یک مرجع متد معتبر است، زیرا MyClass.f یک تابع است، اما x.i نیست، زیرا MyClass.i نیست. اما x.f همان چیزی نیست که MyClass.f — آن یک شیء متد است، نه یک شیء تابع.
معمولاً، یک متد درست بعد از اینکه متصل شود فراخوانی میشود:
x.f()
اگر x = MyClass() باشد، مانند بالا، این رشته 'hello world' را برمیگرداند. با این حال، لازم نیست یک متد را فوراً فراخوانی کنید: x.f یک شیء متد است و میتواند ذخیره شده و بعداً فراخوانی شود. به عنوان مثال:
xf = x.f
while True:
print(xf())
ادامه خواهد داد hello world را تا ابد چاپ کند.
دقیقاً چه اتفاقی میافتد وقتی یک متد فراخوانی شود؟ ممکن است متوجه شده باشید که x.f() بدون آرگومان فراخوانی شد، حتی اگر تعریف تابع برای f() یک آرگومان مشخص کرده بود. با آرگومان چه شد؟ مطمئناً پایتون وقتی تابعی که نیاز به آرگومان دارد بدون هیچ آرگومانی فراخوانی شود استثناء ایجاد میکند — حتی اگر آرگومان واقعاً استفاده نشود...
در واقع، ممکن است جواب را حدس زده باشید: چیز خاص درباره متدها این است که شیء نمونه به عنوان آرگومان اول تابع منتقل میشود. در مثال ما، فراخوانی x.f() دقیقاً معادل MyClass.f(x) است. به طور کلی، فراخوانی یک متد با لیستی از n آرگومان معادل فراخوانی تابع متناظر با لیستی از آرگومانهاست که با قرار دادن شیء نمونه متد قبل از آرگومان اول ایجاد شده است.
به طور کلی، متدها به شکل زیر عمل میکنند. وقتی به یک ویژگی غیرداده یک نمونه ارجاع داده شود، کلاس نمونه جستجو میشود. اگر نام یک ویژگی معتبر کلاس که یک شیء تابع است را نشان دهد، مراجعات به هم شیء نمونه و هم شیء تابع در یک شیء متد بستهبندی میشوند. وقتی شیء متد با لیستی از آرگومانها فراخوانی شود، لیستی جدید از شیء نمونه و لیست آرگومانها ساخته شده و شیء تابع با این لیست جدید فراخوانی میشود.
به طور کلی، متغیرهای نمونه برای دادههای منحصربفرد هر نمونه هستند و متغیرهای کلاس برای ویژگیها و متدهای مشترک بین تمام نمونههای کلاس هستند:
class Dog:
kind = 'canine' # متغیر کلاس مشترک بین تمام نمونهها
def __init__(self, name):
self.name = name # متغیر نمونه منحصربفرد برای هر نمونه
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind # مشترک بین تمام سگها
'canine'
>>> e.kind # مشترک بین تمام سگها
'canine'
>>> d.name # منحصربفرد برای d
'Fido'
>>> e.name # منحصربفرد برای e
'Buddy'
همانطور که در «چند کلمه درباره نامها و اشیاء» بحث شد، دادههای مشترک میتوانند تأثیرات ممکن است تعجبآوری شامل اشیاء تغییرپذیر مانند لیستها و دیکشنریها داشته باشند. به عنوان مثال، لیست tricks در کد زیر نباید به عنوان متغیر کلاس استفاده شود زیرا فقط یک لیست توسط تمام نمونههای Dog مشترک خواهد بود:
class Dog:
tricks = [] # استفاده اشتباه از متغیر کلاس
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # به طور غیرمنتظره مشترک بین تمام سگها
['roll over', 'play dead']
طراحی صحیح کلاس باید به جای آن از یک متغیر نمونه استفاده کند:
class Dog:
def __init__(self, name):
self.name = name
self.tricks = [] # یک لیست خالی جدید برای هر سگ ایجاد میکند
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://docs.python.org/3/tutorial