PythonPython · Chapterبەش 11 · Lectureوانە 11.2
Attributes and Methodsخەسڵەتەکان و میتۆدەکان
Instance attributes and class attributes, shadowing and the shared-list trap; instance methods that change an object or return a value; __str__ and __repr__; comparing objects with __eq__ and __hash__; special methods such as __len__; class methods and static methods with @classmethod and @staticmethod; and a small school program with Student, Teacher and Course classes.
و ، و تەڵەی لیستی هاوبەش؛ کە دەگۆڕن یان دەگەڕێننەوە؛ __str__ و __repr__؛ بەراوردکردنی بە __eq__ و __hash__؛ وەک __len__؛ و ستاتیک بە @classmethod و @staticmethod؛ و بچووکی قوتابخانە بە Student، Teacher و Course.
What you will learnچی فێر دەبیت
- Tell instance attributes from class attributes, change class attributes through the class, and avoid shadowing and shared lists.
- Write instance methods that check and change an object's state or return a value.
- Write
__str__and__repr__, and know which calls use each. - Define equality with
__eq__(and a matching__hash__), and tell==fromis. - Use
@classmethodfor alternative constructors and@staticmethodfor helpers, and choose the right kind of method. - Read and extend a small program in which several classes work together.
- لە جیا بکەیتەوە، لە ڕێگەی بگۆڕیت و خۆت لە و لیستی هاوبەش بپارێزیت.
- بنووسیت کە دۆخی بپشکنن و بگۆڕن یان بگەڕێننەوە.
__str__و__repr__بنووسیت و بزانیت کام بانگکردنەکان هەریەکەیان بەکار دەهێنن.- یەکسانی بە
__eq__(و__hash__ـێکی گونجاو) پێناسە بکەیت و==لەisجیا بکەیتەوە. @classmethodبۆ جێگرەوە و@staticmethodبۆ یارمەتیدەر بەکار بهێنیت و جۆری گونجاوی هەڵبژێریت.- بچووک بخوێنیتەوە و فراوانی بکەیت کە تێیدا چەند پێکەوە کار دەکەن.
What an object knows and what it can doئۆبجێکتێک چی دەزانێت و دەتوانێت چی بکات
An object knows things, its attributes, and can do things, its methods. The last lesson, Classes and objects, made both with self. This lesson looks closer: attributes that belong to each object or to the whole class, methods that change an object or answer a question, the special methods Python calls by itself, and two more kinds of methods. All examples come from one small school with students, teachers and courses.
شت دەزانێت (ئەمانە ) و دەتوانێت شت بکات (ئەمانە ). وانەی پێشوو، کلاسەکان و ئۆبجێکتەکان، هەردووکیانی بە self دروست کرد. ئەم وانەیە نزیکتر سەیر دەکات: ئەو هی هەر یان هی هەموو ، ئەو دەگۆڕن یان وەڵامی پرسیارێک دەدەنەوە، ئەو خۆی بانگیان دەکات () و دوو جۆری تری . هەموو نموونەکان لە قوتابخانەیەکی بچووکەوە دێن کە قوتابی، مامۆستا و کۆرسی هەیە.
Instance attributes and class attributesخەسڵەتەکانی نموونە و خەسڵەتەکانی کلاس
An attribute written in the class body, outside every method, is a class attribute: it belongs to the class, and all its objects share one copy. Attributes made with self. are instance attributes: each object has its own.
کە لە لاشەی ، لە دەرەوەی هەموو ، نووسراوە : هی و هەموو یەک کۆپی بەش دەکەن. ئەو بە self. دروست دەکرێن ن: هەر هی خۆی هەیە.
class Student:
school = "Azadi School" # class attribute: one copy for all
def __init__(self, name, grade):
self.name = name # instance attributes: one per object
self.grade = grade
aram = Student("Aram", 10)
shilan = Student("Shilan", 11)
print(aram.school)
print(shilan.school)
print(Student.school)
print(vars(aram)) # school is not stored in the objectAzadi School
Azadi School
Azadi School
{'name': 'Aram', 'grade': 10}Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 2
Written once, in the class body: a class attribute.
یەک جار لە لاشەی نووسراوە: .
school is not in vars(aram), yet aram.school works. When you read aram.school, Python looks in the object first and, if the name is not there, in its class. The animation shows the search, and what happens when neither has the name.
school لە vars(aram)ـدا نییە، بەڵام aram.school کار دەکات. کاتێک aram.school دەخوێنیتەوە، سەرەتا لە دەگەڕێت و ئەگەر ناوەکە لەوێ نەبوو، لە . ئەنیمەیشنەکە گەڕانەکە پیشان دەدات و ئەوەی ڕوو دەدات کاتێک هیچیان ناوەکەیان نییە.


