简体   繁体   中英

Python object has no attribute

I've got a strange problem. I've got a test script where it works. Now i have used the same code i my main script and now it's not working and i can't se why not. So i hope someone can see what went wrong.

When i run the script i throws an error:

File "E:/Python/Amp_Glade_1.py", line 226, in
  on_volume_scale_value_changed
    self.update_control("volume", x)
File "E:/Python/Amp_Glade_1.py", line 264, in update_control
    self.control[self.name] = self.value
AttributeError: 'GTK_Main' object has no attribute 'control'

So in:

def on_volume_scale_value_changed(self, object, data=None):
    x = int(self.volume.get_value())
    y = self.volume_step[x]
    self.label_volume.set_text(str(y))
    self.update_control("volume", x)

I call:

def update_control(self, name, value):
    self.name = name
    self.value = value
    self.control[self.name] = self.value

And i can't see what will cause that error, as it is working in my test script. This is the dict that is self.control:

self.control = {"volume": 3, "bass": 0,
                    "middle": 0, "treble": 0,
                    "center": 16, "pre_gain": 0}

This is the script:

#!/usr/bin/env python
'''
GUI / Amlifier control
Connects to ESP8266 on wifi
Controls Pre-Amp and Amplifier

'''

try:
    import os
 except:
    print ("No os")

try:
    import thread
 except:
print ("No thread")

try:
    import gi
except:
    print ("No gi")

try:
    import sys
except:
    print ("No sys")

try:
    gi.require_version('Gtk', '3.0')
    from gi.repository import GObject, Gtk as Gtk
except:
    print ("No Gtk")

try:
    import socket
except:
    print ("No socket")

try:
    from datetime import datetime, timedelta
except:
    print ("No datetime, timedelta")

try:
    # neede for window.get_xid(), xvimagesink.set_window_handle(),     respectively:
    gi.require_version('GdkX11', '3.0')
    from gi.repository import GdkX11
except:
    print ("No GdkX11")
    sys.exit()


