top-down-design: Funktionen allgemein definieren

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.
BlackJack

@peter99: Warum willst Du vermeiden Module aus der Standardbibliothek zu importieren? Das macht keinen Sinn. Dafür sind diese Module da.

In den beiden gezeigten Funktionen wird das globale `k` nicht verwendet, und wie die Fehlermeldung sehr deutlich sagt wird in `compute_energy()` ein `i` verwendet, welches nicht definiert ist. Ich würde mal behaupten das müsste auch jeweils `k` heissen und das `k` auf Modulebene kann weg. `Vebit0` von Modulebene wird auch gar nicht verwendet. Verwirrt aber in der Schreibweise, weil es ein Argument mit diesem Namen gibt.

Wenn das mit dem `i` gelöst ist, wird `phi` der nächste `NameError`. Die aufrufende Funktion hat ein Argument mit dem Namen — vielleicht sollte der Wert übergeben werden? Das gleiche gilt für `Qout`. Wobei das übergeben einer leeren Liste, die dann gefüllt wird, nicht schön ist. Wenn eine Funktion etwas zurückgeben soll, dann sollte man das mit ``return`` machen und nicht in dem man eine übergebene Liste mit Werten füllt. Wobei mir diese Liste sehr unsinnig erscheint. Wozu soll die gut sein? Je nach `condition` wird sie mit immer dem gleichen Wert `k` gefüllt und zwar `number` mal, oder sie bleibt leer. Und die `decision()`-Funktion macht dann auch überhaupt gar nichts mit dieser Liste. Das einige wofür die Liste ”benutzt” wird, ist ihre Länge als Schleifenzähler zu missbrauchen. *Das* kann man einfacher und direkter haben.

Bei `Lambda` ist ein Kommentar, den man sich sparen könnte wenn man den Namen komplett in Grossbuchstaben benennt, wie das bei Konstanten per Konvention üblich ist. Siehe Style Guide for Python Code.

Du lässt `s` von 1 bis `number` laufen und ziehst aber jedesmal wenn `s` benutzt wird 1 ab. Warum lässt Du es dann nicht gleich von 0 bis `number - 1` laufen, also einfach ``xrange(number)``. Wobei die Indirektion über einen Index wie gesagt unnötig ist und Module aus der Standardbibliothek dazu da sind sie zu benutzen. `math` und `string` importierst Du ja auch. Die könnte man schliesslich mit der gleichen Argumentation ablehnen.

Wenn man alles bis hierher berücksichtigt, dann bleibt bei der `compute_energy()` eine Schleife übrig die im Falle das `condition` unwahr ist, viel berechnet, aber immer nur `refresh()` aufruft. Ohne das die Berechnungen selber irgendeinen Effekt hätten. Ich kann mich des Eindrucks nicht erwehren, dass man dann `compute_energy()` gar nicht erst *aufrufen* bräuchte, die Bedingung für `condition` also nicht nur nicht *in* der Schleife, sondern eigentlich noch nicht einmal in der Funktion stehen sollte.

Der rückwärtsgerichtete Schrägstrich zur Fortsetzung einer logischen Zeile ist nicht nötig solange noch geöffnete Klammern nicht geschlossen sind. Dann weiss der Compiler das der Ausdruck noch nicht vollständig sein kann.

Bei der `decision()`-Funktion werden ganze sieben Argumente überhaupt nicht verwendet.

Auch in dieser Funktion sind die Prüfungen teilweise an der falschen Stelle falls `refresh()` nichts an den Bedingungen ändert und nur aufgerufen werden muss um zum Beispiel die GUI am laufen zu halten. Der Wert von `checks` ändert sich innerhalb der Schleife nicht. Der Wert des `all()`-Ausdrucks von `condition` den man aus `compute_energy()` vor den Aufruf von `compute_energy()` ziehen kann, wird in der Schleife nicht verändert, kann also auch davor gezogen werden.

Ich lande dann bei ungefähr so etwas hier:

Code: Alles auswählen

from itertools import count, islice, izip
from math import cos, pi as PI, sin, sqrt

BETA_S = 0.041
G_EFF = 0.067539767
LAMBDA = 3.724129913
VEBIT = None  # TODO

# ...


