Conținut curs
Python Avansat
Despre lecție
  1. Introducere în descriptori

    • Ce sunt descriptorii și de ce sunt utili
    • Exemple de descriptori în Python (property, staticmethod, classmethod, etc.)
    • Cum funcționează mecanismul descriptorilor
  2. Crearea unui descriptor simplu

    • Metodele descriptorilor: __get__, __set__ și __delete__
    • Exemplu: descriptor pentru validarea atributelor
    • Exercițiu: creați un descriptor pentru gestionarea atributelor numerice
  3. Crearea unui descriptor read-only

    • Cum să creați un descriptor care nu poate fi modificat
    • Exemplu: descriptor pentru calcularea ariei unui dreptunghi
    • Exercițiu: creați un descriptor pentru calcularea lungimii unui vector
  4. Crearea unui descriptor cu proprietăți avansate

    • Cum să adăugați proprietăți avansate la un descriptor
    • Exemplu: descriptor pentru gestionarea memoriei cache
    • Exercițiu: creați un descriptor pentru gestionarea versiunilor unui obiect
  5. Utilizarea descriptorilor în clase de bază și clase derivate

    • Cum să folosiți descriptori în clase de bază și clase derivate
    • Exemplu: descriptor pentru validarea atributelor într-o ierarhie de clase
    • Exercițiu: creați un descriptor pentru gestionarea atributelor într-o ierarhie de clase geometrice
  6. Descriptori și metode de clasă

    • Cum să creați descriptori care funcționează cu metode de clasă
    • Exemplu: descriptor pentru înregistrarea apelurilor la metode de clasă
    • Exercițiu: creați un descriptor pentru gestionarea log-urilor în metodele de clasă

Exemple și exerciții pentru fiecare subpunct:

Exemplu: descriptor pentru validarea atributelor

python
class ValidarePozitiv:
    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if value < 0:
            raise ValueError("Valoarea trebuie să fie pozitivă")
        instance.__dict__[self.name] = value

    def __set_name__(self, owner, name):
        self.name = name

class Numar:
    valoare = ValidarePozitiv()

n = Numar()
n.valoare = 5  # Funcționează corect
n.valoare = -2  # Ridică ValueError: Valoarea trebuie să fie pozitivă

Exercițiu:

Creați un descriptor pentru gestionarea atributelor numerice. Acest descriptor ar trebui să permită doar valori numerice și să ridice o excepție atunci când se încearcă atribuirea unei valori non-numerice.

Exemplu: descriptor pentru calcularea ariei unui dreptunghi

python
class Arie:
    def __get__(self, instance, owner):
        return instance.lungime * instance.latime

class Dreptunghi:
    def __init__(self, lungime, latime):
        self.lungime = lungime
        self.latime = latime

    arie = Arie()

d = Dreptunghi(4, 5)
print(d.arie)  # 20

Exercițiu:

Creați un descriptor pentru calcularea lungimii unui vector într-o clasă Vector. Acest descriptor ar trebui să fie read-only și să calculeze lungimea vectorului pe baza componentelor sale.

Exemplu: descriptor pentru gestionarea memoriei cache

python
class Cache:
    def __init__(self, func):
        self.func = func
        self.cache = {}

    def __get__(self, instance, owner):
        if instance not in self.cache:
            self.cache[instance] = self.func(instance)
        return self.cache[instance]

class Fibonacci:
    def __init__(self, n):
        self.n = n

    @Cache
    def fib(self):
        if self.n <= 1:
            return self.n
        f1 = Fibonacci(self.n - 1)
        f2 = Fibonacci(self.n - 2)
        return f1.fib + f2.fib

f = Fibonacci(10)
print(f.fib)  # 55

Exercițiu:

Creați un descriptor pentru gestionarea versiunilor unui obiect. Acest descriptor ar trebui să mențină o listă de versiuni anterioare ale obiectului și să permită accesarea acestora prin index.

Exemplu: descriptor pentru înregistrarea apelurilor la metode de clasă

python
class InregistrareApeluri:
    def __init__(self, func):
        self.func = func
        self.numar_apeluri = 0

    def __get__(self, instance, owner):
        self.numar_apeluri += 1
        return self.func.__get__(instance, owner)

class Exemplu:
    @classmethod
    def metoda(cls):
        print("Metoda apelată")

    metoda = InregistrareApeluri(metoda)

Exemplu.metoda()  # Metoda apelată
Exemplu.metoda()  # Metoda apelată
print(Exemplu.metoda.numar_apeluri)  # 2

Exercițiu:

Creați un descriptor pentru gestionarea log-urilor în metodele de clasă. Acest descriptor ar trebui să înregistreze fiecare apel la o metodă de clasă și să permită accesarea log-urilor prin metoda afisare_loguri().