Nové výhodné predplatné namiesto kreditov je tu! Viac informácií. Upravili sme aj naše prevádzkové podmienky.
NOVINKA: Kurz Práca s umelou inteligenciou teraz už od 0 €. Staň sa žiadaným profesionálom. Zisti viac:

Diskusia – 13. diel - Statika v Pythone - Triedne atribúty

Späť

Upozorňujeme, že diskusie pod našimi online kurzmi sú nemoderované a primárne slúžia na získavanie spätnej väzby pre budúce vylepšenie kurzov. Pre študentov našich rekvalifikačných kurzov ponúkame možnosť priameho kontaktu s lektormi a študijným referentom pre osobné konzultácie a podporu v rámci ich štúdia. Toto je exkluzívna služba, ktorá zaisťuje kvalitnú a cielenú pomoc v prípade akýchkoľvek otázok alebo projektov.

Komentáre
Posledné komentáre sú v spodnej časti poslednej stránky.
Avatar
DarkCoder
Člen
Avatar
DarkCoder:2.12.2024 15:47

V článku správně uvádíte, že třídní atributy jsou sdílené mezi všemi instancemi třídy. Ale tato informace dost zaniká když ji nevypíchnete a neukážete praktický příklad.

Třídní atributy v Pythonu jsou atributy (neboli proměnné), které jsou přiřazeny samotné třídě, nikoli jejím instancím. To znamená, že všechny instance dané třídy sdílejí stejné hodnoty těchto atributů, protože jsou uloženy na úrovni třídy, nikoli na úrovni jednotlivých objektů.

Třídní atributy jsou definovány přímo v těle třídy, mimo jakékoliv metody. Jsou dostupné všem instancím této třídy a mohou být měněny jak zvenčí, tak i uvnitř třídy.

Příklad:

class Auto:
    # Třídní atribut
    pocet_kol = 4

    def __init__(self, model):
        # Instanční atribut
        self.model = model

# Vytvoření instancí
auto1 = Auto("Škoda")
auto2 = Auto("Toyota")

# Přístup k třídnímu atributu
print(auto1.pocet_kol)  # 4
print(auto2.pocet_kol)  # 4

# Změna třídního atributu
Auto.pocet_kol = 6
print(auto1.pocet_kol)  # 6
print(auto2.pocet_kol)  # 6

V tomto příkladu je pocet_kol třídním atributem. Když změníme hodnotu tohoto atributu v samotné třídě (Auto.pocet_kol = 6), změna se promítne do všech instancí této třídy.

K čemu slouží třídní atributy:
Sdílení dat mezi instancemi: Třídní atributy jsou ideální pro hodnoty, které mají být stejné pro všechny instance třídy, jako například počet kol pro třídu Auto.

Optimalizace paměti: Pokud máte hodnoty, které budou stejné pro všechny objekty, místo jejich ukládání do každé instance (což by bylo paměťově náročné), můžete je uložit jako třídní atribut. To znamená, že tato hodnota se nachází pouze na úrovni třídy a neexistuje její duplikace pro každou instanci.

Udržování globálních parametrů: Třídní atributy mohou sloužit pro uchování hodnot, které mají globální význam pro všechny instance třídy, např. konstanty, limity, konfigurace apod.

Rozdíl mezi instančními a třídními atributy:
Instanční atributy jsou specifické pro konkrétní objekt (instanci třídy). Tyto atributy jsou definovány uvnitř metody __init__ nebo jinými metodami a každá instance třídy má vlastní kopii těchto atributů.
Třídní atributy jsou sdílené mezi všemi instancemi třídy, což znamená, že pokud dojde k jejich změně, změní se pro všechny instance.

Příklad:

class Auto:
    # Třídní atribut
    pocet_kol = 4

    def __init__(self, model):
        # Instanční atribut
        self.model = model

# Vytvoření instancí
auto1 = Auto("Škoda")
auto2 = Auto("Toyota")

# Změna instančního atributu
auto1.model = "Audi"
print(auto1.model)  # "Audi"
print(auto2.model)  # "Toyota"

# Změna třídního atributu
Auto.pocet_kol = 6
print(auto1.pocet_kol)  # 6
print(auto2.pocet_kol)  # 6

V tomto případě jsou model a pocet_kol různými typy atributů – model je instanční atribut, který je specifický pro každou instanci, zatímco pocet_kol je třídní atribut, který je sdílen mezi všemi instancemi.

Pokud chceš sledovat, kolik instancí třídy bylo vytvořeno, můžeš použít třídní atribut, který se bude zvyšovat při každém vytvoření nové instance a snižovat při jejím zničení (pomocí metody __del__).

Příklad:

class Auto:
    # Třídní atribut pro uchovávání počtu instancí
    pocet_instanci = 0

    def __init__(self, model):
        self.model = model

        # Zvýšení počtu instancí při vytvoření nové instance
        Auto.pocet_instanci += 1

    def __del__(self):
        # Snížení počtu instancí při zničení instance
        Auto.pocet_instanci -= 1

# Vytvoření instancí
auto1 = Auto("Škoda")
auto2 = Auto("Toyota")

# Zobrazení počtu aktivních instancí
print(Auto.pocet_instanci)  # 2

# Zničení jedné instance
del auto1

# Zobrazení počtu aktivních instancí po zničení jedné instance
print(Auto.pocet_instanci)  # 1

Třídní atribut pocet_instanci je inicializován na hodnotu 0.
Když je vytvořena nová instance třídy Auto (v konstruktoru __init__), počet instancí se zvýší o 1 pomocí Auto.pocet_instanci += 1.
Při zničení instance (například pomocí del auto1) je metoda __del__ volána a počet instancí se sníží o 1.

Odpovedať
Jazyk C je jako formule. Můžete předjíždět ve 300 km/h. Každá drobná chyba vás ale nekompromisně pošle do zdi.
Avatar
Radek Feix
Člen
Avatar
Radek Feix:31.1.2025 17:27

POZOR! Dnešní lekce vám ukáže statiku, tedy
postupy, které v podstatě narušují objektový model. OOP je obsahuje jen pro
speciální případy a obecně platí, že vše jde napsat bez
statiky. Vždy musíme pečlivě zvážit, zda statiku opravdu
nutně potřebujeme. Obecné doporučení je statiku vůbec
NEPOUŽÍVAT. Proč to tady je? ještě dvě lekce. WTF

Avatar
Jan černý
Člen
Avatar
Jan černý:27.2.2025 17:17

když je na začátku napsáno nepoužívejte to! ale v předchozích lekcí to bylo běžně v kódech, bez vysvětlení. Pak relativně užitečné věci ke je vlastně super to použít na denní bázi.
z toho by byl jeden trochu zmaten tak používat nebo nepoužívat.

když jde kód napsat bez statiky jak se tedy bez statiky řeší to číslování a tvoření hesla ?

Editované
Avatar
DarkCoder
Člen
Avatar
Odpovedá na Jan černý
DarkCoder:27.2.2025 20:32

Sdělení o tom to nepoužívat naprosto ignoruj. Používání třídních atributů je v mnoha ohledech výhodné. Ať už sdílení nějaké konfigurace napříč všemi instancemi. Použití třídního atributu může zjednodušit správu těchto hodnot. Dále výkonová optimalizace. Třídní atributy šetří paměť, protože se ukládají pouze jednou pro celou třídu na rozdíl od instančních atributů, které jsou uložené pro každou instanci objektu. Pro konstantní hodnoty, jež jsou neměnné instancemi.

Je třeba mít na vědomí, že třídní atributy mohou být přístupné a měnitelné zvenčí, což může vést k neúmyslným změnám stavu objektu. V konečném důsledku záleží na konkrétním případě a designu třídy. Když jsou používány správně, třídní atributy mohou výrazně zjednodušit kód.

Odpovedať
Jazyk C je jako formule. Můžete předjíždět ve 300 km/h. Každá drobná chyba vás ale nekompromisně pošle do zdi.
Avatar
Jan Moučka
Člen
Avatar
Jan Moučka:30.10.2025 13:14

prostě se mi to jen nelíbilo tak moc, jako ostatní články... možná syntaxe vět? absolutně netuším

Avatar
Odpovedá na DarkCoder
Vratislav Hirš:10. októbra 19:29

10.10.2026
Opravdu vede užití třídního atributu k úspoře paměti zabranou instancí?

class Auto:
    # Třídní atribut
    pocet_kol = 4

    def __init__(self, model):
        # Instanční atribut
        self.model = model

# Vytvoření instancí
auto1 = Auto("Škoda")
auto2 = Auto("Toyota")

# Změna instančního atributu
auto1.model = "Audi"
print(auto1.model)  # "Audi"
print(auto2.model)  # "Toyota"

# Změna třídního atributu
Auto.pocet_kol = 6
print(auto1.pocet_kol)  # 6
print(auto2.pocet_kol)  # 6

#--------------------------
# Šetří třídní atribut paměť užitou instancí?
# Opravdu se v instanci nenaplní vnitřní kopie třídního atributu při inicializaci?
# Že by se instanční atribut vytvořil opravdu až po jeho naplnění v instanci a do té doby že by se četl ten třídní?
auto1.pocet_kol=5
auto2.pocet_kol=7
print(auto1.pocet_kol)  # 5
print(auto2.pocet_kol)  # 7
print(Auto.pocet_kol)   # 6
Avatar
DarkCoder
Člen
Avatar
Odpovedá na Vratislav Hirš
DarkCoder:10. októbra 20:22

Ano, třídní atribut může šetřit paměť, protože se ukládá na úrovni třídy a instance si jeho hodnotu automaticky nekopírují do vlastních atributů. Pokud instance vlastní atribut nemá, Python při čtení použije hodnotu ze třídy.

Třídní a instanční atributy lze kombinovat: jedna instance může používat třídní hodnotu a jiná může mít vlastní. Třídní atribut se proto hodí pro hodnoty společné všem instancím, zatímco instanční atribut je vhodný pro hodnoty, které se mezi objekty liší.

Úspora paměti je největší tehdy, když všechny instance využívají stejný třídní atribut a žádná si nevytváří vlastní instanční atribut.

V závěru uvedeného kódu se však příkazy auto1.pocet_kol = 5 a auto2.pocet_kol = 7 vytvářejí vlastní instanční atributy, které zastíní třídní atribut Auto.pocet_kol = 6. Výhoda sdílení tohoto atributu se tak u těchto instancí ztrácí. Konkrétní úspora paměti závisí na způsobu ukládání atributů v Pythonu.

Odpovedať
Jazyk C je jako formule. Můžete předjíždět ve 300 km/h. Každá drobná chyba vás ale nekompromisně pošle do zdi.
Avatar
DarkCoder
Člen
Avatar
Odpovedá na Vratislav Hirš
DarkCoder:10. októbra 20:30

Ještě odpovědi na tvé dotazy v kódu:

Šetří třídní atribut paměť?
Ano, může, protože se hodnota sdílí na úrovni třídy.

Vytváří se při inicializaci kopie v instanci?
Ne, automaticky se nevytváří.

Vznikne instanční atribut až při přiřazení?
Ano, v tomto příkladu vznikne při přiřazení hodnoty instanci.

Snad je to jasné a srozumitelné.

Odpovedať
Jazyk C je jako formule. Můžete předjíždět ve 300 km/h. Každá drobná chyba vás ale nekompromisně pošle do zdi.
Avatar
Odpovedá na DarkCoder
Vratislav Hirš:12. októbra 9:48

Děkuji za ujištění.
Ale co si neověřím, tomu hned tak úplně nevěřím.
A tak jsem si to potřeboval dokázat.
Zde je důkaz:

class Auto:
    # Třídní atribut
    pocet_kol = 4

    def __init__(self, model):
        # Instanční atribut
        self.model = model

# Vytvoření instancí
auto1 = Auto("Škoda")
auto2 = Auto("Toyota")

# Změna instančního atributu
auto1.model = "Audi"
print(auto1.model)  # "Audi"
print(auto2.model)  # "Toyota"

# Změna třídního atributu
Auto.pocet_kol = 6
print(auto1.pocet_kol)  # 6
print(auto2.pocet_kol)  # 6

#--------------------------
# Šetří třídní atribut paměť užitou instancí?
# Opravdu se v instanci nenaplní vnitřní kopie třídního atributu při inicializaci?
# Ano, je tomu tak. Zde je důkaz.

print(auto1.model,id(auto1.pocet_kol)," - Dotaz z instance na třídní atribut před jeho změnou.")
print(auto2.model,id(auto2.pocet_kol)," - Dotaz z instance na třídní atribut před jeho změnou.")
auto1.pocet_kol=5
auto2.pocet_kol=7
print(auto1.model,id(auto1.pocet_kol)," - Dotaz z instance na třídní atribut po jeho změně - vznikl instanční atribut.")
print(auto2.model,id(auto2.pocet_kol)," - Dotaz z instance na třídní atribut po jeho změně - vznikl instanční atribut.")
print(auto1.pocet_kol)  # 5
print(auto2.pocet_kol)  # 7
print(Auto,id(Auto.pocet_kol)," - Dotaz na třídní atribut přímo přes třídu.")
print(Auto.pocet_kol)   # 6

výstup kódu:

Audi
Toyota
6
6
Audi 140724013491480  - Dotaz z instance na třídní atribut před jeho změnou.
Toyota 140724013491480  - Dotaz z instance na třídní atribut před jeho změnou.
Audi 140724013491448  - Dotaz z instance na třídní atribut po jeho změně - vznikl instanční atribut.
Toyota 140724013491512  - Dotaz z instance na třídní atribut po jeho změně - vznikl instanční atribut.
5
7
<class '__main__.Auto'> 140724013491480  - Dotaz na třídní atribut přímo přes třídu.
6
Avatar
DarkCoder
Člen
Avatar
Odpovedá na Vratislav Hirš
DarkCoder:12. októbra 10:33

Není zač. To že si vše ověřuješ je naprosto správné.

Jinak k tomu ověřování. Metoda __dict__ je pro tento příklad vhodnější než funkce id(), protože nám umožňuje přímo zobrazit atributy uložené v instanci nebo třídě. Zatímco id() ukazuje identitu objektu v paměti, __dict__ nám ukáže, které atributy jsou skutečně uložené v daném objektu. Díky tomu můžeme názorně ověřit, že se třídní atribut při vytvoření instance automaticky nekopíruje do jejího slovníku.

class Auto:
    # Třídní atribut
    pocet_kol = 4

    def __init__(self, model):
        # Instanční atribut
        self.model = model


# Vytvoření instancí
auto1 = Auto("Škoda")
auto2 = Auto("Toyota")

# Změna instančního atributu
auto1.model = "Audi"
print(auto1.model)  # Audi
print(auto2.model)  # Toyota

# Změna třídního atributu
Auto.pocet_kol = 6
print(auto1.pocet_kol)  # 6
print(auto2.pocet_kol)  # 6

# ----------------------------------------
# Uložení atributů pomocí __dict__
# ----------------------------------------

print("\nSlovník instance auto1 před změnou:")
print(auto1.__dict__)

print("\nSlovník instance auto2 před změnou:")
print(auto2.__dict__)

print("\nSlovník třídy Auto:")
print(Auto.__dict__)

# Změna třídního atributu přes instance
auto1.pocet_kol = 5
auto2.pocet_kol = 7

print("\nSlovník instance auto1 po změně:")
print(auto1.__dict__)

print("\nSlovník instance auto2 po změně:")
print(auto2.__dict__)

print("\nHodnoty atributu pocet_kol:")
print("auto1:", auto1.pocet_kol)  # 5
print("auto2:", auto2.pocet_kol)  # 7
print("Auto:", Auto.pocet_kol)    # 6

Kód ukazuje důležité věci:

Před změnou: instance mají pouze vlastní atribut model
Po změně: každá instance má vlastní pocet_kol
Třídní atribut zůstává nezměněný

Každá instance nyní používá svou vlastní hodnotu, zatímco třída si zachovává hodnotu 6.

Hlavní poučení: Čtení třídního atributu přes instanci nezpůsobí jeho zkopírování. Teprve přiřazení hodnoty přes instanci v tomto případě vytvoří její vlastní atribut.
Před změnou: instance mají pouze vlastní atribut model

Odpovedať
Jazyk C je jako formule. Můžete předjíždět ve 300 km/h. Každá drobná chyba vás ale nekompromisně pošle do zdi.
Posledné komentáre sú v spodnej časti poslednej stránky.
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa prihlás. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zobrazené 10 správy z 41.