# TODO If `beta_s` is not really variable, remove the argument and replace it
#   by a constant.
def compute_energy(number, k, cavlist, phi, v_ebit0, factors, beta_s):
    table = display.getWidget('Table').getTable()
    e_0 = 600
    for i, cav, factor in islice(izip(count(), cavlist, factors), number):
        # 10**(-16), because keV
        beta = sqrt(2 * e_0 * 1.602177e-16 / 1.6726e27) / 299792458
        tmp = PI * G_EFF / (beta * LAMBDA)
        T = sin(tmp) / tmp * sin(PI * beta_s / (2 * beta))
        e_0 = (27.98 * cav * k * cos(phi) * T) / (factor * e_0)
        set_cells(table, i, k, v_ebit0, number, e_0)


def decision(
    phi, q_in, A, v_ebitmax, checks, number, cavlist, factors, cavmax_css
):
    if (
        # Ist possibility: fixed number, compute Energy
        checks == [1, 0, 0, 1]
        and all(t < u for t, u in izip(cavlist, cavmax_css))
    ):
        for i in xrange(1 , q_in + 1):
            v_ebit = 12 * A / i   
            if v_ebit < v_ebitmax:
                compute_energy(number, i, cavlist, phi, v_ebit, factors, BETA_S)
Hier könnte man noch überlegen ob man den `all()`-Teilausdruck in `decision()` nicht in den Aufrufer verschieben kann, dann würde man ein Argument sparen, denn `cavmax_css` wird nur für diesen Test verwendet.

Und man könnte (und sollte IMHO) Berechnung und Darstellung besser trennen. Etwas was `compute_energy()` heisst sollte nur das tun: Die Energiewerte berechnen. Und sie zurückgeben und nicht selbst anzeigen. Denn diese Funktion hat ja auch ein Argument was nur übergeben wird weil es in `set_cells()` verwendet wird und nicht weil man es tatsächlich zur Berechnung der Energiewerte brauchen würde.
peter99
User
Beiträge: 84
Registriert: Samstag 3. August 2013, 21:32

Vielen Dank für den vielen, äußerst produktiven Input. refresh wird deshalb gebraucht, dass wenn der user das Programm zB mehrmals hintereinander läuft, nicht noch etwas altes vom vorigen Durchlauf in dem table stehen bleibt, obwohl das Programm eigentlich keinen output produziert, deswegen muss immer wenn die condition nicht erfüllt ist refresht werden.. und an der richtigen stelle- muss also erst schauen an welcher Stelle das in deinem code ist.
Sorry, dass ich erst jetzt antworte, hab die 2. Seite nicht gesehen.
peter99
User
Beiträge: 84
Registriert: Samstag 3. August 2013, 21:32

Außerdem(verwende jetzt noch den alten code, aber werde deine Verbesserungsvorschläge definitiv berücksichtigen;) muss ich leider k und dieses dumme Zeug setten(zum. ist es der einzige Umweg, den ich gerade sehe), weil ich sonst den error in meiner main-Funktion erhalte, dass ich k nicht als globalen Parameter eingeführt habe.. was ich ja verstehe, aber soll ja nur ein Standhalter sein bis ich die Funktion abhängig von einem globalen Parameter aufrufe.

Code: Alles auswählen

k = 2
s = 2
Vebit0 = 1
# find a better solution
Qout = []
numberout = []
Energyout = []
fieldout = []

def main():
    Qcont_unstable, A1_unstable, Around_unstable, nameiso_unstable, qdivbya_unstable, abu2_unstable, information_unstable, \
    Qcont_stable, A1_stable, Around_stable, nameiso_stable, qdivbya_stable, abu2_stable, information_stable = readcontaminationfile()
    cavmaxCSS, cavmaxreal, factor = readcavmaxfile()
    phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, check2, check1, check3, check4, checks,\
           number, numbers, diffqa0, cavlist, combo = getInputs(A1, Around, nameiso, Qcont, factor)
    alarm(cavlist, cavmaxCSS, number)
    info_for_click = decision(phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, checks, \
             number, numbers, cavlist, factor, cavmaxCSS, cavmaxreal)
    clickrow(info_for_click, Qcont, A1, nameiso, qdivbya, abu2, information, A, diffqa0, check3, check4, factor, \
             phi, minimumf, maximumf, cavmaxreal, combo)

