Osa 10

Åtkomstmodifierare

Om en egenskap definieras som privat i basklassen är den inte direkt åtkomlig i några härledda klasser, liksom kort nämndes i föregående avsnitt. Låt oss ta en titt på ett exempel. I klassen Anteckningsbok nedan lagras anteckningarna i en lista, och listattributet är privat:


class Anteckningsbok:
    """ En Anteckningsbok förvarar anteckningar i strängformat """

    def __init__(self):
        # privat attribut
        self.__anteckningar = []

    def tillsatt_anteckning(self, anteckning):
        self.__anteckningar.append(anteckning)

    def hamta_anteckning(self, index):
        return self.__anteckningar[index]

    def alla_anteckningar(self):
        return ",".join(self.__anteckningar)

Om klassens integritet är viktig är det vettigt att göra listattributen anteckningar privat. Klassen förser trots allt klienten med lämpliga metoder för att lägga till och bläddra i anteckningar. Detta tillvägagångssätt blir problematiskt om vi definierar en ny klass AnteckningsbokPro, som ärver Anteckningsbok-klassen. Det privata listattributet är inte tillgängligt för klienten, men det är inte heller tillgängligt för de härledda klasserna. Om vi försöker komma åt det, som i metoden hamta_anteckningar nedan, får vi ett felmeddelande:

class AnteckningsbokPro(Anteckningsbok):
    """ En bättre Anteckningsbok med sökfunktionalitet """
    def __init__(self):
        # Detta är ok, eftersom konstruktorn är offentlig trots understrykning
        super().__init__()

    # Detta orsakar ett fel
    def hitta_anteckningar(self, sokord):
        hittade = []
        # Attributet __anteckningar är privat, den härledda
        # klassen kan inte komma åt den direkt
        for anteckning in self.__anteckningar:
            if sokord in anteckning:
                hittade.append(anteckning)

        return hittade
Exempelutskrift

AttributeError: 'AnteckningsbokPro' object has no attribute '_AnteckningsbokPro__anteckningar'

Skyddade egenskaper

Många objektorienterade programmeringsspråk har en funktion, oftast ett speciellt nyckelord, för att skydda egenskaper. Detta innebär att en egenskap ska vara dold för klassens klienter, men hållas tillgänglig för dess underklasser. Python avskyr i allmänhet nyckelord, så ingen sådan funktion är direkt tillgänglig i Python. Istället finns det en konvention för att markera skyddade egenskaper på ett visst sätt.

Kom ihåg att en egenskap kan döljas genom att prefixera dess namn med två understreck:


def __init__(self):
    self.__anteckningar = []

Den överenskomna konventionen för att skydda en egenskap är att prefixera namnet med endast ett understreck. Nu är detta bara en konvention. Ingenting hindrar en programmerare från att bryta mot konventionen, men det anses vara en dålig programmeringspraxis.


def __init__(self):
    self._anteckningar = []

Nedan har vi hela Anteckningsbok-exemplet, med skyddade _anteckningar istället för privata __anteckningar:


class Anteckningsbok:
    """ En Anteckningsbok förvarar anteckningar i strängformat """

    def __init__(self):
        # Skyddade attribut
        self._anteckningar = []

    def tillsatt_anteckning(self, anteckning):
        self._anteckningar.append(anteckning)

    def hamta_anteckning(self, index):
        return self._anteckningar[index]

    def alla_anteckningar(self):
        return ",".join(self._anteckningar)

class AnteckningsbokPro(Anteckningsbok):
    """ En bättre Anteckningsbok med sökfunktionalitet """
    def __init__(self):
        # Detta är ok, eftersom konstruktorn är offentlig trots understrykning
        super().__init__()

    # Nu fungerar metoden, eftersom den skyddadde attributen är
    # ankomstbar till den härledda klassen
    def hitta_anteckningar(self, sokord):
        hittade = []
        for anteckning in self._anteckningar:
            if sokord in anteckning:
                hittade.append(anteckning)

        return hittade

Nedan har vi en praktisk tabell för synligheten av attribut med olika åtkomstmodifierare:

ÅtkomstmodifierareExempelSynlig till klientenSynlig till härledd klass
Offentligself.namnjaja
Skyddadself._namnnejja
Privatself.__namnnejnej

Åtkomstmodifierare fungerar på samma sätt med alla egenskaper. I klassen Person nedan har vi till exempel den skyddade metoden versalisera_initialer Den kan användas från den härledda klassen Fotbollsspelare:


class Person:
    def __init__(self, namn: str):
        self._namn = self._versalisera_initialer(namn)

    def _versalisera_initialer(self, namn):
        namn_versaliserat = []
        for n in namn.split(" "):
            namn_versaliserat.append(n.capitalize())

        return " ".join(namn_versaliserat)

    def __repr__(self):
        return self.__namn

class Fotbollsspelare(Person):

    def __init__(self, namn: str, smeknamn: str, position: str):
        super().__init__(namn)
        # metoden är ankomstbar eftersom den är skyddad i basklassen
        self.__smeknamn = self._versalisera_initialer(smeknamn)
        self.__position = position

    def __repr__(self):
        r =  f"Fotbollsspelare - namn:{self._namn}, smeknamn: {self.__smeknamn}"
        r += f", position: {self.__position}"
        return r

# Testar klasserna
if __name__ == "__main__":
    fs = Fotbollsspelare("peter pythonson", "putte", "anfallare")
    print(fs)
Exempelutskrift

Fotbollsspelare - namn:Peter Pythonson, smeknamn: Putte, position: anfallare

Loading
Loading
Du har nått slutet av den här delen! Fortsätt till nästa del:

Se dina poäng genom att klicka på cirkeln nere till höger av sidan.