class GTK_Main(object):

    def __init__(self, sock=None):

        ## Create window
        self.gladefile  = ("Amp_2.glade")
        self.builder = Gtk.Builder()
        self.builder.add_from_file(self.gladefile)
        self.builder.connect_signals(self)

        ## Create objects by name frpm gladefile
        self.window = self.builder.get_object("window")
        self.Store = self.builder.get_object("Store")
        self.Mute = self.builder.get_object("Mute")
        self.Load = self.builder.get_object("Load")
        self.Reset = self.builder.get_object("Reset")
        self.bass = self.builder.get_object("bass_scale")
        self.middle = self.builder.get_object("middle_scale")
        self.treble = self.builder.get_object("treble_scale")
        self.volume = self.builder.get_object("volume_scale")
        self.pre_gain = self.builder.get_object("gain")
        self.center = self.builder.get_object("center_scale")
        self.label_bass = self.builder.get_object("label_bass")
        self.label_middle = self.builder.get_object("label_middle")
        self.label_treble = self.builder.get_object("label_treble")
        self.label_volume = self.builder.get_object("label_volume")
        self.label_pre_gain = self.builder.get_object("label_gain")
        self.label_center = self.builder.get_object("label_center")
        self.label_IP = self.builder.get_object("label_IP")
        self.label_Port = self.builder.get_object("label_Port")
        self.label_connected = self.builder.get_object("label_connected")
        self.image_mute = self.builder.get_object("image1")
        self.image_radio_1 = self.builder.get_object("image2")
        self.image_radio_2 = self.builder.get_object("image3")
        self.image_radio_3 = self.builder.get_object("image4")
        self.image_radio_4 = self.builder.get_object("image5")
        self.radiobutten_1 = self.builder.get_object("radiobutton1")
        self.radiobutten_2 = self.builder.get_object("radiobutton2")
        self.radiobutten_3 = self.builder.get_object("radiobutton3")
        self.radiobutten_4 = self.builder.get_object("radiobutton4")

        self.window.show_all()

        ## Set init values
        self.mute_state = False
        self.center.set_value(16)

        self.host = '192.168.0.23'
        self.port = 8888

        ## Create TCP socket
        if sock is None:
            self.sock = socket.socket(socket.AF_INET,
                                  socket.SOCK_STREAM)
        else:
            self.sock = sock

        self.connect(self.host, self.port)

        ## Scale steps
        self.volume_step = (-40, -32. -24, -16, -8, -7,
                        -6, -5, -4, -3, -2, -1, 0)

        self.pre_gain_step = (0, 2, 4, 6, 8, 10, 12, 14,
                          16, 18, 20, 22, 24, 26, 28, 30)

        self.bass_step = (-14, -12, -10, -8, -6, -4, -2, 0,
                      2, 4, 6, 8, 10, 12, 14)

        self.middle_step = (-14, -12, -10, -8, -6, -4, -2, 0,
                      2, 4, 6, 8, 10, 12, 14)

        self.treble = (-14, -12, -10, -8, -6, -4, -2, 0,
                      2, 4, 6, 8, 10, 12, 14)

        self.right_step = (0, -1, -2, -3, -4, -5, -6,
                       -7, -8, -16, -24, -32,
                       -40, -48, -56, -64, -72)

        self.left_step = (0, -1, -2, -3, -4, -5, -6,
                       -7, -8, -16, -24, -32,
                       -40, -48, -56, -64, -72)

        ## Set init scale values
        self.volume.set_value(3)

        ## JSON
        self.control = {"volume": 3, "bass": 0,
                    "middle": 0, "treble": 0,
                    "center": 16, "pre_gain": 0}

        ## Graphic elements to control
        self.GUI_labels = {"volume": self.label_volume,
                       "bass": self.label_bass,
                       "middle": self.label_middle,
                       "treble": self.label_treble,
                       "center": self.label_center,
                       "pre_gain": self.label_pre_gain}

        self.GUI_items = {"volume": self.volume, "bass": self.bass,
                      "middle": self.middle, "treble": self.treble,
                      "center": self.center, "pre_gain": self.pre_gain}

        ## start ping to server
        thread.start_new_thread(self.ping_send(), )

        ## Create handles
    def on_window_destroy(self, obkect, data=None):
        self.sock.close()
        thread.exit()
        Gtk.main_quit()

    def connect(self, host, port):
        try:
            self.sock.connect((self.host, self.port))
            self.label_connected.set_text("Connection:")
            self.label_IP.set_text(self.host)
            self.label_Port.set_text(str(self.port))
        except Exception as e:
            print("No connection. Exceptions is %s:" % (e))
            self.label_connected.set_text("No connection")

        return None

    def on_Mute_released(self, object, data=None):
        if not self.mute_state:
            self.image_mute.set_from_file("circle_red_small.png")
            self.mute_state = True
        else:
            self.image_mute.set_from_file("circle_blue_small.png")
            self.mute_state = False

    def on_radiobutton1_pressed(self, object, data=None):
        self.image_radio_1.set_from_file("circle_green_small.png")
        self.image_radio_2.set_from_file("circle_blue_small.png")
        self.image_radio_3.set_from_file("circle_blue_small.png")
        self.image_radio_4.set_from_file("circle_blue_small.png")

    def on_radiobutton2_pressed(self, object, data=None):
        self.image_radio_2.set_from_file("circle_green_small.png")
        self.image_radio_1.set_from_file("circle_blue_small.png")
        self.image_radio_3.set_from_file("circle_blue_small.png")
        self.image_radio_4.set_from_file("circle_blue_small.png")

    def on_radiobutton3_pressed(self, object, data=None):
        self.image_radio_3.set_from_file("circle_green_small.png")
        self.image_radio_1.set_from_file("circle_blue_small.png")
        self.image_radio_2.set_from_file("circle_blue_small.png")
        self.image_radio_4.set_from_file("circle_blue_small.png")

    def on_radiobutton4_pressed(self, object, data=None):
        self.image_radio_4.set_from_file("circle_green_small.png")
        self.image_radio_1.set_from_file("circle_blue_small.png")
        self.image_radio_2.set_from_file("circle_blue_small.png")
        self.image_radio_3.set_from_file("circle_blue_small.png")

    def on_Reset_released(self, object, data=None):
        pass

    def on_Store_released(self, object, data=None):
        pass

    def on_Load_released(self, object, data=None):
        pass

    def on_center_scale_value_changed(self, object, data=None):
        pass

    def on_volume_scale_value_changed(self, object, data=None):
        x = int(self.volume.get_value())
        y = self.volume_step[x]
        self.label_volume.set_text(str(y))
        self.update_control("volume", x)

    def on_bass_scale_value_changed(self, object, data=None):
        pass

    def on_middle_scale_value_changed(self, object, data=None):
        pass

    def on_treble_scale_value_changed(self, object, data=None):
        pass

    def on_gain_scale_value_changed(self, object, data=None):
        pass

    def ping_send(self):
        now = datetime.now()
        next_ping= now + timedelta(hours = 0, minutes = 0, seconds = 5)
        while True:
            if next_ping <= datetime.now():
                self.mysend("OK")
                now = next_ping
                next_ping = datetime.now() + timedelta(hours = 0, minutes     = 0,
                                               seconds = 5)
            while Gtk.events_pending():
                Gtk.main_iteration()

    def mysend(self, msg):
        totalsent = 0
        MSGLEN = len(msg)
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("Socket connection broken")
            totalsent = totalsent + sent

    def update_control(self, name, value):
        self.name = name
        self.value = value
        self.control[self.name] = self.value

    def write_json(self):
        with open("amp.dat", "w+") as jsonFile:
            jsonFile.write(json.dumps(self.control))
            jsonFile.close()

    def load_json(self):
        with open("amp.dat", "r") as jsonFile:
            data = json.load(jsonFile)
            jsonFile.close()
            self.control = json.dumps(data)

    def update_GUI(self):
        for key in self.control.items():
            if key == "gain":
                pass
            else:
                x = self.GUI_labels[key]
                x.set_text(str(value))
                y = self.GUI_items[key]
                y.set_value(value)


