Ich habe mir Effective Python kurz angesehen. Ich denke, es ist ein sehr gutes Buch. Ich denke, ich bin ein Anfänger in Python. Ich denke, dass es eine Rolle bei der Überbrückung von Anfängern und Fortgeschrittenen spielt, mehr als genug, weil es Dinge enthält, über die ich bis zu einem gewissen Grad nachdenke und die mir in den Sinn kommen. Ich bin ein großer Google-Experte. Als Entwickler gibt es einige Erklärungen, die für mich nicht intuitiv nützlich sind, da ich viel kleinen Code schreibe, aber es ist nicht Brett Slatkins Schuld, weil ich nicht allein bin.
Es ist leicht zu vergessen, wenn ich es nur lese. Ich möchte einige der Punkte zusammenfassen, die mich beeindruckt haben. Der hier verwendete Code ist Github [ ^ 1].
Da einige Auszüge veröffentlicht werden, kann es schwierig sein, den Kontext zu erfassen, aber bitte kaufen Sie ihn und lesen Sie ihn.
Sie können Generatorausdrücke verwenden, um eine große Anzahl von Eingaben nacheinander zu verarbeiten:
import random
with open('my_file.txt', 'w') as f:
for _ in range(10):
f.write('a' * random.randint(0, 100))
f.write('\n')
it = (len(x) for x in open('my_file.txt'))
print(next(it))
print(next(it))
Dies alles auf einmal mit einer Liste oder einem Taple zu tun, verbraucht viel Speicher. Ich denke, es ist eine ziemlich bekannte Methode, aber Expert Python Programming /books/books/detail/978-4-04-868629-7.shtml) war auch beeindruckend, dass die Generatorformel dringend empfohlen wurde.
Es ist ein "für ... sonst", das nicht nützlich zu sein scheint, aber es scheint die beste Vorgehensweise zu sein, es doch nicht zu verwenden. Der Grund dafür ist, dass sich der Kontext vom allgemeinen "sonst" unterscheidet. Wenn der vorherige Block fehlschlägt Es ist normal, zu elsezu springen, aber
for ... else führt einen
else-Block aus, wenn die
for-Anweisung erfolgreich abgeschlossen wurde (ohne
break`). Dies beeinträchtigt die Lesbarkeit. Das ist.
Als ich es zum ersten Mal las, dachte ich: "Was ist das? ...", aber ** "Effektiv ..." betont konsequent "generisch sein". ** Programmierung Die Behauptung, dass eine Verwendung, die die Bedeutung von "sonst" in der allgemeinen Sprache untergräbt, vermieden werden sollte, scheint jetzt, da ich sie gelesen habe, natürlich zu sein. Ich denke, es macht Sinn zu lesen.
Eine Schließung ist ein staatlicher Mechanismus, aber ich bin mir nicht sicher, zum Beispiel:
def closure():
flag = False
def getter():
print(flag)
return getter
func = closure()
func() # False
func ()
enthält eine Variable namens flag
. Es ist praktisch, diese Technik zu verwenden, um globale Variablen zu reduzieren.
Eine Sache, die Sie beachten sollten, ist, dass traurige Dinge passieren, wenn es um Aufgaben geht:
def closure():
flag = False
def setter():
flag = True
setter()
return flag
print(closure()) # False
Ich versuche "flag = True" mit "setter ()", aber der Rückgabewert von "schloss ()" ist "False", da sich im Bereich "setter ()" kein "flag" im Bereich befindet. Zuweisungen wurden in als Variablendefinitionen behandelt. Wenn Sie Schließungen nutzen möchten, müssen Sie mit Zuweisungen sehr vorsichtig sein. Um dieses Problem zu lösen, verwenden Sie "nicht lokal":
def closure():
flag = False
def setter():
nonlocal flag
flag = True
setter()
return flag
print(closure()) # True
Dies bezieht sich auf den nächsthöheren Bereich. Die Wurzel dieses Problems liegt darin, dass Variablendefinitionen und -zuweisungen in Python dieselbe Syntax haben. Um dies zu lösen, ähneln Variablendefinitionen Javascript. Es scheint, dass vorgeschlagen wurde, "var flag = False" auf "var flag = False" zu setzen, aber es scheint, dass "nonlocal" unter Berücksichtigung der Kompatibilität übernommen wurde.
Verschlüsse sind praktisch, aber die Verwendung von "nicht lokal" in großen Funktionen erschwert das Erfassen. Daher scheint es in solchen Fällen besser zu sein, Klassen zu verwenden.
Im Detail müssen Schlüsselwortargumente nach Positionsargumenten angegeben werden:
def remainder(number, divisor):
return number % divisor
remainder(20, 7) # OK
remainder(20, divisor=7) # OK
remainder(number=20, divisor=7) # OK
remainder(divisor=7, number=20) # OK
remainder(number=20, 7) # NG
Wörterbücher eignen sich sehr gut als Container, aber es kann sehr schwierig sein, sie so zu verschachteln, dass sie sich in den Wörterbüchern befinden. Teilen Sie sie vorher in Klassen auf:
import collections
Grade = collections.namedtuple('Grade', ('score', 'weight'))
class Subject(object):
def __init__(self):
self._grades = []
def report_grade(self, score, weight):
self._grades.append(Grade(score, weight))
def average_grade(self):
total, total_weight = 0, 0
for grade in self._grades:
total += grade.score * grade.weight
total_weight += grade.weight
return total / total_weight
class Student(object):
def __init__(self):
self._subjects = {}
def subject(self, name):
if name not in self._subjects:
self._subjects[name] = Subject()
return self._subjects[name]
def average_grade(self):
total, count = 0, 0
for subject in self._subjects.values():
total += subject.average_grade()
count += 1
return total / count
class Gradebook(object):
def __init__(self):
self._students = {}
def student(self, name):
if name not in self._students:
self._students[name] = Student()
return self._students[name]
book = Gradebook()
albert = book.student('Albert Einstein')
math = albert.subject('Math')
math.report_grade(80, 0.10)
math.report_grade(80, 0.10)
math.report_grade(70, 0.80)
gym = albert.subject('Gym')
gym.report_grade(100, 0.40)
gym.report_grade(85, 0.60)
print(albert.average_grade())
Es ist ein bisschen lang, aber lasst es uns gut lesen. ** Es scheint eine Antwort auf die Frage zu sein: "Was ist ein Klassendesign, das einfach zu warten und zu erweitern ist?" **
Die Schichtstruktur von "1. Notenbuch → 2. Schüler → 3. Fächer → 4. Noten" wird durch die Instanzvariablen (Wörterbücher) jedes Objekts realisiert, das die Objekte in der unteren Hierarchie enthält. Es gibt eine Methode zum Festlegen einer Instanz einer niedrigeren Klasse auf eine Instanzvariable und eine Methode zum Berechnen der durchschnittlichen Punktzahl. Wenn Sie genauer hinschauen, werden Sie feststellen, dass dieser Code in hohem Maße erweiterbar ist. Es ist gefährlich zu versuchen, es mit einem Wörterbuch zu realisieren.
Ich bin mir nicht sicher, ob der obige Code intuitiv und unkompliziert ist. Ich habe ihn nicht sofort verstanden. Aber als ich ihn wusste, war ich überzeugt, dass es eine sehr einfache Idee war. Andererseits konnte ich ihn verstehen. Mancher Code fühlt sich immer noch wie "Warum haben Sie eine so chaotische Implementierung?" An. ** Leicht verständlicher Code ist nicht immer guter Code. Leicht zu erklärender Code ist (wahrscheinlich) guter Code. ** Zen of Python sagt auch, dass:
Although that way may not be obvious at first unless you're Dutch. Die Methode ist auf den ersten Blick möglicherweise schwer zu verstehen. Es kann nur für Niederländer leicht zu verstehen sein.
If the implementation is hard to explain, it's a bad idea. Wenn es schwierig ist zu erklären, was der Code ist, ist es eine schlechte Implementierung.
If the implementation is easy to explain, it may be a good idea. Wenn Sie den Inhalt Ihres Codes leicht erklären können, ist dies wahrscheinlich eine gute Implementierung.
@ classmethod
?Es scheint gut zu sein, es für die Methode zu verwenden, die ein eigenes Objekt erstellt. Betrachten Sie die folgende übergeordnete Klasse / untergeordnete Klasse:
from tempfile import TemporaryDirectory
class GenericInputData(object):
def read(self):
raise NotImplementedError
@classmethod
def generate_inputs(cls, config):
raise NotImplementedError
class PathInputData(GenericInputData):
def __init__(self, path):
super().__init__()
self.path = path
def read(self):
return open(self.path).read()
@classmethod
def generate_inputs(cls, config):
data_dir = config['data_dir']
for name in os.listdir(data_dir):
yield cls(os.path.join(data_dir, name))
class GenericWorker(object):
def __init__(self, input_data):
self.input_data = input_data
self.result = None
def map(self):
raise NotImplementedError
def reduce(self, other):
raise NotImplementedError
@classmethod
def create_workers(cls, input_class, config):
workers = []
for input_data in input_class.generate_inputs(config): #Erstellen Sie eine Instanz der Klasse, die als Argument verwendet wird
workers.append(cls(input_data)) #Erstellen Sie Ihre eigene Instanz
return workers #Gibt eine eigene Instanz zurück
class LineCountWorker(GenericWorker):
def map(self):
data = self.input_data.read()
self.result = data.count('\n')
def reduce(self, other):
self.result += other.result
with TemporaryDirectory() as tmpdir:
config = {'data_dir': tmpdir}
workers = LineCountWorker.create_workers(PathInputData, config)
Das ist auch lang, aber gib dein Bestes! Es gibt zwei wichtige Punkte.
Das erste ist, dass die Klassenmethode der Klasse selbst für das Erstellen der Instanz verantwortlich ist. ** Wenn neue untergeordnete Klassen hinzugefügt werden, ist es die Verwaltung von "wo und wer die Instanz der Klasse erstellt". Im obigen Beispiel erstellt "LineCountWorker.create_workers ()" eine eigene Instanz unter "with" und erstellt darin eine Instanz von "PathInputData" [^ 2]. Mit anderen Worten, "wo" und "wer macht es" sind klar.
Die zweite ist eng mit der ersten verwandt. Dies bedeutet, dass " cls
durch die aufgerufene Klasse ersetzt wird ". Nun, es klingt offensichtlich, ist aber sehr wichtig. Im obigen Code * * cls (input_data)
definiert inGenericWorker.create_workers ()
wird beim Aufruf über die untergeordnete Klasse LineCountWorker
alsLineCountWorker (input_data)
verstümmelt. ** Dank dessen` Selbst wenn Sie eine neue abgeleitete Klasse "HogeCountWorker" erstellen, deren übergeordnete Klasse "GenericWorker" ist, erstellt "HogeCountWorker.create_workers ()" immer noch eine Instanz davon, und in "HogeCountWorker" wird eine neue Methode "create_workers" erstellt. Es ist nicht erforderlich. Obwohl es sich um eine Methode handelt, die von der übergeordneten Klasse geerbt wurde, wechselt sie beim Aufruf von der abgeleiteten Klasse schnell zu einer Methode, die diesem untergeordneten Element gewidmet ist! Dies ist das "Generikum", über das in "Effektiv ..." oft gesprochen wird.
Es gibt viele andere nützliche Dinge, wie Tipps zu Iteratorgeneratoren und zur Verwendung von "@ property". Bitte kaufen Sie es und lesen Sie es [^ 3].
Effective Python ist ein großartiges Buch, aber es gibt einige Dinge, auf die ich neugierig bin. ** Qualität der Übersetzung. ** Zum Beispiel ...
Beispiel 1 | |
---|---|
(Original) | You'd want a similar abstract interface for the MapReduce worker that consumes the input data in a standard way. |
(Übersetzung) | Angenommen, Sie möchten eine ähnliche abstrakte Schnittstelle für MapReduce Worker, die standardmäßig Eingabedaten verwenden. |
Beispiel 2 | |
---|---|
(Original) | Here, I extend the InputData class with a generic class method that's responsible for creating new InputData instances using a common interface. |
(Übersetzung) | Erweitern Sie die InputData-Klasse und fügen Sie eine generische Klassenmethode hinzu, die für die Erstellung neuer InputData-Instanzen mit einer gemeinsamen Schnittstelle verantwortlich ist. |
Hmm ... es ist subtil. Ich hatte viele Zweifel, ob ich den Inhalt wirklich verstanden und geschrieben habe. Insbesondere "Kapitel 3: Klasse und Vererbung" war schmerzhaft. Ich machte mein Unverständnis für die Übersetzung verantwortlich. Es war so sehr, dass ich wollte ... Nein, es tut mir leid, dass ich nicht klug genug bin.
Der Inhalt selbst ist jedoch immer noch wunderbar. Wer gut Englisch kann, sollte den Originaltext lesen.
Ich denke, dass das Wichtigste in Lernbüchern, nicht nur das Programmieren, ein "ausgezeichnetes Einführungsbuch" ist. Es gibt eine hohe Barriere zwischen Anfängern und Anfängern, um Schüler zu sehen, die Mathematik aufgeben, und Studenten, die in C-Sprache abbrechen. Es ist offensichtlich.
Zum Glück ist Python voll von Einführungsbüchern. Wenn Sie eine große Anzahl von Büchern haben, gibt es ausgezeichnete Bücher unter ihnen. Was ist dagegen mit japanischen Büchern für Anfänger und Fortgeschrittene? Es gibt viele Python-Bücher von O'Reilly, aber die einzigen Anfängerbücher, die eine breite Palette von Menschen abdecken, sind "Effective Python" und "Practical Python 3", und mit Ausnahme von O'Reilly ist "Expert Python Programming" wahrscheinlich das einzige [^ 4]. Ich bin wirklich froh, dass einer von ihnen, "Effective Python", mit dieser Perfektion veröffentlicht wurde.
Recommended Posts