Ich schaute wieder auf die Python-Klasse zurück

Dieser Artikel ist der Artikel zum 9. Tag von Python Part 3 Adventskalender 2019. In diesem Artikel möchte ich als Memorandum auf die Grundlagen der Python-Klasse zurückblicken. Dieser Artikel basiert auf einigen der folgenden Bücher.

Verkapselung

Muster 1

Diese Funktion wird verwendet, wenn Sie die Variablen in der Klasse nicht von außen referenzieren oder aktualisieren möchten. Definieren Sie zunächst die Klasse (Benutzer) normal.

class User:
    def __init__(self, name=None):
        self.name = name

user = User(name='qiita')
print('user name: ', user.name)   # user name:  qiita

Ich möchte einer neuen Klasse, die von dieser Klasse erbt, eine Eigenschaft namens "flag" hinzufügen. Wenn Sie diese Eigenschaft von außen umschreiben und unlesbar machen möchten, fügen Sie vor der Eigenschaft __ (zwei Unterstriche) hinzu.

class User2(User):
    def __init__(self, name=None, flag=True):
        super().__init__(name)
        self.__flag = flag
        
user2 = User2(name='qiita')
print('user2 flag: ', user2.__flag)   # AttributeError

Es kann jedoch von innerhalb der Klasse zugegriffen werden. Wenn Sie den folgenden Code versuchen, wird der Wert von "flag" ausgegeben.

class User2(User):
    def __init__(self, name=None, flag=True):
        super().__init__(name)
        self.__flag = flag
        print('flag: ', self.__flag)   # flag:  True
        
user2 = User2(name='qiita')

(Hinzufügung) Wie unten gezeigt, können Sie außerdem auf "_class name" vor der Eigenschaft zugreifen. Wie ich nicht wusste, scheint PEP8 zu sagen, dass diese Funktion nicht aktiv in der Metapher von Klasseneigenschaften verwendet werden sollte, sondern nur, um Konflikte mit Eigenschaftsnamen zu vermeiden.

class User2(User):
    def __init__(self, name=None, flag=True):
        super().__init__(name)
        self.__flag = flag

user2 = User2(name='qiita')
print(user2._User2__flag)   # True

Obwohl es von außen nicht umgeschrieben werden kann, ist es auch möglich, eine neue normale Eigenschaft zu definieren. (Ich glaube nicht, dass ich so viel mache)

class User2(User):
    def __init__(self, name=None, flag=True):
        super().__init__(name)
        self.__flag = flag

user2 = User2(name='qiita')
user2.__flag = 'changed'
print('user2 flag: ', user2.__flag)   # user2 flag:  changed

Muster 2

Es gibt einen Unterstrich als flexible Metapher als die beiden obigen Unterstriche. Wenn Sie diese Methode jedoch ohne Einfallsreichtum verwenden, ist sie normalerweise von außen zugänglich. (Seien Sie vorsichtig, da der Entwickler es nicht umschreiben möchte.)

class User3(User):
    def __init__(self, name=None, flag=True):
        super().__init__(name)
        self._flag = flag
        
user3 = User3(name='qiita')
print('user3 flag: ', user3._flag)   # user3 flag:  True

user3._flag = False
print('user3 flag: ', user3._flag)   # user3 flag:  False

Daher werden wir diese Eigenschaft entwickeln. Es ist möglich, "flag" als eine Eigenschaft zu definieren, auf die von außen verwiesen werden kann, indem eine Eigenschaft zusammen mit einem Dekorateur wie unten gezeigt definiert wird, die jedoch nicht neu geschrieben werden kann.

class User3(User):
    def __init__(self, name=None, flag=True):
        super().__init__(name)
        self._flag = flag

    @property
    def flag(self):
        return self._flag

user3 = User3(name='qiita')
print('user3 flag: ', user3.flag)   # user3 flag:  True

user3.flag = False   # AttributeError: can't set attribute