Instance attributes and class attributesخەسڵەتەکانی نموونە و خەسڵەتەکانی کلاس
Change a class attribute through the classخەسڵەتێکی کلاس لە ڕێگەی کلاسەکەوە بگۆڕە
Change a class attribute through the class, and every object sees the new value. Assigning through an object does something else: it makes a new instance attribute with the same name, which hides the class attribute for that object only:
لە ڕێگەی بگۆڕە و هەموو نوێیەکە دەبینێت. دانانی لە ڕێگەی کارێکی تر دەکات: نوێ بە هەمان ناو دروست دەکات کە تەنیا بۆ ئەو دەشارێتەوە:
class Student:
school = "Azadi School"
def __init__(self, name):
self.name = name
aram = Student("Aram")
shilan = Student("Shilan")
Student.school = "Azadi High School" # change it on the class
print(aram.school, "|", shilan.school)
aram.school = "Rozh School" # makes a NEW instance attribute
print(aram.school, "|", shilan.school, "|", Student.school)
print(vars(aram))
del aram.school # remove it: the class value shows again
print(aram.school)Azadi High School | Azadi High School
Rozh School | Azadi High School | Azadi High School
{'name': 'Aram', 'school': 'Rozh School'}
Azadi High SchoolAfter aram.school = "Rozh School", Aram has his own school while the others still read the class's value. del aram.school removed Aram's copy, so the class value showed again. This hiding is called shadowing. Read class attributes through objects if you like, but change them through the class.
دوای aram.school = "Rozh School"، ئارام schoolـی خۆی هەیە و ئەوانی تر هێشتا دەخوێننەوە. del aram.school کۆپییەکەی ئارامی لابرد، بۆیە دووپاتە دەرکەوتەوە. بەم شاردنەوەیە دەگوترێت . ئەگەر دەتەوێت لە ڕێگەی بخوێنەوە، بەڵام لە ڕێگەی بیانگۆڕە.
Instance attributes and class attributesخەسڵەتەکانی نموونە و خەسڵەتەکانی کلاس
A class attribute as a counterخەسڵەتێکی کلاس وەک ژمێرەر
A class attribute is the place for facts about the whole class, such as how many students exist. __init__ adds one to Student.count each time an object is made:
شوێنی ئەو زانیاریانەیە کە لەبارەی هەموو ، وەک ئەوەی چەند قوتابی هەیە. __init__ هەر جارێک دروست دەکرێت یەک بۆ Student.count زیاد دەکات:
class Student:
count = 0 # how many Student objects exist
def __init__(self, name):
self.name = name
Student.count += 1 # change the CLASS attribute
aram = Student("Aram")
shilan = Student("Shilan")
karwan = Student("Karwan")
print(Student.count, aram.count)3 3
Write Student.count += 1, not self.count += 1. The second reads 0 from the class and then assigns to self.count, which makes an instance attribute in every object, while the class counter stays at 0:
Student.count += 1 بنووسە، نەک self.count += 1. دووەمیان 0 لە دەخوێنێتەوە و پاشان دادەنێت بۆ self.count، کە لە هەموو دروست دەکات، لە کاتێکدا لە 0 دەمێنێتەوە:
class Student:
count = 0
def __init__(self, name):
self.name = name
self.count += 1 # reads 0 from the class, writes a NEW attribute
aram = Student("Aram")
shilan = Student("Shilan")
print(Student.count, aram.count, shilan.count)0 1 1
self.count += 1 makes one counter per object. لە ڕێگەی بگۆڕە؛ self.count += 1 بۆ هەر دروست دەکات.CêITInstance methods: actions on one objectمیتۆدەکانی نموونە: کار لەسەر یەک ئۆبجێکت
An instance method is an ordinary method with self first. Extra parameters come after self, and the call fills them from left to right: in aram.add_mark(72), self is aram and mark is 72. Inside, self. reaches this object's attributes:
ئاساییە بە self لە پێشەوە. زیاتر دوای self دێن و بانگکردنەکە لە چەپەوە بۆ ڕاست پڕیان دەکاتەوە: لە aram.add_mark(72)ـدا، self aramـە و mark 72ـە. لە ناوەوە، self. دەگاتە ئەم :
class Student:
def __init__(self, name):
self.name = name
self.marks = []
def add_mark(self, mark):
self.marks.append(mark)
def average(self):
return sum(self.marks) / len(self.marks)
aram = Student("Aram")
aram.add_mark(72)
aram.add_mark(48)
aram.add_mark(90)
print(aram.marks)
print(aram.average())[72, 48, 90] 70.0
add_mark() changes the object: it appends to the object's own list. average() reads the object and returns a number. These two kinds of methods, changing and answering, appear in almost every class.
add_mark() دەگۆڕێت: بۆ لیستی تایبەتی زیاد دەکات. average() دەخوێنێتەوە و ژمارەیەک دەگەڕێنێتەوە. ئەم دوو جۆرە ، گۆڕین و وەڵامدانەوە، لە نزیکەی هەموو دەردەکەون.
self; the argument in the brackets fills mark.ئەو پێش خاڵەکەیە self پڕ دەکاتەوە؛ ئەو لە ناو کەوانەکەدایە mark پڕ دەکاتەوە.CêITInstance methods: actions on one objectمیتۆدەکانی نموونە: کار لەسەر یەک ئۆبجێکت
Methods that guard the objectئەو میتۆدانەی ئۆبجێکتەکە دەپارێزن
The values of an object's attributes at one moment are its state. A method that changes the state is a good place to check the new value first. If it is wrong, raise an exception, so the object never holds a bad value:
لە هەر ساتێکدا، دۆخی ئەو پێک دەهێنن. کە دۆخەکە دەگۆڕێت شوێنێکی باشە بۆ ئەوەی سەرەتا نوێیەکە بپشکنێت. ئەگەر هەڵە بوو، هەڵاوێردەیەک دروست بکە، بۆ ئەوەی هەرگیز خراپ هەڵنەگرێت:
class Student:
def __init__(self, name):
self.name = name
self.marks = []
def add_mark(self, mark):
if not 0 <= mark <= 100: # protect the object's state
raise ValueError(f"a mark must be 0-100, not {mark}")
self.marks.append(mark)
aram = Student("Aram")
aram.add_mark(72)
print(aram.marks)
aram.add_mark(720) # a typing slip: 720 instead of 72
print(aram.marks)[72]
Traceback (most recent call last):
File "methods_validation.py", line 14, in <module>
aram.add_mark(720) # a typing slip: 720 instead of 72
~~~~~~~~~~~~~^^^^^
File "methods_validation.py", line 8, in add_mark
raise ValueError(f"a mark must be 0-100, not {mark}")
ValueError: a mark must be 0-100, not 720Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 7-8
Check first, change after: a wrong mark stops here and is never appended.
سەرەتا بپشکنە، پاشان بگۆڕە: نمرەی هەڵە لێرە دەوەستێت و هەرگیز زیاد ناکرێت.
The typing slip 720 was refused with a ValueError, and Aram's marks stayed [72]. Other code could still write aram.marks.append(720) directly, because Python trusts programmers; how to protect attributes better is in the next lesson, Encapsulation and properties.
هەڵە نووسینەکەی 720 بە ValueError ڕەت کرایەوە و نمرەکانی ئارام لە [72] مانەوە. کۆدی تر هێشتا دەتوانێت ڕاستەوخۆ aram.marks.append(720) بنووسێت، چونکە متمانە بە دەکات؛ چۆن باشتر بپارێزیت لە وانەی داهاتوودایە: کەپسوولکردن و تایبەتمەندییەکان.
Instance methods: actions on one objectمیتۆدەکانی نموونە: کار لەسەر یەک ئۆبجێکت
Methods that return a valueئەو میتۆدانەی نرخێک دەگەڕێننەوە
A method that answers a question should return the answer, so the caller can print it, compare it or use it in another calculation. A method can call another method of the same object through self:
کە وەڵامی پرسیارێک دەداتەوە دەبێت وەڵامەکە بگەڕێنێتەوە، بۆ ئەوەی بتوانێت چاپی بکات، بەراوردی بکات یان لە ژماردنێکی تردا بەکاری بهێنێت. دەتوانێت لە ڕێگەی selfـەوە تری هەمان بانگ بکات:
class Student:
pass_mark = 50
def __init__(self, name):
self.name = name
self.marks = []
def add_mark(self, mark):
self.marks.append(mark)
def average(self):
if not self.marks: # no marks yet: avoid dividing by 0
return 0.0
return sum(self.marks) / len(self.marks)
def has_passed(self):
return self.average() >= self.pass_mark # a method using a method
def report(self):
print(f"{self.name}: {self.average():.1f}") # prints, returns None
aram = Student("Aram")
print(aram.average(), aram.has_passed())
for m in [72, 48, 90]:
aram.add_mark(m)
print(aram.average(), aram.has_passed())
result = aram.report()
print(result)0.0 False 70.0 True Aram: 70.0 None
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 12-13
No marks yet: return 0.0 instead of dividing by zero.
هێشتا نمرە نییە: لەبری دابەشکردن بەسەر سفردا 0.0 بگەڕێنەوە.
- Lineدێڕی 17
self.average()calls another method of the same object.self.average()تری هەمان بانگ دەکات.
report() only prints, so it returns None: fine for a report, wrong for a value you need later (return or print?). has_passed() reads the class attribute pass_mark through self, which finds it in the class.
report() تەنیا چاپ دەکات، بۆیە None دەگەڕێنێتەوە: بۆ ڕاپۆرت باشە، بەڵام بۆ کە دواتر پێویستت دەبێت هەڵەیە (return یان print؟). has_passed() pass_mark لە ڕێگەی selfـەوە دەخوێنێتەوە کە لە دەیدۆزێتەوە.
__str__ and __repr__: how an object shows itself__str__ و __repr__: ئۆبجێکتێک چۆن خۆی پیشان دەدات
Two special methods turn an object into text. __str__ gives a friendly text for people: print(), str() and f-strings use it. __repr__ gives an exact text for programmers: repr(), the Python shell and lists of objects use it. A good __repr__ looks like the code that makes the object:
دوو دەکەنە دەق. __str__ دەقێکی ڕوون بۆ خەڵک دەدات: print()، str() و بەکاری دەهێنن. __repr__ دەقێکی ورد بۆ دەدات: repr()، شێڵی و بەکاری دەهێنن. __repr__ـێکی باش وەک ئەو کۆدە دەردەکەوێت کە دروست دەکات:
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __str__(self): # for people: print(), str(), f-strings
return f"{self.name} (grade {self.grade})"
def __repr__(self): # for programmers: repr(), lists, the shell
return f"Student({self.name!r}, {self.grade})"
aram = Student("Aram", 10)
print(aram)
print(f"Top student: {aram}")
print(repr(aram))
print([aram, Student("Dilan", 12)])Aram (grade 10)
Top student: Aram (grade 10)
Student('Aram', 10)
[Student('Aram', 10), Student('Dilan', 12)]Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 10
!rwrites the value withrepr(), so the name keeps its quotes:'Aram'.!rبەrepr()دەنووسێت، بۆیە ناوەکە کەوانەکانی دەمێنێت:'Aram'.
A list shows its items with __repr__, which is why the last line shows Student('Aram', 10). If a class has only __repr__, print() uses it as well, so when you write only one, write __repr__. Both must return a string.
دانەکانی بە __repr__ پیشان دەدات، بۆیە دوا دێڕ Student('Aram', 10) پیشان دەدات. ئەگەر تەنیا __repr__ـی هەبێت، print()ـیش ئەوە بەکار دەهێنێت، بۆیە ئەگەر تەنیا یەکێکیان دەنووسیت، __repr__ بنووسە. هەردووکیان دەبێت بگەڕێننەوە.
__str__ and which use __repr__.کام بانگکردنەکان __str__ بەکار دەهێنن و کامیان __repr__.CêITComparing objects: == and __eq__بەراوردکردنی ئۆبجێکتەکان: == و __eq__
Without help, == between two of your objects asks the same as is: are they one object? So two objects made from the same typed-in data are not equal (as in the last lesson). Teach the class what equal means with __eq__. Here two students are equal when their student numbers match:
بەبێ یارمەتی، == لە نێوان دوو خۆتدا هەمان پرسیاری is دەکات: ئایا یەک ؟ بۆیە دوو کە لە هەمان نووسراو دروست کراون یەکسان نین (وەک وانەی پێشوو). بە __eq__ فێری بکە یەکسان واتای چییە. لێرەدا دوو قوتابی یەکسانن کاتێک ژمارەی قوتابییان وەک یەک بێت:
class Student:
def __init__(self, student_id, name):
self.student_id = student_id
self.name = name
def __eq__(self, other):
if not isinstance(other, Student):
return NotImplemented # "I cannot compare with that"
return self.student_id == other.student_id
a = Student(1021, "Aram")
b = Student(1021, "Aram") # the same student, typed in twice
c = Student(1034, "Shilan")
print(a == b, a is b)
print(a == c, a != c)
print(a == "Aram")
print(b in [c, a]) # in uses == tooTrue False False True False True
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 7-8
For other types return
NotImplemented: Python then tries the other side and finally answersFalse.بۆ جۆرەکانی تر
NotImplementedبگەڕێنەوە: پاشان لایەکەی تر تاقی دەکاتەوە و لە کۆتاییداFalseدەڵێت.
a == b is now True while a is b stays False: equal, but two objects. != and in use __eq__ too, so b in [c, a] finds Aram.
ئێستا a == b Trueـە، لە کاتێکدا a is b هێشتا Falseـە: یەکسانن، بەڵام دوو . != و inـیش __eq__ بەکار دەهێنن، بۆیە b in [c, a] ئارام دەدۆزێتەوە.
== asks "equal?" through __eq__; is asks "the same object?".== لە ڕێگەی __eq__ـەوە دەپرسێت «یەکسانن؟»؛ is دەپرسێت «هەمان ؟».CêITComparing objects: == and __eq__بەراوردکردنی ئۆبجێکتەکان: == و __eq__
Equal objects in sets and dictionariesئۆبجێکتی یەکسان لە کۆمەڵەکان و فەرهەنگەکاندا
Sets and dictionary keys find items by a hash number. A class that defines __eq__ but no __hash__ cannot be put in a set at all:
و دانەکان بە ژمارەیەکی هاش دەدۆزنەوە. کە __eq__ پێناسە دەکات، بەڵام __hash__ نا، هەرگیز ناتوانرێت بخرێتە ناو :
__eq__ بێ __hash__eq_hash.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسەclass Student:
def __init__(self, student_id, name):
self.student_id = student_id
self.name = name
def __eq__(self, other):
if not isinstance(other, Student):
return NotImplemented
return self.student_id == other.student_id
a = Student(1021, "Aram")
b = Student(1021, "Aram")
print({a, b})Traceback (most recent call last):
File "eq_hash.py", line 13, in <module>
print({a, b})
^^^^^^
TypeError: unhashable type: 'Student'Python sets __hash__ to None in such a class, because equal objects must have equal hashes. Give the class a __hash__ built from the same value that __eq__ compares:
لەم جۆرە __hash__ دەکاتە None، چونکە یەکسان دەبێت هاشی یەکسانیان هەبێت. __hash__ـێک بدە بە کە لە هەمان دروست بکرێت کە __eq__ بەراوردی دەکات:
__hash__ـێکی گونجاوeq_hash_fixed.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسەclass Student:
def __init__(self, student_id, name):
self.student_id = student_id
self.name = name
def __eq__(self, other):
if not isinstance(other, Student):
return NotImplemented
return self.student_id == other.student_id
def __hash__(self): # equal students give the same hash
return hash(self.student_id)
a = Student(1021, "Aram")
b = Student(1021, "Aram")
c = Student(1034, "Shilan")
print(len({a, b, c}))
seats = {a: "row 1"}
print(seats[b]) # b finds a's seat: they are equal2 row 1
Aram is counted once in the set, and b finds the seat stored under a. Hash only values that never change: if a student's number could change, leave __hash__ out. More: what can be a key?
ئارام یەک جار لە دەژمێردرێت و b ئەو کورسییە دەدۆزێتەوە کە بە a هەڵگیراوە. تەنیا ئەو هاش بکە کە هەرگیز ناگۆڕێن: ئەگەر ژمارەی قوتابییەک بتوانێت بگۆڕێت، __hash__ مەنووسە. زیاتر: چی دەتوانێت ببێتە کلیل؟
Special methods: Python calls them for youمیتۆدە تایبەتەکان: Python بۆت بانگیان دەکات
Names with two underscores on each side are special methods, also called dunder methods (from double underscore). You write them, and Python calls them when your object meets an operator or a built-in function. Course below works with len() and print():
ئەو ناوانەی دوو هێڵی ژێرەوەیان لە هەر لایەکەوە هەیە ن کە پێیان دەگوترێت dunder (double underscore). تۆ دەیاننووسیت و کاتێک بەر یان دەکەوێت بانگیان دەکات. Courseـی خوارەوە لەگەڵ len() و print() کار دەکات:
class Course:
def __init__(self, title): # Course("Python 1")
self.title = title
self.students = []
def enrol(self, name):
self.students.append(name)
def __len__(self): # len(course)
return len(self.students)
def __str__(self): # print(course), str(course)
return f"{self.title}: {len(self)} students"
python = Course("Python 1")
python.enrol("Aram")
python.enrol("Hana")
print(len(python))
print(python)
print(python.__len__()) # what len() really calls2 Python 1: 2 students 2
Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 20
len(python)is reallypython.__len__().len(python)لە ڕاستیداpython.__len__()ـە.
There are special methods for operators too, such as __add__ for + and __lt__ for <; the data model lists them all. PEP 8 asks you never to invent new names of this shape: use only those Python documents.
بۆ هەن، وەک __add__ بۆ + و __lt__ بۆ <؛ بەڵگەنامەکانی Python هەموویانی لیست کردووە. PEP 8 داوات لێ دەکات هەرگیز ناوی نوێی بەم شێوەیە دامەهێنیت: تەنیا ئەوانە بەکار بهێنە کە ناساندوونی.
Class methods: @classmethod and clsمیتۆدەکانی کلاس: @classmethod و cls
Sometimes a method needs the class, not one object, most often to make objects in a second way. Mark it with the decorator @classmethod: a line starting with @ above def that changes how the method is called. Python then passes the class as the first parameter, named cls by convention. A class method that builds a student from a line of text is an alternative constructor:
هەندێک جار پێویستی بە هەیە، نەک بە یەک ، زۆربەی جار بۆ دروستکردنی بە ڕێگایەکی تر. بە @classmethod نیشانەی بکە: دێڕێک کە بە @ دەست پێ دەکات و لە سەرووی defـەوە دەنووسرێت و شێوەی بانگکردنی دەگۆڕێت. ئەو کاتە وەک یەکەم دەنێرێت کە بە ڕێککەوتن ناوی clsـە. کە قوتابییەک لە دێڕێکی دەق دروست دەکات جێگرەوەیە:
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
@classmethod
def from_line(cls, line): # an alternative constructor
name, grade = line.split(",")
return cls(name.strip(), int(grade))
def __repr__(self):
return f"Student({self.name!r}, {self.grade})"
rows = ["Aram, 10", "Shilan, 11", "Karwan, 10"] # lines from a text file
students = []
for row in rows:
students.append(Student.from_line(row))
print(students)[Student('Aram', 10), Student('Shilan', 11), Student('Karwan', 10)]Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 6-9
cls(...)is the same asStudent(...)here: it calls the class, and so__init__.cls(...)لێرەدا هەمانStudent(...)ـە: بانگ دەکات و بەمەش__init__.- Lineدێڕی 14
Lines like these come from a text file.
دێڕی وەک ئەمانە لە فایلێکی دەقییەوە دێن.
You call a class method on the class: Student.from_line(row). It returns a ready object, so the code that splits text stays out of __init__, and __init__ stays simple.
لەسەر خودی بانگ دەکەیت: Student.from_line(row). ئامادە دەگەڕێنێتەوە، بۆیە ئەو کۆدەی دەق دابەش دەکات لە دەرەوەی __init__ دەمێنێتەوە و __init__ سادە دەمێنێتەوە.
cls and can make objects with it. وەک cls وەردەگرێت و دەتوانێت پێ دروست بکات.CêITStatic methods: @staticmethodمیتۆدی ستاتیک: @staticmethod
A static method, marked @staticmethod, gets no automatic first parameter at all: no self and no cls. It is a plain helper function kept inside the class because it belongs to the class's topic, such as the rule for a valid mark. This class uses all three kinds:
ستاتیک، کە بە @staticmethod نیشانە دەکرێت، هیچ یەکەمی خۆکار وەرناگرێت: نە self و نە cls. یارمەتیدەری سادەیە کە لە ناو هێڵراوەتەوە چونکە سەر بە بابەتی ، وەک یاسای نمرەی دروست. ئەم هەر سێ جۆرەکە بەکار دەهێنێت:
class Student:
pass_mark = 50 # class attribute
def __init__(self, name, mark):
if not Student.is_valid_mark(mark):
raise ValueError(f"bad mark: {mark}")
self.name = name
self.mark = mark
def has_passed(self): # instance method: gets the object
return self.mark >= self.pass_mark
@classmethod
def set_pass_mark(cls, mark): # class method: gets the class
cls.pass_mark = mark
@staticmethod
def is_valid_mark(mark): # static method: gets nothing extra
return isinstance(mark, int) and 0 <= mark <= 100
print(Student.is_valid_mark(85), Student.is_valid_mark(120))
aram = Student("Aram", 55)
print(aram.has_passed())
Student.set_pass_mark(60) # a new rule for every student
print(aram.has_passed(), Student.pass_mark)True False True False 60
set_pass_mark() changes the class attribute through cls, so the new rule reaches every student at once: Aram's 55 is no longer a pass. In Java, one keyword, static, covers members that belong to the class: static members in Java.
set_pass_mark() لە ڕێگەی clsـەوە دەگۆڕێت، بۆیە یاسا نوێیەکە یەکسەر دەگاتە هەموو قوتابییەک: 55ـی ئارام چیتر دەرچوون نییە. لە یەک ، static، ئەو ئەندامانە دەگرێتەوە کە هی : ئەندامە ستاتیکەکان لە Java.
Static methods: @staticmethodمیتۆدی ستاتیک: @staticmethod
Which kind of method?کام جۆری میتۆد؟
Choose by what the method needs:
بەپێی ئەوەی پێویستی پێیەتی هەڵبژێرە:
| Kindجۆر | First parameterیەکەم | Called asبانگکردن | Use it whenکەی بەکاری بهێنیت |
|---|---|---|---|
| Instance method | self | aram.has_passed() | it reads or changes one object's attributes (most methods) یەک دەخوێنێتەوە یان دەیانگۆڕێت (زۆربەی ) |
Class method, @classmethod ، @classmethod | cls | Student.from_line(...) | it makes objects in another way or changes class attributesبە ڕێگایەکی تر دروست دەکات یان دەگۆڕێت |
Static method, @staticmethod ستاتیک، @staticmethod | noneهیچ | Student.is_valid_mark(85) | it needs neither, but belongs to the class's topicپێویستی بە هیچیان نییە، بەڵام سەر بە بابەتی |
When in doubt, write an instance method. A static method that has nothing to do with the class's topic is better as an ordinary function in a module.
ئەگەر دڵنیا نیت، بنووسە. ستاتیک کە هیچ پەیوەندییەکی بە بابەتی نییە باشترە ببێتە ئاسایی لە مۆدیوڵێکدا.
Worked program: a small schoolبەرنامەیەکی چارەسەرکراو: قوتابخانەیەکی بچووک
Now the pieces work together. A school has students, teachers and courses. Each class lives in a module of its own; people.py holds Student and Teacher:
ئێستا پارچەکان پێکەوە کار دەکەن. قوتابخانەیەک قوتابی، مامۆستا و کۆرسی هەیە. هەر لە مۆدیوڵێکی تایبەتدایە؛ people.py Student و Teacher هەڵدەگرێت:
class Student:
def __init__(self, student_id, name):
self.student_id = student_id
self.name = name
self.marks = {} # course title -> mark
def __repr__(self):
return f"Student({self.student_id}, {self.name!r})"
def __eq__(self, other):
if not isinstance(other, Student):
return NotImplemented
return self.student_id == other.student_id
def __hash__(self):
return hash(self.student_id)
class Teacher:
def __init__(self, name, subject):
self.name = name
self.subject = subject
def __str__(self):
return f"{self.name} ({self.subject})"Student keeps a dictionary of marks (course title → mark), shows itself exactly with __repr__, and is equal to another student with the same number; its __hash__ matches __eq__. Teacher needs only a friendly __str__. The class diagram shows how the three classes fit together.
Student نمرە هەڵدەگرێت (ناوی کۆرس ← نمرە)، بە __repr__ خۆی بە وردی پیشان دەدات و لەگەڵ قوتابییەکی تر کە هەمان ژمارەی هەبێت یەکسانە؛ __hash__ـەکەی لەگەڵ __eq__ دەگونجێت. Teacher تەنیا پێویستی بە __str__ـێکی ڕوون هەیە. پیشان دەدات سێ چۆن پێکەوە دەگونجێن.
Worked program: a small schoolبەرنامەیەکی چارەسەرکراو: قوتابخانەیەکی بچووک
The Course classکلاسی Course
course.py holds Course. A course has a teacher object and a list of student objects: objects inside an object.
course.py Course هەڵدەگرێت. کۆرسێک مامۆستا و قوتابی هەیە: لە ناو .
class Course:
seats = 3 # class attribute: the room's size
def __init__(self, title, teacher):
self.title = title
self.teacher = teacher # an object inside an object
self.students = []
def enrol(self, student):
if student in self.students: # uses Student.__eq__
return f"{student.name} is already in {self.title}"
if len(self.students) >= Course.seats:
return f"{self.title} is full"
self.students.append(student)
return f"{student.name} joined {self.title}"
def give_mark(self, student, mark):
if not Course.is_valid_mark(mark):
raise ValueError(f"a mark must be 0-100, not {mark}")
student.marks[self.title] = mark # the student object keeps it
@staticmethod
def is_valid_mark(mark):
return 0 <= mark <= 100
def __len__(self):
return len(self.students)
def __str__(self):
lines = [f"{self.title}, taught by {self.teacher}, {len(self)} students"]
for s in self.students:
lines.append(f" {s.name:<8}{s.marks.get(self.title, '-')}")
return "\n".join(lines)Explain the codeڕوونکردنەوەی کۆدەکە
- Lineدێڕی 10
incompares withStudent.__eq__, so a second object with the same number counts as the same student.inبەStudent.__eq__بەراورد دەکات، بۆیە دووەم بە هەمان ژمارە وەک هەمان قوتابی دەژمێردرێت.- Lineدێڕی 20
The mark is stored in the student object, so each student carries all their marks.
نمرەکە لە ناو قوتابییەکەدا هەڵدەگیرێت، بۆیە هەر قوتابییەک هەموو نمرەکانی خۆی هەڵدەگرێت.
enrol() returns a message in each case instead of printing it, so the caller decides what to do with it. give_mark() checks the mark with a static method before it stores anything.
enrol() لە هەموو حاڵەتێکدا پەیامێک دەگەڕێنێتەوە لەبری ئەوەی چاپی بکات، بۆیە بڕیار دەدات چی لێ بکات. give_mark() پێش هەڵگرتنی هەر شتێک نمرەکە بە ستاتیک دەپشکنێت.
enrol() before a student joins.دوو پشکنینەکەی enrol() پێش ئەوەی قوتابییەک بێتە ناو کۆرسەکە.CêITWorked program: a small schoolبەرنامەیەکی چارەسەرکراو: قوتابخانەیەکی بچووک
Running the schoolکارپێکردنی قوتابخانەکە
main.py imports the classes (ways to import) and uses them:
main.py هاوردە دەکات (شێوەکانی import) و بەکاریان دەهێنێت:
from people import Student, Teacher
from course import Course
hana = Teacher("Hana", "Computer Science")
python = Course("Python 1", hana)
aram = Student(1021, "Aram")
shilan = Student(1034, "Shilan")
karwan = Student(1040, "Karwan")
dilan = Student(1052, "Dilan")
for s in [aram, shilan, Student(1021, "Aram"), karwan, dilan]:
print(python.enrol(s))
python.give_mark(aram, 88)
python.give_mark(shilan, 94)
print(python)
print("Aram's marks:", aram.marks)
print(python.students)Aram joined Python 1
Shilan joined Python 1
Aram is already in Python 1
Karwan joined Python 1
Python 1 is full
Python 1, taught by Hana (Computer Science), 3 students
Aram 88
Shilan 94
Karwan -
Aram's marks: {'Python 1': 88}
[Student(1021, 'Aram'), Student(1034, 'Shilan'), Student(1040, 'Karwan')]The third enrolment is a new Student(1021, "Aram") object, but == says it is Aram, so he is not added twice. Dilan arrives when the 3 seats are taken. print(python) calls Course.__str__, which shows the teacher through Teacher.__str__; the last line shows the students through Student.__repr__.
تۆمارکردنی سێیەم نوێی Student(1021, "Aram")ـە، بەڵام == دەڵێت ئەوە ئارامە، بۆیە دوو جار زیاد ناکرێت. دیلان کاتێک دێت کە 3 کورسییەکە گیراون. print(python) Course.__str__ بانگ دەکات کە مامۆستای کۆرسەکە لە ڕێگەی Teacher.__str__ـەوە پیشان دەدات؛ دوا دێڕ قوتابییەکان لە ڕێگەی Student.__repr__ـەوە پیشان دەدات.
Common mistakesهەڵە باوەکان
Each mistake below was run with Python 3.13; the table shows what happened and the fix.
هەریەکە لەم هەڵانەی خوارەوە بە 3.13 تاقی کرایەوە؛ خشتەکە پیشان دەدات چی ڕوو دا و چارەسەرەکە چییە.
| Mistakeهەڵە | What happensچی ڕوو دەدات | Fixچارەسەر |
|---|---|---|
self.count += 1 for a class counterself.count += 1 بۆ | Each object gets count 1; Student.count stays 0هەر count 1 وەردەگرێت؛ Student.count لە 0 دەمێنێتەوە | Student.count += 1 |
marks = [] in the class bodymarks = [] لە لاشەی | All students share one listهەموو قوتابییەکان یەک لیست بەش دەکەن | self.marks = [] in __init__ |
__str__ that prints instead of returning__str__ـێک کە چاپ دەکات لەبری گەڕاندنەوە | TypeError: __str__ returned non-string (type NoneType) | return the textدەقەکە return بکە |
__eq__ without an isinstance() check__eq__ بێ پشکنینی isinstance() | AttributeError: 'str' object has no attribute 'student_id' | Return NotImplemented for other typesبۆ جۆرەکانی تر NotImplemented بگەڕێنەوە |
__eq__ without __hash__, then a set__eq__ بێ __hash__، پاشان | TypeError: unhashable type: 'Student' | Add a matching __hash____hash__ـێکی گونجاو زیاد بکە |
A helper with no self and no decorator, called through an objectیارمەتیدەرێک بێ self و بێ ، کە لە ڕێگەی بانگ دەکرێت | TypeError: Student.is_valid_mark() takes 1 positional argument but 2 were given | Add @staticmethod@staticmethod زیاد بکە |
| Changing a class attribute through an objectگۆڕینی لە ڕێگەی | Only that object changes (shadowing)تەنیا ئەو دەگۆڕێت () | Assign through the classلە ڕێگەی دابنێ |
Common mistakesهەڵە باوەکان
One more trap: a list as a default valueتەڵەیەکی تر: لیستێک وەک نرخی بنەڕەتی
The shared-list trap also hides in a default value. A default is made only once, when Python reads the def (defaults are made once), so every object made without marks shares that one list:
تەڵەی لیستی هاوبەش لە خۆی دەشارێتەوە. تەنیا یەک جار دروست دەکرێت، کاتێک defـەکە دەخوێنێتەوە (نرخی بنەڕەتی یەک جار دروست دەکرێت)، بۆیە هەموو ئەو بێ نمرە دروست دەکرێن ئەو یەک لیستە بەش دەکەن:
marks=[] وەک نرخی بنەڕەتی: هەڵەmistake_default_list.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسەclass Student:
def __init__(self, name, marks=[]): # the default list is made only once
self.name = name
self.marks = marks
aram = Student("Aram")
hana = Student("Hana")
aram.marks.append(90)
print(hana.marks)[90]
Hana got Aram's mark. Use None as the default and make a new list inside __init__; copying a list you were given with list(marks) also keeps the caller's list safe:
هانا نمرەکەی ئارامی وەرگرت. None وەک بەکار بهێنە و لە ناو __init__ـدا لیستێکی نوێ دروست بکە؛ کۆپیکردنی ئەو لیستەی پێت دراوە بە list(marks) لیستی دەپارێزێت:
marks=None و پاشان لیستێکی نوێ: ڕاستfixed_default_list.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسەclass Student:
def __init__(self, name, marks=None):
self.name = name
if marks is None:
marks = [] # a new list on every call
self.marks = list(marks) # and a copy of a list we were given
aram = Student("Aram")
hana = Student("Hana")
aram.marks.append(90)
print(aram.marks, hana.marks)[90] []
Exercisesڕاهێنانەکان
A Course has these attributes: the school's name, the number of seats in every room of the school, the course title, the teacher and the list of students. Which should be class attributes and which instance attributes? Write the class.
Course ئەم هەیە: ناوی قوتابخانەکە، ژمارەی کورسی لە هەموو پۆلێکی قوتابخانەکەدا، ناوی کۆرسەکە، مامۆستای کۆرسەکە و لیستی قوتابییەکان. کامیان دەبێت بن و کامیان ؟ بنووسە.
Show answerوەڵامەکە پیشان بدە
The school name and the seats are the same for every course: class attributes. The title, the teacher and the students differ for each course: instance attributes, and the list must be made in __init__.
ناوی قوتابخانە و کورسییەکان بۆ هەموو کۆرسێک وەک یەکن: . ناوی کۆرس، مامۆستا و قوتابییەکان بۆ هەر کۆرسێک جیاوازن: و دەبێت لیستەکە لە __init__ـدا دروست بکرێت.
class Course:
school = "Azadi School" # the same for every course
seats = 30 # every room in this school has 30 seats
def __init__(self, title, teacher):
self.title = title # different for each course
self.teacher = teacher
self.students = [] # a new list for each course
maths = Course("Maths", "Hana")
python = Course("Python 1", "Soran")
print(maths.school, maths.seats, maths.title, len(maths.students))
print(python.school, python.seats, python.title, python.teacher)Azadi School 30 Maths 0 Azadi School 30 Python 1 Soran
Without running it, write down what this program prints.
بەبێ کارپێکردنی، بنووسە ئەم چی چاپ دەکات.
class Classroom:
capacity = 30
def __init__(self, name):
self.name = name
a = Classroom("10A")
b = Classroom("10B")
a.capacity = 25
Classroom.capacity = 32
print(a.capacity, b.capacity, Classroom.capacity)Show answerوەڵامەکە پیشان بدە
class Classroom:
capacity = 30
def __init__(self, name):
self.name = name
a = Classroom("10A")
b = Classroom("10B")
a.capacity = 25
Classroom.capacity = 32
print(a.capacity, b.capacity, Classroom.capacity)25 32 32
a.capacity = 25 made an instance attribute in a, which hides the class attribute: 25. Then the class attribute became 32, which b reads: 32, and Classroom.capacity is 32.
a.capacity = 25 لە aـدا دروست کرد کە دەشارێتەوە: 25. پاشان بوو بە 32 کە b دەیخوێنێتەوە: 32 و Classroom.capacity 32ـە.
__str__ و __repr__ بۆ TeacherGive the class Teacher(name, subject) a __str__ that returns "Hana teaches Maths" and a __repr__ that returns "Teacher('Hana', 'Maths')". Print one teacher, its repr() and a list of two teachers.
__str__ بدە بە Teacher(name, subject) کە "Hana teaches Maths" بگەڕێنێتەوە و __repr__ـێک کە "Teacher('Hana', 'Maths')" بگەڕێنێتەوە. مامۆستایەک، repr()ـەکەی و دوو مامۆستا چاپ بکە.
Hintئاماژە
Use !r inside the f-string of __repr__ so the names keep their quotes.
لە ناو __repr__ـدا !r بەکار بهێنە بۆ ئەوەی ناوەکان کەوانەکانیان بمێنێت.
Show answerوەڵامەکە پیشان بدە
class Teacher:
def __init__(self, name, subject):
self.name = name
self.subject = subject
def __str__(self):
return f"{self.name} teaches {self.subject}"
def __repr__(self):
return f"Teacher({self.name!r}, {self.subject!r})"
hana = Teacher("Hana", "Maths")
print(hana)
print(repr(hana))
print([hana, Teacher("Soran", "Physics")])Hana teaches Maths
Teacher('Hana', 'Maths')
[Teacher('Hana', 'Maths'), Teacher('Soran', 'Physics')]Add a class method Teacher.from_dict(data) that makes a teacher from a dictionary such as {"name": "Soran", "subject": "Physics"}.
Teacher.from_dict(data) زیاد بکە کە مامۆستایەک لە وەک {"name": "Soran", "subject": "Physics"} دروست بکات.
Show answerوەڵامەکە پیشان بدە
class Teacher:
def __init__(self, name, subject):
self.name = name
self.subject = subject
@classmethod
def from_dict(cls, data):
return cls(data["name"], data["subject"])
def __repr__(self):
return f"Teacher({self.name!r}, {self.subject!r})"
row = {"name": "Soran", "subject": "Physics"}
soran = Teacher.from_dict(row)
print(soran)Teacher('Soran', 'Physics')Add a method top_student() to Course that returns the student with the highest mark in this course, or None when nobody has a mark yet.
top_student() بۆ Course زیاد بکە کە ئەو قوتابییە بگەڕێنێتەوە کە بەرزترین نمرەی لەم کۆرسەدا هەیە، یان None کاتێک هێشتا کەس نمرەی نییە.
Show answerوەڵامەکە پیشان بدە
class Student:
def __init__(self, name):
self.name = name
self.marks = {} # course title -> mark
class Course:
def __init__(self, title):
self.title = title
self.students = []
def enrol(self, student):
self.students.append(student)
def give_mark(self, student, mark):
student.marks[self.title] = mark
def top_student(self):
best = None
for s in self.students:
if self.title not in s.marks:
continue # no mark yet in this course
if best is None or s.marks[self.title] > best.marks[self.title]:
best = s
return best
python = Course("Python 1")
print(python.top_student()) # no students yet
for name in ["Aram", "Shilan", "Karwan"]:
python.enrol(Student(name))
python.give_mark(python.students[0], 88)
python.give_mark(python.students[1], 94)
print(python.top_student().name)None Shilan
best starts as None. Students without a mark in this course are skipped with continue, so Karwan does not break the comparison.
best بە None دەست پێ دەکات. ئەو قوتابییانەی لەم کۆرسەدا نمرەیان نییە بە continue تێدەپەڕێنرێن، بۆیە کاروان بەراوردەکە تێک نادات.
Add a static method Course.is_valid_title(title) that is True when the title, without spaces at the ends, has 1 to 40 characters. Use it in __init__ to refuse a bad title with a ValueError.
ستاتیکی Course.is_valid_title(title) زیاد بکە کە True بێت کاتێک ناوەکە، بەبێ بۆشایی لە دوو سەرەکەیدا، 1 تا 40 بێت. لە __init__ـدا بەکاری بهێنە بۆ ڕەتکردنەوەی ناوێکی هەڵە بە ValueError.
Show answerوەڵامەکە پیشان بدە
class Course:
def __init__(self, title):
if not Course.is_valid_title(title):
raise ValueError(f"bad course title: {title!r}")
self.title = title.strip()
@staticmethod
def is_valid_title(title):
return 0 < len(title.strip()) <= 40
print(Course.is_valid_title("Python 1"), Course.is_valid_title(" "))
c = Course(" Python 1 ")
print(repr(c.title))
Course("")True False
'Python 1'
Traceback (most recent call last):
File "valid_title.py", line 14, in <module>
Course("")
~~~~~~^^^^
File "valid_title.py", line 4, in __init__
raise ValueError(f"bad course title: {title!r}")
ValueError: bad course title: ''Summaryپوختە
- Instance attributes (
self.xin__init__) belong to one object; class attributes (in the class body) are shared. Readingobj.xlooks in the object, then in the class. - Change class attributes through the class (
Student.count += 1); assigning through an object makes a new instance attribute (shadowing). Make lists in__init__, never in the class body or as a default. - Instance methods (
self) change an object or return an answer; check new values before changing the state. - Special methods are called by Python:
__str__(people),__repr__(programmers),__eq__(==,in),__hash__(sets, keys),__len__(len()). All__str__/__repr__must return strings. - A decorator line changes a method:
@classmethodpasses the class ascls(alternative constructors);@staticmethodpasses nothing extra (helpers). - Classes work together: a course has a teacher object and a list of student objects.
- (
self.xلە__init__ـدا) هی یەک ؛ (لە لاشەی ) هاوبەشن. خوێندنەوەیobj.xلە دەگەڕێت، پاشان لە . - لە ڕێگەی بگۆڕە (
Student.count += 1)؛ دانانی لە ڕێگەی نوێ دروست دەکات (). لیستەکان لە__init__ـدا دروست بکە، هەرگیز لە لاشەی یان وەک . - (
self) دەگۆڕن یان وەڵامێک دەگەڕێننەوە؛ پێش گۆڕینی دۆخ نوێ بپشکنە. - بانگیان دەکات:
__str__(خەڵک)،__repr__()،__eq__(==،in)،__hash__(، )،__len__(len()).__str__و__repr__دەبێت بگەڕێننەوە. - دێڕێکی دەگۆڕێت:
@classmethodوەکclsدەنێرێت ( جێگرەوە)؛@staticmethodهیچی زیادە نانێرێت (یارمەتیدەرەکان). - پێکەوە کار دەکەن: کۆرسێک مامۆستا و قوتابی هەیە.
Next: Encapsulation and properties protects attributes, and Inheritance and polymorphism builds classes from classes. Compare with Java in Python and Java.
داهاتوو: کەپسوولکردن و تایبەتمەندییەکان دەپارێزێت و بۆماوە و فرەشێوەیی لە دروست دەکات. بەراوردی بکە لەگەڵ لە Python و Java.
Lesson complete!وانەکە تەواو بوو!
Well done. Review the key terms, then go on to the next lesson.دەستخۆش. سەیرێکی زاراوە سەرەکییەکان بکەرەوە، پاشان بڕۆ بۆ وانەی داهاتوو.
Key termsزاراوە سەرەکییەکان
Encapsulation and Propertiesکەپسوولکردن و خەسڵەتە بەڕێوەبراوەکان
Related lecturesوانە پەیوەندیدارەکان
- Classes and Objectsکلاسەکان و ئۆبجێکتەکان
- Lists, References, Copies and Functionsلیستەکان، ئاماژەکان، کۆپی و کردارەکان
- Positional, Keyword and Default Argumentsئارگیومێنتە شوێنییەکان، ئارگیومێنتە ناودارەکان و نرخە بنەڕەتییەکان
- Return Values and Noneنرخە گەڕاوەکان و None
- Handling Errors with try and exceptمامەڵەکردن لەگەڵ هەڵاوێردە بە try و except
- Modules and importمۆدیوڵەکان و import
- Tuples, Sets and Dictionariesتاپڵەکان، کۆمەڵەکان و فەرهەنگەکان
- Reading and Writing Filesخوێندنەوە و نووسینی فایلەکان
- Classes and Objects: Attributes and Methodsکلاسەکان و ئۆبجێکتەکان: تایبەتمەندییەکان و میتۆدەکان
- Constructors, Modifiers and Encapsulationدروستکەرەکان، دیاریکەرەکان و کەپسوولکردن
- Python Next to JavaPython لە تەنیشت Javaـەوە
- Encapsulation and Propertiesکەپسوولکردن و خەسڵەتە بەڕێوەبراوەکان
- Inheritance and Polymorphismبۆماوە و فرەشێوەیی
References and further readingسەرچاوەکان و خوێندنەوەی زیاتر
- The Python Tutorial, chapter 9: Classes (9.3.5 class and instance variables, the shared tricks list; 9.4 random remarks, attribute lookup)
- Python Language Reference 3.3: Special method names (__repr__, __str__, rich comparisons, __hash__, __len__; classmethod and staticmethod objects)
- Python Library: built-in functions classmethod(), staticmethod(), isinstance(), repr()
- Python Glossary: class variable, decorator, method, special method, dunder
- PEP 8: Style Guide for Python Code (self and cls, never invent __dunder__ names)
- Harvard CS50's Introduction to Programming with Python, Lecture 8: Object-Oriented Programming (class methods, static methods, __str__)
This lecture is a first edition. The Kurdish text and terminology are waiting for review by Kurdish IT teachers.ئەم وانەیە چاپی یەکەمە. دەقە کوردییەکە و زاراوەکانی چاوەڕێی پێداچوونەوەی مامۆستایانی کوردی بواری IT ن.