GObject.threads_init()
GTK_Main() 
Gtk.main()

So mayby someone can tell whats wrong? I would really appreciate it.

There are a number of issues with this code. I will first state what I think is the problem and how to solve that, but then move on to other issues.


There is a lot of non-obvious stuff going on here, and I imagine it is because the GTK framework is doing some things implicitly. For example, I note that GTK_Main is instantiated but the resulting object is never saved anywhere. My guess is that there is some sort of weird nested dependency that occurs when you do

        self.builder = Gtk.Builder()
        ...
        self.builder.connect_signals(self)

and that somehow the this allows the instantiated object to connect with the GTK event loop.

I also suspect that somehow the builder expects that this object implement methods like on_volume_scale_value_changed that are to be executed when the volume scale value changes.

If this is true, then the following code causes the error

        ## Set init scale values
        self.volume.set_value(3)

        ## JSON
        self.control = {"volume": 3, "bass": 0,
                    "middle": 0, "treble": 0,
                    "center": 16, "pre_gain": 0}

This would be because setting the volume would trigger the on_volume_scale_value_changed to be called, which attempts to access self.control , but you do not define self.control till after the volume is set. Reversing the order should fix the problem.

In general, you should

  1. always set data members (like self.control , since it just holds data) before performing any logic (like setting the volume), and
  2. Be aware of the order things are called so you don't get into loops like this.

Having said that, the next problem you will have is here:

    def load_json(self):
        with open("amp.dat", "r") as jsonFile:
            data = json.load(jsonFile)
            jsonFile.close()
            self.control = json.dumps(data)

self.control should be a dictionary, yet you are setting it to the output of json.dumps which will be a string. So if you ever call that function your code will stop working. You should just do self.control = json.load(jsonFile) .

Additionally, in a context manager (the with block) a file is automatically closed upon exit, so calling jsonFile.close() explicitly is redundant at best - at worst it might raise an error when exiting the with block because the file is already closed.


All of the

try:
    import sys
 except:
    print ("No sys")

is very bad for the following reasons

  1. You are doing a blanket except , rather than catching a specific error. I am assuming you are trying to catch ImportError , so you should do except ImportError . You have know idea what other types of exceptions could be raised, so you don't know what could be swallowed and leave your system in an invalid state. Which brings me to
  2. You are trying to import a module, but if that fails you are just printing that it doesn't exist and moving on. In the case of os and sys that's fine since you never use os (though I would say you should avoid importing things you do not use) and sys is only used for sys.exit() (which would trigger an exit anyway since sys is missing), but what if datetime couldn't be imported? You use datetime in your code, so your code might run for who knows how long then suddenly fail when you try to use datetime . In general it is MUCH better to fail early and descriptively rather than leave your system in a broken state which could fail at any time.
  3. Most of the imports you are doing this with are from the standard library. If something from the standard library is missing then there is a problem. Especially sys ... I don't think python can start without sys .
  4. If a module does not exist, it will raise an ImportError and tell the user it does not exist, then halt code. This is what you want, since if GTK were missing you couldn't run your code anyway.

Moral: NEVER swallow errors and keep on going, because it leaves your system in a broken state where things can fail at any time for no apparent reason.

I hope this is just a typo onkect here, and not in the actual code?

 def on_window_destroy(self, obkect, data=None):
         self.sock.close()
         thread.exit()
         Gtk.main_quit()

It must be a some kind of bug in the compiler. After done a hole lot of testing, commented out several regions, made new variables it stills create an error on start up. But how ever, the function works as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM