NoneType' object has no attribute 'execute'

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
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Hallo Leute, ich bin dabei eine Datenbank Klasse zu erstellen und komme nicht weiter.

Ich erhalte ein <NoneType' object has no attribute 'execute'> und weiß nicht wieso.
Ich habe gegooglet aber half nichts. Hat jemand eine Idee?

Gruß Tron

Code: Alles auswählen

import mysql.connector
import sys

class databaseconnection:
    host = username = password = database = connection = cursor = None

    def __init__(self, host, username, password, database):
        self.host = host
        self.username = username
        self.password = password
        self.database = database

    def Connect(self):
        config = {
            'user': self.username,
            'password': self.password,
            'host': self.host,
            'database': self.database
        }
        try:
            self.connection = mysql.connector.connect(**config)
            self.cursor = self.connection.cursor()
            print("Verbunden")

        except mysql.connector.Error as error:
            print("Verbindungs Fehler: {}".format(error))

    def QuerySelect(self, sqlstatement):

            try:
                self.cursor.execute(sqlstatement) # <<< line 31, in QuerySelect - self.cursor.execute(sqlstatement) - AttributeError: 'NoneType' object has no attribute 'execute'
                return_value = self.cursor.fetchall()
                for row in return_value:
                    return row

                print("Aufruf erfolgreich")

            except mysql.connector.Error as error:
                print("Aufruf fehlgeschlagen: {}".format(error))
                return False

    def Disconnect(self):
        self.connection.close()
        print("Verbindung geschlossen")


v1 = databaseconnection("localhost", "mysql", "****************", "Video_Database")

# v1.QuerySelect("SELECT fi_title, fi_year FROM Video_Database.Movies WHERE `fi_file_id`='1' AND `fi_TMDb_Title` IS NULL")
v1.QuerySelect("SELECT fi_title, fi_year FROM Video_Database.Movies WHERE fi_file_id=1 AND fi_TMDb_Title IS NULL")




Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

v1 ist ein superschlechter Name für eine Instanz der Klasse.
Benutze vernünftige, aussagekräftige Namen.

Variablen und Funktionsnamen schreibt man in Python klein_mit_unterstrich, Klassennamen MixedCase und Konstanten KOMLPETT_GROSS.
Was soll denn diese Zeile

Code: Alles auswählen

host = username = password = database = connection = cursor = None
? Mach die weg. Die tut nicht, was du denkst. Und die Fehlermeldung, die dann kommt, die ist dann auch viel aussagekräftiger.

Wo genau weist du denn self.cursor ein Objekt zu?
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Hallo sparrow, vielen Dank für Deine Hilfe,
sparrow hat geschrieben: Montag 11. Mai 2020, 10:15 Wo genau weist du denn self.cursor ein Objekt zu?
Ich dachte das mache ich mit

Code: Alles auswählen

self.cursor = self.connection.cursor()
Aber das ist ja nicht der Fall wie es scheint.

Code: Alles auswählen

AttributeError: 'DatabaseConnection' object has no attribute 'cursor'
Da fehlt was. Aber ich weiß nicht was es ist bzw. wie ich self.cursor einem Objekt zuweise und bräuchte dabei bitte Eure Hilfe.
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Aber wann wird das denn aufgerufen?
Du hast das in eine Methode gekapselt. Rufst du die auf?
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Das will ich damit machen:

Code: Alles auswählen

    def query_select(self, sqlstatement):

            try:
                self.cursor.execute(sqlstatement)
                return_value = self.cursor.fetchall()
                for row in return_value:
                    return row
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Ja, aber die _Zuweisung_ von self.cursor tust du in einer anderen Methode.
Und die rufst du nie auf.

Du hast in der Klasse DatabaseConnection 3 Methoden: __init__, connect und query_select. (ich habe mir erlaubt die Schreibweisen anzupassen).
Wenn du in query_select self.cursor verwenden willst, musst du es in einer der anderen Methoden auch zuweisen.
Das tust du zwar in connect - aber connect rufst du nie auf.
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Ah, verstehe. Ich versuch das mal zu fixen. Ich danke Dir.
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Leider bekomme ich das immer noch nicht zum laufen. Ich habe aus der query_select() die self.connect() Methode aufgerufen aber es kommt immer noch noch der
<AttributeError: 'DatabaseConnection' object has no attribute 'cursor'> Fehler zurück.

Aberzusätzlich habe ich jetzt eine Verbindungsfehler zurück bekommen
<Verbindungs Fehler: 1698 (28000): Access denied for user 'mysql'@'localhost'>

Aber ich weiß echt nicht was ich noch machen soll.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Der zweite Fehler ist doch eindeutig: Du darfst Dich nicht verbinden.
Und der erste Fehler kommt daher, dass Deine Fehlerbehandlung des anderen Fehler, fehlerhaft ist, weil Du einfach weiter machst, als ob nichts gewesen wäre.
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Hallo Sirius3, ich weiß dass meine Fehlerbehandlung fehlerhaft ist. Das liegt daran, dass ich es nicht besser weiß und es deshalb bei dem Versuch bleibt den Fehler zu beheben.
Und da ich es nicht besser weiß probiere ich das was ich kenne und was ich im Internet finde. Der Methode "connect" gebe ich jetzt den Parameter cursor=""

Code: Alles auswählen

   def connect(self, cursor=""):
        self.cursor = cursor
Ob das jetzt das richtige ist weiß ich nicht. Aber der <AttributeError: 'DatabaseConnection' object has no attribute 'cursor'> wird jetzt nicht mehr angezeigt.

Dafür habe ich jetzt den Fehler <AttributeError: 'str' object has no attribute 'execute'>. Und ich weiß nicht ob das jetzt ein Fortschritt oder Rückschritt ist.
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Tron0070 hat geschrieben: Montag 11. Mai 2020, 18:39 Und da ich es nicht besser weiß probiere ich das was ich kenne und was ich im Internet finde.
Aber ohne es zu verstehen. Mit "Code raten" wird da kein vernünftig lauffähiges Programm herauskommen. Was erwartest du denn, was deine connect-Methode tun soll und warum hat sie eine leere Zeichenkette als Default-Parameter für den cursor? War nicht eigentlich die Absicht, dass in connect das cursor-Attribut der Klasse gesetzt wird?
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Mit fehlerhafter Fehlerbehandlung meine ich, dass Du zwar mit `except` einen Fehler abfängst, dann aber so weiter machst, als ob nichts passiert wäre. Wenn ein Fehler nicht sinnvoll behandelt werden kann, dann macht man das gar nicht. Denn dann taucht gleich der entscheidende Fehler auf, nämlich der, dass Du Dich nicht verbinden kannst: Access denied.
Hast Du denn auf anderem Weg es schon geschafft, mit diesem Nutzer und Passwort Dich mit der Datenbank zu verbinden?
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

/me hat geschrieben: Montag 11. Mai 2020, 18:43 ..und warum hat sie eine leere Zeichenkette als Default-Parameter für den cursor?
Das sollte eigentlich das 'cursor' attribute setzten ohne was zu übergeben. Dadurch verschwand auch diese Fehlerausgabe.
Sirius3 hat geschrieben: Montag 11. Mai 2020, 18:48 Hast Du denn auf anderem Weg es schon geschafft, mit diesem Nutzer und Passwort Dich mit der Datenbank zu verbinden?
Ja, habe ich. Ich habe es eben probiert. Dabei fiel mir auf das sich ein Fehler eingeschlichen hat

Jetzt funktioniert es soweit das ich einen Datensatz aus der Datenbank bekomme. Es gibt noch ein paar Sachen die nicht ganz stimmen, aber das schaue ich mir selbst erst mal an und würde dieses Thema schließen.

Ich danke Euch allen vielmals für Eure Geduld und kompetente Hilfe.

Gruß Tron

PS. @sparrow schrieb noch "Konstanten KOMLPETT_GROSS" schreiben.Ich bin mir nicht sicher welche gemeint sind. War damit das CONFIG = { gemeint?
Hier noch mal der vorerst aktuelle code der einen Datensatz abruft:

Code: Alles auswählen

import mysql.connector


class DatabaseConnection:

    def __init__(self, host, username, password, database):
        self.host = host
        self.username = username
        self.password = password
        self.database = database


    def connect(self):
        config = {
            'user': self.username,
            'password': self.password,
            'host': self.host,
            'database': self.database
        }
        try:
            self.connection = mysql.connector.connect(**config)
            self.cursor = self.connection.cursor()

            print("Verbunden")

        except mysql.connector.Error as error:
            print("Verbindungs Fehler: {}".format(error))

    def query_select(self, sqlstatement):

        try:
            self.connect()
            self.cursor.execute(sqlstatement)
            return_value = self.cursor.fetchall()
            for row in return_value:
                return row

            print("Aufruf erfolgreich")

        except mysql.connector.Error as error:
            print("Aufruf fehlgeschlagen: {}".format(error))
            return False

    def disconnect(self):
        self.connection.close()
        print("Verbindung geschlossen")


zugangsdaten = DatabaseConnection("localhost", "mysql", "****************", "Video_Database")

print(zugangsdaten.query_select("SELECT fi_title, fi_year FROM Video_Database.Movies WHERE `fi_file_id`='1' AND `fi_TMDb_Title` IS NULL"))




Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tron0070: Das mag zwar ”funktionieren” aber die Klasse ist ziemlich kompletter Murks und ich sehe auch nicht wie man die reparieren könnte, denn die macht einfach keinen Sinn und bis auf `disconnect()` macht jede Methode etwas falsch(es).
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

In __init__ sollten alle Attribute schon angelegt werden, auch wenn sie nur den Wert None erhalten, damit man gleich sehen kann, was alles existieren kann.
cursor sind etwas kurzlebiges, das nicht als Attribut existieren sollte, sondern nur als lokale Variable.
Die fehlerhafte Fehlerbehandlung ist immer noch drin, einfach ersatzlos löschen.
**-Magie wird völlig unnötigerweise eingesetzt, weil man direkt Keyword-Argumente übergeben könnte.
Eine for-Schleife, die gleich beim ersten Durchlauf per return verlassen wird, sieht wie ein Fehler aus. Du willst da fetchone benutzen, statt fetchall. Exceptions sind dazu da, dass man Fehler erkennt, nicht dass man sie durch ein nichtssagendes False ersetzt.

Eine Datenbankinstanz `zugangsdaten`, wo aber dann Filmtitel abgefragt werden, ist sehr überraschend. Wenn da keine Zugangsdaten drin sind, sollte die Variable auch nicht so heißen.

Wenn man aufräumt, bleibt also das:

Code: Alles auswählen

import mysql.connector

class DatabaseConnection:
    def __init__(self, host, username, password, database):
        self.host = host
        self.username = username
        self.password = password
        self.database = database
        self.connection = None

    def connect(self):
        self.connection = mysql.connector.connect(
            user=self.username,
            password=self.password,
            host=self.host,
            database=self.database
        )

    def query_select(self, sqlstatement):
        if self.connection is None:
            raise RuntimeError("not connected")
        try:
            cursor = self.connection.cursor()
            cursor.execute(sqlstatement)
            return cursor.fetchone()
        finally:
            cursor.close()

    def disconnect(self):
        if self.connection is not None:
            self.connection.close()
            self.connection = None


movies = DatabaseConnection("localhost", "mysql", "****************", "Video_Database")
movies.connect()
print(movies.query_select("SELECT fi_title, fi_year FROM Video_Database.Movies WHERE `fi_file_id`='1' AND `fi_TMDb_Title` IS NULL"))
Das ist nicht viel mehr, als `mysql.connector` eh schon als Interface hat, nur dass query_select viel unflexibler ist, als direkt ein execute mit fetch.
Tron0070
User
Beiträge: 24
Registriert: Dienstag 28. April 2020, 12:57

Hallo Sirius3, vielen Dank für den aufgeräumten code.
Sirius3 hat geschrieben: Montag 11. Mai 2020, 21:04 Das ist nicht viel mehr, als `mysql.connector` eh schon als Interface hat, nur dass query_select viel unflexibler ist, als direkt ein execute mit fetch.
Meinst du damit, dass es in diesem Umfang nicht nötig ist es in eine Klasse zu schreiben? Fall ja: Ich hatte nämlich vor, die Klasse später noch mit einem query_insert und evtl. query_update Methode zu erweitern.



Mit `fetchone` habe ich Fehler zurück bekommen aber mit `fetchall` funktioniert es.

Code: Alles auswählen

Traceback (most recent call last):
  File "Tools/PY/DB.py", line 38, in <module>
    print(movies.query_select("SELECT fi_title, fi_year FROM Video_Database.Movies WHERE `fi_file_id`='1' AND `fi_TMDb_Title` IS NULL"))
  File "Tools/PY/DB.py", line 28, in query_select
    cursor.close()
  File "/usr/lib/python3.8/site-packages/mysql/connector/cursor.py", line 395, in close
    self._connection.handle_unread_result()
  File "/usr/lib/python3.8/site-packages/mysql/connector/connection.py", line 1177, in handle_unread_result
    raise errors.InternalError("Unread result found")
mysql.connector.errors.InternalError: Unread result found
Aber ich kann jetzt erstmal mit dem Projekt weiter machen.

Nochmals vielen Dank an alle beteiligten. Ihr wart eine große Hilfe.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Ah, interessant, dass mysql.connector einen zwingt, alle Ergebnisse abzufragen. Das ist ein nicht-standard-Verhalten.
Bedeutet aber auch, dass ein SELECT-Ausdruck mehr als ein Ergebnis liefert, und zwar irgendeins. Da stellt sich mir natürlich die Frage, ist das Absicht? Wenn ja, muß man bei SELECT ein LIMIT angeben, damit auch wirklich nur 1 Ergebnis geliefert wird.
Antworten