def compute_energy(number, A, phi,  k, cavlist, Vebit0, Vebitmax, cavmaxCSS, factor, betaS):
    #all(t < u for t, u in zip(cavlist, cavmaxCSS)) and
    condition_energy = (
    Vebit0 < Vebitmax
    )
    E0 = 600
    for s in range(1,number + 1):
        # 10**(-16), because keV
        beta = sqrt(2 * E0 * 1.602177 * 10**(-16) / 1.6726 * 10**27) /c0
        tmp = pi * geff / (beta * Lambda)
        T = sin(tmp) / tmp * sin(pi * betaS / (2 * beta))
        E0 = E0 + (k*35*cavlist[s-1]/factor[s-1])/A*T*cos(phi)
    if condition_energy:
        Qout.append(k)
        set_cells(table, len(Qout) - 1, k, Vebit0, number, E0)
    else:
        refresh()
 
def compute_field(s, A, phi,  k, Vebit0, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E):
    E_average = (600 + E)/2
    v_averge = sqrt(2*E_average*1.602177*10**(-16)/1.6726*10**27)
    beta_average = v_averge/c0
    tmp = pi * geff / (beta_average * Lambda)
    T_average = sin(tmp)/tmp*sin(pi*betaS/(2*beta_average))
    fieldreal = diffE*A/(27.98*k*float(s)*T_average*cos(phi))
    # cannot be defined earlier because otherwise listfields not already defined
    condition_field = (
    fieldreal > minimumf and fieldreal < maximumf and all(fieldreal < u for u in  cavmaxreal) and Vebit0 < Vebitmax
    )
    if condition_field:
        Qout.append(k)
        fieldout.append(fieldreal)
        numberout.append(s)
        Energyout.append(E)
        set_cells(table, len(Qout) - 1, k, Vebit0, s, E)
    # no provide information for click
  #  info_for_click = zip(Qout, fieldout, numberout, Energyout)
   # else:
      #  refresh()
    #return info_for_click

def decision(phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, checks, \
             number, numbers, cavlist, factor, cavmaxCSS, cavmaxreal):
    Q = range(1 , Qin + 1, 1)
    for i in Q:
        Vebit = 12*A/i   
# Ist possibility: fixed number, compute Energy
        if checks == [1, 0, 0, 1]:
            compute_energy(number, A, phi,  i, cavlist, Vebit, Vebitmax, cavmaxCSS, factor, betaS)
            # does not provide any information - not needed
        elif checks == [1, 0, 1, 0]:
            compute_field(number, A, phi, i, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E)
            info_for_click = zip(Qout, fieldout, numberout, Energyout)
        elif checks == [0, 1, 1, 0]:
        # for some reason: after checks no for..
            normann = 3
            for j in numbers:
                compute_field(j, A, phi, i, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E)
                info_for_click = zip(Qout, fieldout, numberout, Energyout)
   	else:
            refresh()
    return info_for_click
BlackJack

@peter99: Wenn sich in der `main()`-Funktion über nicht definierte Namen beschwert wird, sollte man die *dort* definieren und nicht für das ganze Modul. Es ist sehr verwirrend wenn in Funktionen Namen verwendet werden die auch auf Modulebene schon definiert sind, weil man dann immer erst schauen muss ob ein Name lokal oder Modulglobal ist.
peter99
User
Beiträge: 84
Registriert: Samstag 3. August 2013, 21:32

meinst du so??

Code: Alles auswählen

from org.csstudio.opibuilder.scriptUtil import PVUtil
from org.csstudio.opibuilder.scriptUtil import FileUtil
from org.csstudio.swt.widgets.natives.SpreadSheetTable  import ITableSelectionChangedListener
from java.util import Arrays
from org.csstudio.opibuilder.scriptUtil import ColorFontUtil
RED = ColorFontUtil.getColorFromRGB(255,0,0)
# import math for later calculations in imported data
import os

from math import*
from string import*
table = display.getWidget("Table").getTable()
table1 = display.getWidget("Table1").getTable()
c0 = 299792458.0
betaS = 0.041
geff = 0.067539767
#big letter because lambda seems to be predefined
Lambda = 3.724129913
# should help not to use not defined functions until this moment
# find a better solution
Qout = []
numberout = []
Energyout = []
fieldout = []