Selbst im obigen Fall können Sie es normal umschreiben, wenn Sie es mit "._flag" anstelle von ".flag" aufrufen. Seien Sie also vorsichtig. Mit @ property name.setter ist es auch möglich, es neu zu schreiben und darauf zu verweisen. In diesem Fall wird es oft zusammen mit "if" usw. als "wiederbeschreibbar" verwendet, wenn bestimmte Bedingungen erfüllt sind. Im folgenden Code kann die Eigenschaft "flag" nur neu geschrieben werden, wenn die Eigenschaft "pswd" die Bedingungen erfüllt.

class User3(User):
    def __init__(self, name=None, flag=True, pswd=None):
        super().__init__(name)
        self._flag = flag
        self.pswd = pswd

    @property
    def flag(self):
        return self._flag

    @flag.setter
    def flag(self, new_flag):
        if self.pswd=='777':
            self._flag = new_flag
        else:
            pass

user3 = User3(name='qiita', flag=True, pswd='222')
user3.flag = False
print('user3 flag: ', user3.flag)   # user3 flag:  True  ->Nicht umgeschrieben

Im obigen Beispiel wird "pass" verwendet, aber die Ausnahmebehandlung kann verwendet werden, um einen Fehler zu verursachen. Im Fall des obigen Beispiels ist es notwendig, die Möglichkeit von Fehlern zu berücksichtigen, die durch die Tatsache verursacht werden, dass die Absicht neu geschrieben, aber nicht neu geschrieben wurde.

Spezielle Methode

Wenn Sie in der Klasse eine spezielle Methode definieren, können Sie die Instanz mithilfe von Operatoren bedienen. Wenn Sie nachschlagen, werden Sie viel finden, aber dieses Mal möchte ich einige davon aufgreifen.

Arithmetische Operator Edition

class Add:
    def __init__(self, value):
        self.value = value
    
    #  [+]Spezielle Methode, die bei der Verwendung aufgerufen wird
    def __add__(self, other):
        return self.value + other.value
    
    #  [-]Spezielle Methode, die bei der Verwendung aufgerufen wird
    def __sub__(self, other):
        return self.value + other.value + 5

x = Add(10)
print(type(x))    # <class '__main__.Add'>
print(x + Add(5))   # 15
print(x - Add(5))   # 20

Die obige Methode add ist eine spezielle Methode, die mit [+] nach der Instanz aufgerufen wird.

Andere Beispiele (Auszug)

Arithmetischer Operator Methode
* mul
/ truediv
& and

Vergleichsoperator

Die Spezifikationen entsprechen fast den obigen arithmetischen Operatoren.

class Equ:
    def __init__(self, value):
        self.value = value
    
    #  [==]Spezielle Methode, die bei der Verwendung aufgerufen wird
    def __eq__(self, other):
        return self.value == other.value

print(Equ(str(4)) == Equ(str(4)))   # True

Andere Beispiele (Auszug)

Vergleichsoperator Methode
!= ne
< lt
> gt

Spezielle Methoden, die die Typkonvertierung definieren

class Int:
    def __init__(self, num):
        self.num = num

    def __int__(self):
        return int(self.num)

x = Int('1')
print(type(x))   # <class '__main__.Int'>
print(type(int(x)))   # <class 'int'>
print(int(x))   # 1

Das Obige ist eine spezielle Methode, die aufgerufen wird, wenn die integrierte Funktion int verwendet wird, und wie der Name schon sagt, das Objekt selbst in den Typ int konvertiert. Darüber hinaus ist int ('100') == 100 # True, das häufig in der Python-Programmierung verwendet wird, eine Funktion, die durch Aufrufen der im Standard-str-Objekt definierten Methode __int __ () realisiert werden kann. ..

Andere Beispiele (Auszug)

bewirken Methode
Typ schweben float
Zum String-Typ str

Spezielle Methode für den Containertyp

class Dataset:
    def __init__(self):
        self.imgs = ['img01', 'img02', 'img03']
        
    def __getitem__(self, idx):
        return self.imgs[idx]
    
    def __len__(self):
        return len(self.imgs)
    
dataset = Dataset()
print(dataset[0])   # img01
print(len(dataset))   # 3

Der obige Schreibstil ist ein Muster, das häufig in PyTorch usw. verwendet wird. Ein Containertyp ist ein Objekt mit mehreren Werten, z. B. eine Liste oder ein Wörterbuch. Auf diese wird normalerweise mit "[]" und "len" zugegriffen, um auf die Länge zu verweisen, aber auf die Instanz selbst kann auf die gleiche Weise zugegriffen werden.

Klassenvariablen / Instanzvariablen

Eine Python-Klasse kann Variablen definieren, die innerhalb der Klasse gemeinsam verwendet werden können, auch wenn sie nicht durch Initialisierung initialisiert werden. Ersteres wird als Instanzvariable und letzteres als Klassenvariable bezeichnet. Klassenvariablen werden gemeinsam genutzt, wenn mehrere Instanzen aus derselben Klasse erstellt wurden. Dies kann zu Fehlern führen, insbesondere wenn Sie veränderbare Werte als Klassenvariablen haben.

class Sort:
    num_list = []
    
    def num_sort(self, nums):
        self.num_list +=  sorted(nums)

        return self.num_list
        
num_list1 = Sort().num_sort([3, 5, 10, 2])
print(num_list1)   # [2, 3, 5, 10]

num_list2 = Sort().num_sort([-1, 8, 0, -2])
print(num_list2)   # [2, 3, 5, 10, -2, -1, 0, 8]

Im obigen Beispiel wird die Klassenvariable von "num_list1" auch mit "num_list2" geteilt, was seltsam ist. Wenn Sie es als Instanzvariable mit "init" definieren, wird es jedes Mal initialisiert, wenn Sie eine Instanz deklarieren. Dies ist also nicht der Fall.

class Sort:
    def __init__(self):
        self.num_list = []
    
    def num_sort(self, nums):
        self.num_list +=  sorted(nums)

        return self.num_list
        
num_list1 = Sort().num_sort([3, 5, 10, 2])
print(num_list1)   # [2, 3, 5, 10]

num_list2 = Sort().num_sort([-1, 8, 0, -2])
print(num_list2)   # [-2, -1, 0, 8]

Eingebaute Vererbung

Am Ende habe ich versucht, die Funktionen zusammenzufassen, die ich persönlich nützlich finde. In Python ist es auch möglich, integrierte Typen zu erben und eigene Originalobjekte zu erstellen. Im folgenden Beispiel wird ein neuer Objekttyp erstellt, indem der Wörterbuchtyp geerbt wird.

class Dict2(dict): 
    def __init__(self, *args, **kwargs): 
        super().__init__(*args, **kwargs) 
        self.__dict__ = self
        
dic = Dict2(i=1, j=2, k=3)
print(dic.i, dic.j, dic.k)

Im obigen Beispiel können Sie im Gegensatz zum normalen Wörterbuchtyp auf den Wert mit "." Verweisen. Es kann für diejenigen natürlich sein, die an andere Programmiersprachen gewöhnt sind. Bei einem normalen Python-Wörterbuchtyp müssen Sie jedes Mal auf dic ['i'] zugreifen.

duck typing Sie können dieselbe Methode in verschiedenen Klassen verwenden und zwischen denselben Operationen für verschiedene Objekte wechseln. Dies nennt man Ententypisierung.

def animal_cry(animal):
    animal.cry()

class Duck:
    def cry(self):
        print('ga-ga-')

class Turkey:
    def cry(self):
        print('bo-bo-')

duck = Duck()
turkey = Turkey()

for ani in [duck, turkey]:
    animal_cry(ani)

# ga-ga-
# bo-bo-

Das obige Beispiel wendet dieselbe "Schrei" -Methode auf Instanzen an, die aus verschiedenen Klassen Ente und Vogel erstellt wurden. Wenn Sie dies nutzen, können Sie möglicherweise objektorientierteren und präziseren Code schreiben.

class Bird:
    def __init__(self, voice):
        self.voice = voice
        if type(voice) != str:
            raise AttributeError('The argument voice must be str type.')
        
    def cry(self):
        print(self.voice)
        

