Instanz aus Variable verwenden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
TenchiMuyo1984
User
Beiträge: 18
Registriert: Donnerstag 17. Januar 2019, 21:17

Hallo zusammen,

ich habe ein Problem und weiß keine Lösung :/

Code: Alles auswählen

schilddarstellungen = [
['101-10', 'Gefahrstelle', 'TRUE', 'Zeichen Hundert.ttf', [['drawblack', '1'], ['drawred', '2'], ['drawblack', 'A']]],
['102', 'Kreuzung oder Einmündung', 'TRUE', 'Zeichen Hundert.ttf', [['drawblack', '1'], ['drawred', '2'], ['drawblack', 'B']]],
['103-10', 'Kurve – links', 'TRUE', 'Zeichen Hundert.ttf', [['drawblack', '1'], ['drawred', '2'], ['drawblack', 'D']]]
]

def draw_sign(direction, pos_x, pos_y, size):
    epd = epd4in2b.EPD()
    epd.init()
    
    i = 2   
    
    Blackimage = Image.new('1', (epd4in2b.EPD_HEIGHT, epd4in2b.EPD_WIDTH), 255)  # 126*298
    Redimage   = Image.new('1', (epd4in2b.EPD_HEIGHT, epd4in2b.EPD_WIDTH), 255)  # 126*298
    
    drawblack   = ImageDraw.Draw(Blackimage)
    drawred     = ImageDraw.Draw(Redimage  )
    
    schilddarstellungen[i][4][0][0].text((pos_x, pos_y), str(schilddarstellungen[i][4][0][1]), font = fontzeichen, fill = 0)
Ich möchte die Instanz "drawblack" bzw. "drawred" dynamisch aus meinem Array verwenden, sodass hinterher sowas interpretiert wird:

Code: Alles auswählen

drawblack.text((pos_x, pos_y), '1', font = fontzeichen, fill = 0)
Mein Ziel ist es, eine Schleife um diese Zeile zu bringen, die alle Elemente von [4] in die Instanz "drawblack" und "drawred" übergibt.
Jedoch bekomme ich immer diese Exception:

Code: Alles auswählen

AttributeError: \'str\' object has no attribute \'text\
Ich hoffe ihr könnt mir helfen, oder einen alternativen Lösungsansatz bereitstellen. :D

Grüße
TenchiMuyo1984
Benutzeravatar
__blackjack__
User
Beiträge: 14040
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TenchiMuyo1984: Binde die Bilder nicht an Namen sondern lege sie in einem Wörterbuch ab, mit den Namen als Zeichenketten. Dann kannst Du sie aus diesem Wörterbuch leicht mit der Zeichenkette aus der (unübersichtlichen) Datenstruktur auslesen.

`schilddarstellungen` ist wirklich ziemlich unübersichtlich und so eine Indexorgie wie ``schilddarstellungen[ i ][4][0][0]`` ist schwer verständlich weil man sich magische Indexzahlen merken muss.

Der `str()`-Aufruf in der Zeile macht keinen Sinn da `schilddarstellungen` doch ausschliesslich Zeichenketten enthält.

Ich würde die Datenstruktur so gestalten das man an ihr ablesen kann was die Elemente bedeuten. Also beispielsweise mehr Wörterbücher mit sinnvoll benannten Schlüsseln, oder Datentypen die mit `collections.namedtuple()` erstellt wurden.

Namensschreibweise für alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase) ist in Python klein_mit_unterstrichen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
TenchiMuyo1984
User
Beiträge: 18
Registriert: Donnerstag 17. Januar 2019, 21:17

Hallo __blackjack__
Ob ich das über diese "unübersichtliche" Art gestalte oder nicht, ist erstmal zweitrangig.
Ich bin Arrays von C und Java gewöhnt und hatte auch schon Überlegungen Richtung eines dictionaries angestellt. Jedoch wurde dieses durch meinen Anwendungsfall deutlich unübersichtlicher, weswegen ich zurück zu Arrays gegangen bin.

Hätte dann in etwa so ausgesehen:

Code: Alles auswählen

schilddarstellungen = { 
    'Schildtyp': 'Gefahrstelle', 
    'Schildcode': '101-10',
    'Darstellbarkeit': 'TRUE',
    'Schriftart': 'Zeichen Hundert.ttf',
    'Zeichencodes': {
        'Zeichen_1': {
            'Farbcode': 'drawblack',
            'Zeichencode': '1'
        },
        'Zeichen_2': {
            'Farbcode': 'drawred',
            'Zeichencode': '2'
        },
        'Zeichen_3': {
            'Farbcode': 'drawblack',
            'Zeichencode': 'A'
        }
    }
}
So mit arrays:

Code: Alles auswählen

['101-10', 'Gefahrstelle', 'TRUE', 'Zeichen Hundert.ttf', [['drawblack', '1'], ['drawred', '2'], ['drawblack', 'A']]],
Aber das ist auch nicht meine Frage gewesen.

Wie kann ich eben eine Variable als Instanz inpterpretieren?
Grüße

Edit:
Habe ein paar '' im Code vergessen.

TenchiMuyo1984
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Entscheidung welche Datenstruktur man wählt ist kein entweder oder. Wenn Zeichencodes durchnummerierte Schlüssel haben, dann ist das ein Zeichen dafür, dass DIE eine Liste sein sollten.

Und bezüglich deines Problems: alles in Python ist ein Objekt. So wie in Java (fast) auch alle sein Objekt ist. Ob du darauf nun per Namen oder per Index oder per Schlüssel zugreifst ist vollkommen unerheblich.

Code: Alles auswählen

drawred = ...
drawblack = ...
images = [drawred, drawblack]
images[0].text(...)
other_images = { “red”: drawred, “black”: drawblack }
other_images[“black”].text(....)
TenchiMuyo1984
User
Beiträge: 18
Registriert: Donnerstag 17. Januar 2019, 21:17

Ich habe nun mal ein Schild in ein dictonary gepackt und kann die Inhalte auch aufrufen.
Jedoch bekomme ich immer noch die gleiche Exception:

Code: Alles auswählen

schilddarstellungen2[\'Zeichencodes\'][\'Zeichen_1\'][\'Farbcode\'].text((pos_x, pos_y), schilddarstellungen2[\'Zeichencodes\'][\'Zeichen_1\'][\'Zeichencode\'], font = fontzeichen, fill = 0)
AttributeError: \'str\' object has no attribute \'text\'

Code: Alles auswählen

schilddarstellungen2 = { 
    'Schildtyp': 'Gefahrstelle', 
    'Schildcode': '101-10',
    'Darstellbarkeit': 'TRUE',
    'Schriftart': 'Zeichen Hundert.ttf',
    'Zeichencodes': {
        'Zeichen_1': {
            'Farbcode': 'drawblack',
            'Zeichencode': '1'
        },
        'Zeichen_2': {
            'Farbcode': 'drawred',
            'Zeichencode': '2'
        },
        'Zeichen_3': {
            'Farbcode': 'drawblack',
            'Zeichencode': 'A'
        }
    }
}

def draw_sign(direction, pos_x, pos_y, size):
    epd = epd4in2b.EPD()
    epd.init()
    
    i = 5   
    
    Blackimage = Image.new('1', (epd4in2b.EPD_HEIGHT, epd4in2b.EPD_WIDTH), 255)  # 126*298
    Redimage   = Image.new('1', (epd4in2b.EPD_HEIGHT, epd4in2b.EPD_WIDTH), 255)  # 126*298
    
    drawblack   = ImageDraw.Draw(Blackimage)
    drawred     = ImageDraw.Draw(Redimage  )
    
    fontzeichen   = ImageFont.truetype('Zeichen Hundert.ttf', size)

    print schilddarstellungen2['Schildtyp']
    # gibt mir: 'Gefahrstelle'

    print schilddarstellungen2['Zeichencodes']['Zeichen_1']['Farbcode']
    # gibt mir: 'drawblack'

    schilddarstellungen2['Zeichencodes']['Zeichen_1']['Farbcode'].text((pos_x, pos_y), schilddarstellungen2['Zeichencodes']['Zeichen_1']['Zeichencode'], font = fontzeichen, fill = 0)
    epd.display(epd.getbuffer(Blackimage), epd.getbuffer(Redimage))
    epd.sleep()
Ich möchte die Instanz "drawblack" bzw. "drawred" durch einen String aus einer Variablen austauschen:

von:

Code: Alles auswählen

drawblack.text((pos_x, pos_y), schilddarstellungen2['Zeichencodes']['Zeichen_1']['Zeichencode'], font = fontzeichen, fill = 0)
zu:

Code: Alles auswählen

schilddarstellungen2['Zeichencodes']['Zeichen_1']['Farbcode'].text((pos_x, pos_y), schilddarstellungen2['Zeichencodes']['Zeichen_1']['Zeichencode'], font = fontzeichen, fill = 0)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

entweder schlägst du den Namen in einem Wörterbuch exakt so wie ich es hinschrieb nach BEVOR du text () aufrufst.

Oder du steckst halt die Instanzen gleich rein.
TenchiMuyo1984
User
Beiträge: 18
Registriert: Donnerstag 17. Januar 2019, 21:17

Ahh, jetzt habe ich es verstanden.
Du hast das über die Variablen drawred und drawblack gemacht. Ich habe die als string versucht in instanzieren ....
Wenn ich diese nun zu variablen umbenenne (Hochkomma entferne) und das dictionary mit in die Funktion schmeiße klappt es.

Aber wie kann ich es schaffen, dass ich das dictionary nicht mit in der Funktion haben muss?
Oder du steckst halt die Instanzen gleich rein.
Ich bekomme so immer eine Exception (was mir auch klar ist)

Code: Alles auswählen

NameError: global name \'drawblack\' is not defined
Sirius3
User
Beiträge: 18269
Registriert: Sonntag 21. Oktober 2012, 17:20

Alles, was eine Funktion braucht, sollte sie über ihre Argumente bekommen. Die Funktion soll ja nicht nur ein Schild zeichnen können:

Code: Alles auswählen

schilddarstellungen2 = { 
    'Schildtyp': 'Gefahrstelle', 
    'Schildcode': '101-10',
    'Darstellbarkeit': 'TRUE',
    'Schriftart': 'Zeichen Hundert.ttf',
    'Zeichencodes': [
        {'farbe': 'black', 'zeichen': '1'},
        {'farbe': 'red', 'zeichen': '2'},
        {'farbe': 'black', 'zeichen': 'A'},
    ]
}

def draw_sign(sign, pos_x, pos_y, size):
    epd = epd4in2b.EPD()
    epd.init()
    
    image_black = Image.new('1', (epd4in2b.EPD_HEIGHT, epd4in2b.EPD_WIDTH), 255)  # 126*298
    image_red = Image.new('1', (epd4in2b.EPD_HEIGHT, epd4in2b.EPD_WIDTH), 255)  # 126*298
    draw = {
        'black': ImageDraw.Draw(image_black),
        'red': ImageDraw.Draw(image_red),
    }
    fontzeichen = ImageFont.truetype(sign['Schriftart'], size)
    for code in sign['Zeichencodes']:
        draw[code['farbe']].text((pos_x, pos_y),
            code['zeichen'], font=fontzeichen, fill=0)
    epd.display(epd.getbuffer(image_black), epd.getbuffer(image_red))
    epd.sleep()
Benutzeravatar
__blackjack__
User
Beiträge: 14040
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich persönlich verwende bei so etwas dann auch noch gerne das externe `addict.Dict` um den Code dann mit Attributzugriffen schreiben zu können:

Code: Alles auswählen

    fontzeichen = ImageFont.truetype(sign.Schriftart, size)
    for code in sign.Zeichencodes:
        draw[code.farbe].text(
            (pos_x, pos_y), code.zeichen, font=fontzeichen, fill=0
        )
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten