2016-10-13 2 views
1

У меня есть программа, которая имеет gui в PyQt в основном потоке. Он связывается с фотодетектором и получает показания мощности в другом потоке, который посылает сигнал в основной поток, чтобы обновить значение мощности gui. Теперь я хочу использовать двигатель для автоматического выравнивания оптического волокна, получения обратной связи с фотодетектором.Ребенок, вызывающий родительский метод без вызова родительского __init__ в python

Итак, я создал класс, который управляет двигателями, но мне нужно как-то передать показания фотодетекторов этому классу. Во-первых, я попытался получить доступ к переменной мощности родителя, но это не сработало. Затем я создал метод в моем gui, чтобы вернуть значение переменной и попытался получить к нему доступ из класса motor. У меня возникла проблема, говоря, что я не мог использовать метод родителя, не используя сначала его __init__. Есть ли способ обойти его? Я не могу снова вызвать gui __init__, я просто хочу использовать один из его методов из дочернего класса.

Если есть альтернативный способ сделать это, я был бы счастлив.

PS: Я думаю, я не могу дать ребенку класс объекта фотодетекторов, потому что он находится в другом потоке, верно?

--Edit-- графического пользовательского интерфейса код:

class MyApp(QtGui.QMainWindow, Ui_MainWindow): 
    self.PDvalue = 0 #initial PD value 
    self.PDState = 0 #control the PD state (on-off) 
    self.PDport = self.dialog.pm100d.itemText(self.dialog.pm100d.currentIndex()) #gets pot info 

    def __init__(self): 
    ... #a lot of other stuff 
    self.nano = AlgoNanoMax.NanoMax('COM12') #creates the motor object 
    self.nano_maxX.clicked.connect(self.NanoMaximizeX) #connect its fun to a buttom 
    self.actionConnect_PM100D.triggered.connect(self.ActionConnect_PM100D) #PD buttom 

    def NanoMaximizeX(self): 
     self.nano.maximize_nano_x() #uses motor object function 

    def ActionConnect_PM100D(self): 
     if self.PDState == 0: #check if PD is on 
      self.PD = PDThread(self.PDState, self.PDport) #creates thread 
      self.PD.valueupdate.connect(self.PDHandler) #signal connect 
      self.PD.dialogSignal.connect(self.PDdialog) #create error dialog 
      self.threads = [] 
      self.threads.append(self.PD) 
      self.PD.start() #start thread 
     else: 
      self.PDState = 0 
      self.PD.state = 0 #stop thread 
      self.startpd.setText('Start PD') #change buttom name 


    def PDHandler(self, value): 
     self.PDvalue = value #slot to get pow from thread 

    def ReturnPow(self): 
     return self.PDvalue #return pow (I tried to use this to pass to the motor class) 

    def PDdialog(self): 
     self.dialog.set_instrument('PM100D') #I have a dialog that says error and asks you to type the right port 
     if self.dialog.exec_() == QtGui.QDialog.Accepted: #if Ok buttom try again 
      ret = self.dialog.pm100d.itemText(self.dialog.pm100d.currentIndex()) #new port 
      self.PD.port = str(ret) 
      self.PD.flagWhile = False #change PD stop loop condition to try again 
     else: #pressed cancel, so it gives up 
      self.PD.photodetector.__del__() #delete objects 
      self.PD.terminate() #stop thread 
      self.PD.quit() 

Теперь класс PD, который находится в другом потоке, но в том же файле графического интерфейса:

class PDThread(QtCore.QThread): 

valueupdate = QtCore.pyqtSignal(float) #creating signals 
dialogSignal = QtCore.pyqtSignal() #signal in case of error 
state = 1 #used to stop thread 

def __init__(self, state, port): 
    QtCore.QThread.__init__(self) 
    self.photodetector = PM100D() #creates the PD object 
    self.port = port 

def run(self): 
    while True: 
     self.flagWhile = True #used to leave while 
     try: 
      self.photodetector.connect(self.port) #try to connect 
     except: 
      self.dialogSignal.emit() #emit error signal 
      while self.flagWhile == True: 
       time.sleep(0.5) #wait here until user press something in the dialog, which is in another thread 
     else: 
      break #leave loop when connected 

    window.PDState = 1 #change state of main gui buttom (change functionality to turn off if pressed again) 
    window.startpd.setText('Stop PD') #change buttom label 
    while self.state == 1: 
     time.sleep(0.016) 
     value = self.photodetector.get_pow() #get PD pow 
     self.valueupdate.emit(value) #emit it 

Файл AlgoNanoMax :

import gui 
from NanoMax import Nano 

class NanoMax(gui.MyApp): #inheriting parent 

def __init__(self, mcontroller_port): 
    self.mcontroller = Nano(mcontroller_port) #mcontroller is the communication to the motor 

def maximize_nano_x(self, step=0.001, spiral_number=3): 
    ''' Alignment procedure with the nano motor X''' 
    print 'Optimizing X' 
    power = super(NanoMax, self).ReturnPow() #here I try to read from the photodetector 
    xpos = self.mcontroller.initial_position_x 
    position = [] 
    position = [[power, xpos]] 
    xsign = 1 
    self.mcontroller.move_relative(self.mcontroller.xaxis, (-1) * spiral_number * step) 
    print 'X nano move: '+ str((-1) * spiral_number * step * 1000) + ' micrometers' 
    time.sleep(4) 
    power = super(NanoMax, self).ReturnPow() 
    xpos += (-1) * spiral_number * step 
    position.append([power, xpos]) 
    for _ in xrange(2*spiral_number): 
     self.mcontroller.move_relative(self.mcontroller.xaxis, xsign * step) 
     print 'X nano move: '+ str(xsign * step * 1000) + ' micrometers' 
     time.sleep(5) 
     power = super(NanoMax, self).ReturnPow() 
     xpos += xsign * step 
     position.append([power, xpos]) 
    pospower = [position[i][0] for i in xrange(len(position))] 
    optimalpoint = pospower.index(max(pospower)) 
    x_shift = (-1) * (xpos - position[optimalpoint][1]) 
    print 'Maximum power: ' + str(max(pospower)) + ' dBm' 
    print 'Current power: ' + str(super(NanoMax, self).ReturnPow()) + ' dBm' 
    self.mcontroller.move_relative(self.mcontroller.xaxis, x_shift) 
+1

_I пытался получить доступ к мощности variable_ родителя ... родитель ? Этот класс моторов наследуется от класса GUI? Это не кажется правильным или даже полезным. Экземпляр класса двигателя может получить данные от объекта фотодетектора в другом потоке, но может потребоваться блокировка, чтобы сделать его потокобезопасным. Предположим, ваш фотодетектор имеет метод геттера, который использует 'threading.Lock' для чтения данных. – tdelaney

+0

Не могли бы вы поделиться своим кодом? В идеале не все это, но, по крайней мере, классы и линии, где они общаются между собой? – brandizzi

ответ

1

__init__ для NanoMax и MyApp должен позвонить super().__init__(), чтобы обеспечить инициализацию для всех уровней (если это Python 2, вы не можете использовать no-arg super, поэтому это будет super(NanoMax, self).__init__() и super(MyApp, self).__init__() соответственно). Это предполагает, что PyQT был правильно написан с классами нового стиля и исправить использование самого super; вы используете super в других местах, поэтому, по-видимому, по крайней мере первое верно. Использование super во всех классах гарантирует, что все уровни равны __init__ - один раз, тогда как перечисление суперклассов вручную не будет работать в определенных шаблонах наследования или может называть некоторое число __init__ несколько раз или вообще не работать.

Если есть вероятность того, что много уровней может принимать аргументы, вы должны также принять *args/**kwargs и направить их на super().__init__ вызова, так что аргументы передаются куда затем нужно идти.

Объединение двух, ваш код должен выглядеть следующим образом:

class MyApp(QtGui.QMainWindow, Ui_MainWindow): 
    def __init__(self, *args, **kwargs): 
     super(MyApp, self).__init__(*args, **kwargs) 
     ... rest of __init__ ... 

class PDThread(QtCore.QThread): 
    def __init__(self, state, port, *args, **kwargs): 
     super(PDThread, self).__init__(*args, **kwargs) 
     ... 

class NanoMax(gui.MyApp): #inheriting parent 

    def __init__(self, mcontroller_port, *args, **kwargs): 
     super(NanoMax, self).__init__(*args, **kwargs) 
     self.mcontroller = Nano(mcontroller_port) #mcontroller is the communication to the motor 

Примечание: Если вы перегружены методы, супер класс может поставить в его __init__ и ваши перегрузках зависят от состояния устанавливается в собственных __init__, вам нужно настроить это состояние раньше, а не после вызова super().__init__(...). Совместное множественное наследование может быть такой болью. Также обратите внимание, что использование позиционных аргументов для чего угодно, кроме класса самого низкого уровня, может быть уродливым с множественным наследованием, поэтому имеет смысл передавать все аргументы по ключевому слову и принимать только **kwargs, а не *args, чтобы люди не передавали позиционные аргументы способами, которые ломаются, если иерархия наследования изменяется незначительно.

+0

Прошу прощения, я не копировал код в свой пост, но инициализирую класс MyApp. Теперь я изменил все '__init__', как вы упомянули, т. Е.' Super (MyApp, self) .__ init __() '. Тем не менее, я получаю бесконечный цикл '__inits'__'. MyApp запускает NanoMax, который запускает конструктор MyApp снова и так далее и так далее. – Eduardo

+0

@Eduardo: Либо вы злоупотребляете «супер» (передавая неправильный тип в качестве первого аргумента), либо ваш код нарушается по дизайну. Вы уверены, что '' __init__' NanoMax' использует 'super (NanoMax, self)' и 'MyApp' использует' super (MyApp, self) '? Даже если так, при перечитывании, скорее всего, неверно, что 'MyApp' создаст экземпляр' NanoMax', когда 'NanoMax'_is_ a' MyApp'; похоже, что вы совмещаете наследование с композицией, ломая оба; если 'NanoMax' является' MyApp', 'MyApp' не нужно' NanoMax'; если 'MyApp' нуждается в' NanoMax', 'NanoMax' не должен быть' MyApp'. В противном случае это круговое движение. – ShadowRanger

+0

@ShadoRanger: Да, все они используют супер. Более того, я согласен с тем, что вы только что сказали, это имеет смысл. В моем случае происходит следующее: я просто хочу разрешить NanoMax читать переменную моего объекта MyApp, на самом деле не обязательно быть дочерним элементом MyApp. Есть ли другой способ сделать это? – Eduardo

0
class MyApp(QtGui.QMainWindow, Ui_MainWindow): 
    self.PDvalue = 0 #initial PD value 
    self.PDState = 0 #control the PD state (on-off) 

В приведенном выше коде устанавливается переменная вне функции. Для этого в классе не ставьте ключевое слово self перед ним. Таким образом, вы можете просто в определении класса

class MyApp(QtGui.QMainWindow, Ui_MainWindow): 
    PDvalue = 0 #initial PD value 
    PDState = 0 #control the PD state (on-off) 

и в супер линии

power = super(NanoMax, self).PDvalue 

Например:

>>> class Hi: 
    H = 5 
    def __init__(self): 
    self.g = 6 

>>> class Bye(Hi): 
    def H(self): 
    print(super(Bye, self).H) 

>>> e = Bye() 
>>> e.H() 
5 
>>> 
+0

Он работает так, но он всегда читает 0 для питания. Я думаю, это потому, что он читает переменную родительского класса, а не переменную экземпляра. Или я сделал что-то не так? Я изменил все self.PDvalue в основном коде на MyApp.PDvalue, а также – Eduardo