def main():
    Qcont, A1, Around, nameiso, abu, qdivbya, abu2, information = readcontaminationfile()
    cavmaxCSS, cavmaxreal, factor = readcavmaxfile()
    phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, check2, check1, check3, check4, checks,\
           number, numbers, diffqa0, cavlist, combo = getInputs(A1, Around, nameiso, Qcont, factor)
    alarm(cavlist, cavmaxCSS, number)
    def compute_energy(number, A, phi,  k, cavlist, Vebit0, Vebitmax, cavmaxCSS, factor, betaS):
    #
        condition_energy = (
        Vebit0 < Vebitmax and all(t < u for t, u in zip(cavlist, cavmaxCSS)) 
        )
        E0 = 600
        for s in range(1,number + 1):
            # 10**(-16), because keV
            beta = sqrt(2 * E0 * 1.602177 * 10**(-16) / 1.6726 * 10**27) /c0
            tmp = pi * geff / (beta * Lambda)
            T = sin(tmp) / tmp * sin(pi * betaS / (2 * beta))
            E0 = E0 + (k*35*cavlist[s-1]/factor[s-1])/A*T*cos(phi)
        if condition_energy:
            Qout.append(k)
            set_cells(table, len(Qout) - 1, k, Vebit0, number, E0)
        else:
            refresh()
 
    def compute_field(s, A, phi,  k, Vebit0, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E):
        E_average = (600 + E)/2
        v_averge = sqrt(2*E_average*1.602177*10**(-16)/1.6726*10**27)
        beta_average = v_averge/c0
        tmp = pi * geff / (beta_average * Lambda)
        T_average = sin(tmp)/tmp*sin(pi*betaS/(2*beta_average))
        fieldreal = diffE*A/(27.98*k*float(s)*T_average*cos(phi))
        # cannot be defined earlier because otherwise listfields not already defined
        condition_field = (
        fieldreal > minimumf and fieldreal < maximumf and all(fieldreal < u for u in  cavmaxreal) and Vebit0 < Vebitmax
        )
        if condition_field:
            Qout.append(k)
            fieldout.append(fieldreal)
            numberout.append(s)
            Energyout.append(E)
            set_cells(table, len(Qout) - 1, k, Vebit0, s, E)
    # no provide information for click
  #  info_for_click = zip(Qout, fieldout, numberout, Energyout)
   # else:
      #  refresh()
    #return info_for_click
    info_for_click = decision(phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, checks, \
             number, numbers, cavlist, factor, cavmaxCSS, cavmaxreal)
    clickrow(info_for_click, Qcont, A1, nameiso, qdivbya, abu2, information, A, diffqa0, check3, check4, factor, \
             phi, minimumf, maximumf, cavmaxreal, combo)
mein erstes Problem dabei waere wie ich die Funktion compute_field wieder aufrufe...
... wenn ich es einfach spaeter aufrufe, bekomme ich einen error, da compute_field/energy nicht mehr global definiert ist.

Code: Alles auswählen

def decision(phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, checks, \
             number, numbers, cavlist, factor, cavmaxCSS, cavmaxreal):
    Q = range(1 , Qin + 1, 1)
    for i in Q:
        Vebit = 12*A/i   
# Ist possibility: fixed number, compute Energy
        if checks == [1, 0, 0, 1]:
            compute_energy(number, A, phi,  i, cavlist, Vebit, Vebitmax, cavmaxCSS, factor, betaS)
            # does not provide any information - not needed
        elif checks == [1, 0, 1, 0]:
            compute_field(number, A, phi, i, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E)
            info_for_click = zip(Qout, fieldout, numberout, Energyout)
        elif checks == [0, 1, 1, 0]:
        # for some reason: after checks no for..
            normann = 3
            for j in numbers:
                compute_field(j, A, phi, i, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E)
                info_for_click = zip(Qout, fieldout, numberout, Energyout)
   	else:
            refresh()
    return info_for_click
vielen dank im vorraus
BlackJack

@BlackJack: Nein, so meinte ich das nicht. Die Funktionen haben ja wohl auch nicht zu einem `NameError` geführt.
peter99
User
Beiträge: 84
Registriert: Samstag 3. August 2013, 21:32

Code: Alles auswählen

def compute_energy(number, A, phi,  k, cavlist, Vebit, Vebitmax, cavmaxCSS, factor, betaS):
    #
    condition_energy = (
    Vebit0 < Vebitmax and all(t < u for t, u in zip(cavlist, cavmaxCSS)) 
    )
    E0 = 600
    for s in range(1,number + 1):
        # 10**(-16), because keV
        beta = sqrt(2 * E0 * 1.602177 * 10**(-16) / 1.6726 * 10**27) /c0
        tmp = pi * geff / (beta * Lambda)
        T = sin(tmp) / tmp * sin(pi * betaS / (2 * beta))
        E0 = E0 + (k*35*cavlist[s-1]/factor[s-1])/A*T*cos(phi)
    if condition_energy:
        Qout.append(k)
        set_cells(table, len(Qout) - 1, k, Vebit, number, E0)
    else:
        refresh()
 
def compute_field(s, A, phi,  k, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E):
    E_average = (600 + E)/2
    v_averge = sqrt(2*E_average*1.602177*10**(-16)/1.6726*10**27)
    beta_average = v_averge/c0
    tmp = pi * geff / (beta_average * Lambda)
    T_average = sin(tmp)/tmp*sin(pi*betaS/(2*beta_average))
    fieldreal = diffE*A/(27.98*k*float(s)*T_average*cos(phi))
    # cannot be defined earlier because otherwise listfields not already defined
    condition_field = (
    fieldreal > minimumf and fieldreal < maximumf and all(fieldreal < u for u in  cavmaxreal) and Vebit < Vebitmax
    )
    if condition_field:
        Qout.append(k)
        fieldout.append(fieldreal)
        numberout.append(s)
        Energyout.append(E)
        set_cells(table, len(Qout) - 1, k, Vebit, s, E)
    # no provide information for click
  #  info_for_click = zip(Qout, fieldout, numberout, Energyout)
   # else:
      #  refresh()
    #return info_for_click

def main():
    Qcont, A1, Around, nameiso, abu, qdivbya, abu2, information = readcontaminationfile()
    cavmaxCSS, cavmaxreal, factor = readcavmaxfile()
    phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, check2, check1, check3, check4, checks,\
           number, numbers, diffqa0, cavlist, combo = getInputs(A1, Around, nameiso, Qcont, factor)
    alarm(cavlist, cavmaxCSS, number)
    info_for_click = decision(phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, checks, \
             number, numbers, cavlist, factor, cavmaxCSS, cavmaxreal)
    clickrow(info_for_click, Qcont, A1, nameiso, qdivbya, abu2, information, A, diffqa0, check3, check4, factor, \
             phi, minimumf, maximumf, cavmaxreal, combo)

def decision(phi, Qin, A, E, diffE, minimumf, maximumf, Vebitmax, checks, \
             number, numbers, cavlist, factor, cavmaxCSS, cavmaxreal):
    Q = range(1 , Qin + 1, 1)
    for i in Q:
        Vebit = 12*A/i   
# Ist possibility: fixed number, compute Energy
        if checks == [1, 0, 0, 1]:
            compute_energy(number, A, phi,  i, cavlist, Vebit, Vebitmax, cavmaxCSS, factor, betaS)
            # does not provide any information - not needed
        elif checks == [1, 0, 1, 0]:
            compute_field(number, A, phi,  i, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E)
            info_for_click = zip(Qout, fieldout, numberout, Energyout)
        elif checks == [0, 1, 1, 0]:
        # for some reason: after checks no for..
            normann = 3
            for j in numbers:
                compute_field(j, A, phi,  i, Vebit, Vebitmax, cavmaxreal, factor, betaS, minimumf, maximumf, diffE, E)
                info_for_click = zip(Qout, fieldout, numberout, Energyout)
   	else:
            refresh()
    return info_for_click
Das scheint zu funktionieren, wobei mir nicht klar ist wie die Funktionen Vebit in der decision-Struktur einlesen... es scheint zu funktionieren, aber es ist mir nicht wirklich klar warum.
Antworten