class Duck(Bird):
    def __init__(self, voice='ga-ga-'):
        super().__init__(voice)

        
class Turkey(Bird):
    def __init__(self, voice='bo-bo-'):
        super().__init__(voice)
        
        
class DuckCry:
    def bird_cry(self, bird):
        if bird.voice != 'ga-ga-':
            print("It's don't duck.")
        else:
            bird.cry()
            
            
duck = Duck()
turkey = Turkey()
duck_cry = DuckCry().bird_cry(duck)   # ga-ga-
duck_cry = DuckCry().bird_cry(turkey)   # It's don't duck.

Obwohl es sich um prägnanten Code handelt, ist das Beispiel nicht gut und ich kann seine Bequemlichkeit nicht ausdrücken, aber ich erstelle eine Klasse, die eine Klasse erbt, verschiedene Klassen erstellt und für jede gemeinsame Methoden ausführt. Hier ist ein Beispiel.

Schließlich

In Bezug auf die Anzahl der Artikel nach Sprache des Adventskalenders 2019 scheint es, dass Go bis zu diesen 3 im Vergleich zu Python 3, das noch nicht gefüllt ist, voll ist. (Stand 07.12.) Ich bin der Meinung, dass Python in Bezug auf die Bevölkerungszahl beliebter ist. Verwenden Python-Benutzer jedoch andere Plattformen als Qiita, um Informationen zu verbreiten? (Es ist wahr, dass es viele Bereiche des maschinellen Lernens gibt, wie zum Beispiel Hatena-Blogs.) Ich hoffe, dass Python weiterhin aufregend ist und ich den Staffelstab an die nächste Person weitergeben werde.

Recommended Posts

Ich schaute wieder auf die Python-Klasse zurück
Ich habe Python unter Windows ausgeführt
[Python] Rückblickend auf das, was ich Programmieranfängern aus Funktionen beigebracht habe
Python unter Windows
Twitter mit Python3
Ich habe Python gestartet
Python auf Mac
Python auf Windbg
Erstellen Sie eine Python-Ausführungsumgebung unter IBM i
Ich kann dich nicht noch einmal fragen (?) Python Knowledge Series -Decorator-
Ich habe Python zum ersten Mal auf dem Mac ausprobiert.
Ich habe versucht, Mine Sweeper auf dem Terminal mit Python zu implementieren
Ich habe Python zum ersten Mal mit Heroku ausprobiert
Ich habe eine Python3-Umgebung unter Ubuntu mit direnv erstellt.
Ich möchte mit Python-Datenklasse nach hinten erben
Ich möchte Lambda mit Python auf Mac AWS!
Ich habe versucht, die Eingabe für UE4 Python VS Code zu interpolieren
Python Conda mit Cygwin
Installieren Sie Python auf der WSL
PyOpenGL-Setup unter Python 3
Installieren Sie Python auf Pidora.
Installieren Sie Scrapy auf Python3
Rückblick auf ABC155
Python-Klassen sind langsam
Installieren Sie Python auf dem Mac
Installieren von Python 3 in einer Mac-Umgebung
Installieren Sie Python3.4 unter CentOS 6.6
Pandas auf python2.6 installieren
Python Basic ② in Windows
Installieren Sie Python unter Windows
Python neu lernen (Algorithmus I)
Python-Grundkurs (13 Klassen)
Installieren Sie Python 2.7.3 unter CentOS 5.4
Build Python auf Ubuntu
Installieren Sie Python 3.3 unter Ubuntu 12.04
Installieren Sie Python 3.4 auf einem Mac
Ich habe Python> Decorator ausprobiert
Warum ich mich für Python entschieden habe
Ich habe Python more-itertools 2.5 → 2.6 verglichen
Installieren Sie Python 3.6 auf Docker
maya Python Ich möchte die gebackene Animation wieder reparieren.
Ich möchte automatisch an Online-Kursen mit Python + Selen teilnehmen!
Ich habe versucht, das Python-Skript unter Windows 10 von 2.7.11 auf 3.6.0 zu ändern