Данас ћу писати о промењивим и функцијама у објектно-оријентисаном програмирању те њиховом додељивању класи или инстанци (објекту) класе.

У претходном примеру смо промењиве додељивали само инстанци, али то није увек случај. Некада нам је потребно да одређен атрибут буде константан за све објекте једне класе и тада користимо класне промењиве. Оне се дефинишу тако што их иницијализујемо на нивоу класе:

class Student:
    id = 0
    students = []

У овом случају смо на нивоу класе дефинисали две промењиве: id и students. Обе промењиве ће имати исту вредност било да јој приступамо преко класе или преко објекта. Ипак, најбољи начин приступања је преко имена класе:

Student.id
Student.students

Да се подсетимо, промењиве инстанце дефинишемо у __init__ методи (конструктору):

    def __init__(self, first_name, last_name, index_number, average_grade):
        # Постављамо јединствени ИД
        self.id = Student.id  # Обратите пажњу како приступамо класним промењивим
        # Увећавамо ИД
        Student.id += 1

        # Постављамо атрибуте
        self.first_name = first_name
        self.last_name = last_name
        self.index_number = index_number
        self.average_grade = average_grade

Овде смо управо искористили константност класних промењивих како бисмо увек добили јединствени id.

Ни са методама није велика разлика. Као што сам већ рекао, методе инстанце имају први параметар self. Пример је и __init__ метода изнад која користи self да би поставила вредности атрибута. Још један пример је метода __str__ помоћу које можемо дефинисати подразумевану конверзију нашег објекта у стринг. Пример употребе ове метода је приликом њеног позивања у print функцији. Уместо да се испише само референца ка објекту, биће исписано оно што је дефинисано __str__ методом:

class Student:
    id = 0
    students = []

    def __init__(self, first_name, last_name, index_number, average_grade):
        # Постављамо јединствени ИД
        self.id = Student.id  # Обратите пажњу како приступамо класним промењивим
        # Увећавамо ИД
        Student.id += 1

        # Постављамо атрибуте
        self.first_name = first_name
        self.last_name = last_name
        self.index_number = index_number
        self.average_grade = average_grade

    def __str__(self):
        # Редефинишемо шта ће се исписати када позовемо наш објекат у print функцији
        return f'{self.first_name} {self.last_name} (ИД: {self.id}): {self.average_grade}'

print(Student('Марко', 'Марковић', 'ИндексБр1', 6))

Испис:

Марко Марковић (ИД: 0): 6

Код класних метода разликујемо статичне и класне. staticmethod су везане за класу и могу бити без параметара. Пример статичне методе која рачуна студента са највећом просечном оценом:

@staticmethod
def get_student_with_biggest_grade():
    return max(Student.students, key=attrgetter('average_grade'))

classmethod су везане за класу, али као први параметар примају cls, што у ствари представља референцу на класу. Изнад можемо видети да у телу get_student_with_biggest_grade методе користимо класни атрибут students, тако да има више смисла користити classmethod:

@classmethod
def get_student_with_biggest_grade(cls):
    return max(cls.students, key=attrgetter('average_grade'))

У суштини статичне методе користимо када не употребљавамо класне атрибуте или методе, док у осталим случајевима боље је искористити classmethod.

Можда сте приметили да су примери повезани са претходним задатком, који сам задао у чланку Основе Python-а: Објектно-оријентисано програмирање. Ево и читавог решења: