invalid syntax bei def

Code-Stücke können hier veröffentlicht werden.
Antworten
Lou Cyphr3
User
Beiträge: 59
Registriert: Donnerstag 6. Juli 2017, 00:04

Hallo,

ich bin ein python-noob. Ich nutze Python3 und probiere immer mal mit charm und Ipython rum.
Nun habe ich mir gedacht ich probiere mal ein Script aus, welches ich in den Weiten des Internets gefunden habe, nachdem
ich mir schon ein wenig die Basics gab.

So jetzt ist mein Problem, dass es mir immer ein invalid syntax ausgibt, obwohl ich meines erachtens keinen drin habe.

Code: Alles auswählen

import argparse
from PIL import Image
from PIL.exifTags import TAGS

def getMetaData(imagename, out):
    try:
        metaData ={}

        imgFile = image.open(imgname)
        print('metadaten ...')
        info = imgFile._getexif()
        if info:
            print('metadaten gefunden...')
            for (tag, value) in info.items():
                tagname = TAGS.get(tag, tag)
                metaData[tagname] = value
                if not out:
                    print(tagname, value)
                    if out:
                        print('ausgeben der Daten...')
                        with open(out, 'w') as f:
                            for (tagname, value) in metaData,items():
                                f.write(str(tagname+'\t'+\
                                            str(value)+'\n')
    except:

def main():

        parser = argparse.ArgumentParser()
        parser.add_argument('img', help='name of the file' )
        parser.add_argument('--ouput','-o', help='dump data out the file')
        args = parser.parse_args()
        if agrs.img:
            getMetaData(args.img, args.output)
        else:
            print(parser.usage
if_name_== '_main_':
        main()
als Fehler wird mir in diesem Fall "
def Main(): line 26
^
SyntaxError: invalid syntax

Process finished with exit code 1" ausgegeben. Ich hab auch schon sämtliche Variationen mit und ohne Klammer; : etc. ausprobiert.

Kann mir wer einen Hinweis geben?
Zuletzt geändert von Anonymous am Donnerstag 6. Juli 2017, 08:08, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Cours, camarade, le vieux monde est derrière toi!
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Lou Cyphr3: der Code ist unvollständig. In Python gibt es eine Namenskonvention, an die Du Dich nicht hältst. Variablen und Funktionen werden klein_mit_unterstrich geschrieben, also get_meta_data. Der Name der Funktion ist aber irreführend, da gar nichts geholt (get) wird, sondern nur etwas in eine Datei geschrieben wird. Blöcke sollten nicht so tief geschachtelt werden. Du hast 8 (in Worten acht) Ebenen. Das dass zu viel ist, sieht Du daran, dass das write, eigentlich ganz kurz ist, aber doch in zwei Zeilen umgebrochen werden muß. Um dies zu verhindern, teilt man solche Stellen in mehrere Funktionen auf.

wenn keine exif-Daten gefunden werden, also info leer ist, wird nichts gemacht; das ist überraschend, und Überraschungen mögen Programmierer nicht. Hier solltest Du mit einem Fehler abbrechen. metaData werden in Zeile 7 initialisiert, aber erst in Zeile 16 verwendet. So weit voneinander entfernte Verwendung macht Code unleserlich. Das Initialisieren gehört direkt vor die for-Schleife.

Danach stimmt etwas mit der Einrückung nicht mehr. In einem Zweig, wo out unwahr ist, wird nur etwas gemacht, wenn out wahr ist, ergo nie. Das `if out` gehört logischerweise auf die gleiche Stufe wie das for. Damit reduziert sich die maximale Einrücktiefe auf 6, was aber immer noch zu viel ist.

In Zeile 22 steht ein Komma, wo ein Punkt sein müßte.
Zeile 23: Strings sollte man nicht mit + zusammenstückeln, das ist kaum lesbar, so dass einem auch leicht eine fehlende schließende Klammer übersieht; benutze "{}\t{}\n".format(tagname, value) oder gleich das csv-Modul, wenn es sich hier um ein csv-Dateiformat handelt.

Nach except bricht die Funktion ab. Da fehlt was. Nackte excepts sollte man nie benutzen, denn das einzige, was man an dieser Stelle sinnvoll behandeln könnte, wäre, den Fehler an die darüberliegende Funktion weiterzureichen. Dann kann das try-except aber gleich weg.

Die Zeilen in main sind zu weit eingerückt. In Zeile 33 ist ein Tippfehler. In Zeile 36 fehlt eine schließende Klammer, In Zeile 37 fehlen ein Leerzeichen und 4 Unterstriche. Zeile 38 ist zu weit eingerückt.

Mach Dich mit der Python-Syntax vertraut, die Du benutzt. Wenn Du ein try-except findest, ließ nach, was Exception-Handling ist, und wie man es benutzt. Achte auf Klammern und Schreibung. Versuche das Programm Zeile für Zeile selbst nachzuvollziehen, was es macht und ob das sinnvoll ist.
BlackJack

Da lauern auch noch mehr Fehler wenn man die beseitigt hat, die ins Auge fallen:

Code: Alles auswählen

In [1]: from PIL.exifTags import TAGS
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-7b5951e10241> in <module>()
----> 1 from PIL.exifTags import TAGS

ImportError: No module named exifTags
Ich wäre auch vorsichtig eine nicht zur öffentlichen API gehörende Methode zu verwenden. Der Grund dafür dürfte folgender Kommentar im Quelltext sein:

Code: Alles auswählen

def _getexif(self):
    # Extract EXIF information.  This method is highly experimental,
    # and is likely to be replaced with something better in a future
    # version.
In diesem experimentellen Stadium ist die Funktion schon seit einer Ewigkeit.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Bei mir wird in PIL.ExifTags das E wohl groß geschrieben.
Und wo soll imgname in imgFile = image.open(imgname) herkommen?
Aus dem Funktionskopf zumindest nicht, denn da steht imagename und kommt nicht mehr in der Funktion vor.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

So funktioniert es zumindest bei mir mit einem Testbild. with open() war zu tief eingerückt und hätte bei jeder Runde der ersten for-Schleife arbeiten müssen. 3 mal NUL sind noch als Steuerzeichen in der "testfile.txt" enthalten, da müsste vorher noch etwas passieren. Weiß nicht, wie sich das mit den Tag-Namen verhält, bei mir haben zumindest diese beiden gestört.

Code: Alles auswählen

from PIL import Image
from PIL.ExifTags import TAGS

def get_meta_data(imagename, textfile = None):
    try:   
        imagefile  = Image.open(imagename)
        image_info = imagefile._getexif()
        meta_data  = {}    
        
        if image_info:
            for tag, value in image_info.items():
                tagname = TAGS.get(tag)
                if (tagname != "UserComment" and 
                        tagname != "ComponentsConfiguration"):
                    meta_data[tagname] = value
                    
            print(meta_data)  
                    
            if textfile is not None:
                with open(textfile, "w") as datei:
                    for tag, wert in meta_data.items():
                        datei.write('{0}\t{1}\n'.format(tag, str(wert)))

    except:
        print("Fehler!")

imagename = "altmaerkische.jpg" 
textfile  = "testfile.txt"

get_meta_data(imagename, textfile)
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Melewo: das try-except ist auch bei Dir falsch; weg damit! Die Bedingung in Zeile 13 kann man besser mit `not in` schreiben. str in Zeile 22 ist unnötig.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Sirius3 hat geschrieben:@Melewo: das try-except ist auch bei Dir falsch; weg damit!
Das dachte ich mir beinahe, weil ich sonst noch nie eine verwendet habe, nur dieses Mal da stehen ließ. Und als ich dann schon gepostet hatte, fragte ich mich anschließend, ob diese Zeile

Code: Alles auswählen

meta_data[tagname] = value
nicht so besser ausgesehen hätte.

Code: Alles auswählen

meta_data.update({tagname : value})
Oder?
BlackJack

@Melewo: Nein überhaupt nicht. Das ist mir an anderer Stelle bei Dir auch schon aufgefallen. Warum sollte es besser zu sein ein Wörterbuch mit einem Schlüssel/Wert-Paar zu erstellen, damit das andere Wörterbuch zu aktualisieren, und dann das Wörterbuch wieder zu verwerfen statt einfach direkt dem Schlüssel einen Wert zuzuweisen?
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Ok, so wie Du es beschreibst leuchtet es mir ein, dann werde ich das andere Script auch noch einmal in diesem Punkt überarbeiten.

Code: Alles auswählen

from PIL import Image
from PIL.ExifTags import TAGS
 
def get_meta_data(imagename, textfile = None):
    imagefile  = Image.open(imagename)
    image_info = imagefile._getexif()
    meta_data  = {}    
   
    if image_info:
        for tag, value in image_info.items():
            tagname = TAGS.get(tag)
            if ("UserComment" not in tagname and
                    "ComponentsConfiguration" not in tagname):
                meta_data[tagname] = value
               
        print(meta_data)  
               
        if textfile is not None:
            with open(textfile, "w") as datei:
                for tag, wert in meta_data.items():
                    datei.write('{0}\t{1}\n'.format(tag, str(wert)))
 
imagename = "altmaerkische.jpg"
textfile  = "testfile.txt"
 
get_meta_data(imagename, textfile)
BlackJack

@Melewo: Du hast beim `get()` jetzt `tag` nicht noch einmal als zweites Argument übergeben. Damit bildest Du Tags für die es keinen Namen gibt, alle auf den Schlüssel `None` ab, womit Informationen verloren gehen können.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Habe das Testbild jetzt mit und ohne zweimal tag bei get aufgerufen und erkenne in der Ausgabe keinen Unterschied.

[codebox=text file=Unbenannt.txt]Make Canon
Model Canon EOS 450D
Orientation 1
YCbCrPositioning 1
XResolution (350, 1)
YResolution (350, 1)
ResolutionUnit 2
ExifOffset 219
Software Digital Photo Professional
DateTime 2015:12:29 11:13:49
ExifVersion b'0221'
ShutterSpeedValue (524288, 65536)
DateTimeOriginal 2011:05:01 14:10:59
DateTimeDigitized 2011:05:01 14:10:59
ApertureValue (548864, 65536)
ExposureBiasValue (0, 1)
FlashPixVersion b'0100'
Flash 16
FocalLength (18, 1)
ColorSpace 1
ExifImageWidth 2053
ExifInteroperabilityOffset 943
FocalPlaneXResolution (4272000, 878)
FocalPlaneYResolution (2848000, 584)
SubsecTime 02
SubsecTimeOriginal 02
SubsecTimeDigitized 02
ExifImageHeight 1424
FocalPlaneResolutionUnit 2
ExposureTime (1, 250)
FNumber (18, 1)
ExposureProgram 4
CustomRendered 0
ISOSpeedRatings 200
ExposureMode 0
WhiteBalance 0
SceneCaptureType 0[/code]
BlackJack

@Melewo: Nicht alle Bilder haben die gleichen Tags, und es kann eben auch sein, das es welche mit ”unregistrierten” Nummern gibt. Da gibt es IMHO zwei sinnvolle Möglichkeiten mit umzugehen: Entweder filtert man die komplett raus, oder man behält sie mit dem Tag als Schlüssel. Dein Code bildet die alle auf das Schlüssel/Wert-Paar ``(None, value)`` ab, das heisst wenn es mehrere unbekannte gibt, bleibt nur der letzte Wert im Ergebnis übrig und in jedem Fall geht die Tagnummer verloren. Man weiss dann also nicht einmal *was* übrig geblieben ist.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Melewo: das `not in` hast Du jetzt genau falsch umgesetzt.

Code: Alles auswählen

def get_meta_data(imagename, textfile=None):
    imagefile = Image.open(imagename)
    image_info = imagefile._getexif()
    if not image_info:
        raise AssertionError("no exif data found")
    meta_data = {}    
    for tag, value in image_info.items():
        tagname = TAGS.get(tag, tag)
        if tagname not in ["UserComment", "ComponentsConfiguration"]:
            meta_data[tagname] = value
    print(meta_data)  
    if textfile is not None:
        with open(textfile, "w") as datei:
            for tag, wert in meta_data.items():
                datei.write('{}\t{}\n'.format(tag, wert))
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Gut, ich weiß es nun von Dir, dass die Verwendung von

Code: Alles auswählen

tagname = TAGS.get(tag, tag)
durchaus sinnvoll sein kann und wer das Beispiel verwenden und weiter ausbauen möchte, sollte es entsprechend ändern. Meine Editierzeit ist abgelaufen, sonst hätte ich es noch geändert. Sehe gerade, Sirius3 hat es zwischenzeitlich geändert. Aber das mit dem not in tagname hatte bei den Testaufrufen funktioniert, doch so ist es besser.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Melewo: es gibt einen Unterschied zwischen, »ich habe das Gefühl, es funktioniert« und »das Programm ist korrekt«.
Lou Cyphr3
User
Beiträge: 59
Registriert: Donnerstag 6. Juli 2017, 00:04

okay, ich werde mir wohl doch nochmal die Basic's ansehen, aber Danke für die rasche Disskusion.
Aber nochmals zu meinen Problemchen mit den Syntax. Ich habe gerade nochmal angefangen bisschen mit der (for)schleife
rum zuspielen.

Code: Alles auswählen

x = ['ja', 'vllt', 'nein']

for w in x:
    print(w)
print('finish')
eigentlich sollte bei diesen simple codeschnippsel nix schief gehen, allerdings gibt er mir mit der Ipython konsole trotzdem
wieder ein Syntax Error aus und zwar beim letzten 'print'. Lass ich es aber über pycharm laufen, funktioniert alles bestens.

Woran liegt das?
Zuletzt geändert von Anonymous am Freitag 7. Juli 2017, 09:47, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Cours, camarade, le vieux monde est derrière toi!
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Dann kopiere die Fehlermeldung, damit die nachvollziehbar oder auswertbar ist.
Bei mir kann ich zumindest nichts sehen, was da einen Fehler auslösen könnte.
Benutzeravatar
/me
User
Beiträge: 3552
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Lou Cyphr3 hat geschrieben:eigentlich sollte bei diesen simple codeschnippsel nix schief gehen, allerdings gibt er mir mit der Ipython konsole trotzdem
wieder ein Syntax Error aus und zwar beim letzten 'print'.
Wenn das mit der interaktiven Konsole so wie bei IDLE läuft, dann solltest du am Ende des Schleifenrumpfs einmal extra die Eingabetaste drücken bevor du den Code fortsetzt.
Antworten