@Caldzera: Ein paar Anmerkungen zu dem Quelltext:
”Magische” Methoden wie `__len__()` ruft man nicht direkt auf wenn es dafür einen anderen vorgesehenen Weg gibt. Dafür gibt es die `len()`-Funktion.
`sys.argv` an einen lokalen Namen zu binden macht nicht wirklich Sinn. Der Code wird dadurch weder leichter verständlich noch signifikant schneller. Grunddatentypen sollten auch nicht in Namen vorkommen. Wenn dann wäre so etwas wie `arguments` oder `commandline_arguments` ein Name der zumindest deutlicher macht was die historisch bedingte Abkürzung `argv` bedeutet. Da beim Zugriff jedes mal das zweite Element dieser Liste angesprochen wird, würde es Sinn machen diesen Wert an einen sprechenden Namen zu binden.
Dateien die man öffnet, sollte man auch wieder schliessen. Bei der Eingabedatei verlässt sich das Skript darauf dass das schon irgendwann automatisch passieren wird.
Variablen sollte man möglichst nahe an der Stelle definieren an der sie dann letztlich auch gebraucht werden und nicht irgendwo am Anfang in einem Block. Das macht es schwerer den Code nachzuvollziehen, Code in eine eigene Funktion heraus zu ziehen, und man übersieht so auch gerne mal Variablen die gar nicht mehr verwendet werden, wenn man Code an anderer Stelle ändert.
`arr_p` und `arr_n` sind fürchterliche Namen. Man muss raten was die Abkürzungen wohl bedeuten mögen. Bei `arr` rate ich mal das da jemand zu faul war `array` zu tippen. Das ist aber inhaltlich falsch, weil das an eine Liste gebunden ist und kein Array. Einer der Gründe warum solche Grunddatentypen nicht in Namen haben will, denn wenn man den Typ im Laufe der Programmentwicklung ändert, hat man falsche, irreführende Namen, oder man muss alle betroffenen Namen anpassen. Der Leser will eigentlich auch gar nicht wirklich wissen was das nun genau für ein Sequenztyp ist, sondern was die Werte darin bedeuten – und da ist mir beim besten Willen nicht eingefallen wofür `p` und `n` wohl stehen mögen. Wenn man sich den Code anschaut sind gute allgemeine Namen `even_page_numbers` und `odd_page_numbers`. Besser wäre natürlich wenn man an den Namen ablesen könnte um was die jeweilige *Bedeutung* des jeweiligen Seitentyps im Kontext dieses Programms ist.
Die beiden ``while``-Schleifen sind eigentlich ``for``-Schleifen. Schauen wir uns die erste mal genauer an:
Code: Alles auswählen
page_count = reader.getNumPages()
even_page_numbers = []
odd_page_numbers = []
i = 0
while i < page_count:
if i % 2 == 0:
even_page_numbers.append(i)
else:
odd_page_numbers.append(i)
i += 1
Wenn man da eine ``for``-Schleife draus macht, wird es schon etwas einfacher:
Code: Alles auswählen
even_page_numbers = []
odd_page_numbers = []
for i in range(reader.getNumPages()):
if i % 2 == 0:
even_page_numbers.append(i)
else:
odd_page_numbers.append(i)
Man könnte aber auch ganz ohne die ``for``-Schleife einfach gleich mit `list()` und `range()` entsprechende Sequenzen erstellen:
Code: Alles auswählen
page_count = reader.getNumPages()
even_page_numbers = range(0, page_count, 2)
odd_page_numbers = range(1, page_count, 2)
Allerdings braucht man diese Listen mit den doch sehr langweiligen Werten überhaupt gar nicht, weil man das doch genau so gut einfach in der nächsten Schleife berechnen kann was da ursprünglich in zwei Listen gesteckt wurde.
Warum `x`? Hier hätte man doch einfach wieder `i` nehmen können. Beziehungsweise einen Namen der verrät was der Wert bedeutet. Ich würde da in der zweiten Schleife, was ja auch eine ``for``-Schleife ist, gleich über die geraden Seitenindizes iterieren.
Wenn man den Code in der zweiten Schleife etwas anders arrangiert, kann man die Wiederholung des Codes zu erstellen von leeren Seiten nur einmal schreiben, statt zweimal.
Die ganzen Zweige mit den `mergeTranslatedPage()`-Aufrufen sind nahezu identisch. Das einzige was sich in Abhängigkeit vom Divisionsrest ändert sind die Koordinaten. Die könnte man in eine Liste stecken und sich so die ganzen ``if``/``elif``-Zweige sparen.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
import sys
from PyPDF2.pdf import PageObject, PdfFileReader, PdfFileWriter
from reportlab.lib.pagesizes import A4
def main():
pdf_filename_stem = sys.argv[1]
with open(f'{pdf_filename_stem}.pdf', 'rb') as pdf_file:
reader = PdfFileReader(pdf_file)
writer = PdfFileWriter()
coordinates = [
(300, 0), (0, 630),
(300, 630), (0, 420),
(300, 420), (0, 210),
(300, 210), (0, 0),
]
width, height = A4
for even_page_index in range(0, reader.getNumPages(), 2):
if even_page_index % len(coordinates) == 0:
if even_page_index != 0:
writer.addPage(translated_page)
starter_page.rotateCounterClockwise(180)
writer.addPage(starter_page)
starter_page = PageObject.createBlankPage(None, width, height)
translated_page = PageObject.createBlankPage(None, width, height)
#
# TODO Find better names without those cryptic `p` and `n`.
#
x, y = coordinates[even_page_index % len(coordinates)]
p_page = reader.getPage(even_page_index)
starter_page.mergeTranslatedPage(p_page, x, y)
n_page = reader.getPage(even_page_index + 1)
translated_page.mergeTranslatedPage(n_page, x, y)
with open(f'{pdf_filename_stem}_printready.pdf', 'wb') as pdf_file:
writer.write(pdf_file)
if __name__ == '__main__':
main()