Seite 1 von 2
global vermeiden
Verfasst: Freitag 1. August 2008, 17:15
von nemomuk
Hallo,
ich versuche gerade keine globalen Vriablen in meinem Programm zu verwenden und wollte fragen, wie ich das am geschicktesten und besten mache.
Bsp:
Code: Alles auswählen
size = 0
def test():
global size
size += 123
if __name__ == "__main__":
test()
print size
Nun wollte ich eine eigene Funktion schreiben, die das += für mich erledigt, leider stehe ich vor dem problem, wie ich auf das "size" dann zugreife...
Code: Alles auswählen
size = 0
def test():
size_add(123)
def size_add(size1)
size += size1
if __name__ == "__main__":
test()
print size
Danke!
Verfasst: Freitag 1. August 2008, 17:33
von Hyperion
Indem du der Funktion size als zusätzlichen Parameter mit gibst!
Verfasst: Freitag 1. August 2008, 20:21
von BlackJack
Ohne ``global``:
Code: Alles auswählen
def test(size):
return size_add(size, 123)
def size_add(size, inkrement):
return size + inkrement
def main():
size = test(0)
print size
if __name__ == '__main__':
main()
Verfasst: Freitag 1. August 2008, 20:48
von nemomuk
Danke!
Verfasst: Samstag 2. August 2008, 13:12
von Leonidas
Wenn man ``global`` vermeiden will, dann vermeidet man auch modulglobale Variablen. So hat BlackJack ``size`` gar nicht im Modul stehen.
Verfasst: Montag 4. August 2008, 14:04
von meneliel
Ich hab das inzwischen auch schon "probiert", ganz ohne garstige gobale Variablen auszukommen, hab dann aber festgestellt, dass sie mitunter ganz nützlich sein können.
Wenn ich eine Variable am Ende wirklich in fast jeder Funktion brauche, erscheint es mir deutlich praktischer sie einfach globalisieren, statt sie mehreren Funktion zu übergeben.
Verfasst: Montag 4. August 2008, 14:37
von EyDu
Das sagst du genau so lange, bis du mal Ewigkeiten nach einem Fehler suchst, der auf komischen Seiteneffekten basiert. Außerdem macht es das unmöglich deine Funktionen noch vernünftig zu testen.
Verfasst: Dienstag 5. August 2008, 07:38
von jens
Noch eine Möglichkeit: Eine Klasse mit Klassenweite Variablen zu nutzten.
Verfasst: Dienstag 5. August 2008, 10:39
von nemomuk
@jens: So mache ich es jetzt auch, das ist zwar in gewisser Weise ein Klassenmissbrauch, macht das Programm aber sehr viel übersichtlicher und erspart einem sehr viel Arbeit...
Verfasst: Dienstag 5. August 2008, 12:01
von snafu
Ich würd's so machen:
Code: Alles auswählen
In [1]: class Size(object):
...: def __init__(self):
...: self.size = 0
...: def add(self, number):
...: return self.size + number
...:
In [2]: size = Size()
In [3]: size.add(23)
Out[3]: 23
In [4]: size.add(42)
Out[4]: 65
Verfasst: Dienstag 5. August 2008, 14:55
von veers
SchneiderWeisse hat geschrieben:@jens: So mache ich es jetzt auch, das ist zwar in gewisser Weise ein Klassenmissbrauch, macht das Programm aber sehr viel übersichtlicher und erspart einem sehr viel Arbeit...
Wieso Missbrauch? Das ist eine der Ideen von OOP - die Logik zusammen mit den Daten zu kapseln. Solange sich die Grösse einer Klasse in grenzen hält funktioniert das auch ganz gut
PS: Irgend wie erinnert mich das ganze an die Informatik Olympiade - die fanden da auch alle "ach einfach alles global machen ist doch viel einfacher". Kommt wohl davon wenn man 90% Wegwerfcode schreibt
Verfasst: Dienstag 5. August 2008, 18:04
von yipyip
Gerade Python bietet doch sooo viele Moeglichkeiten,
ein 'global' zu vermeiden (hab's selbst noch nie gebraucht):
Code: Alles auswählen
#!/usr/bin/env python
# C style
size_struct = {'size': 10}
def size_add(struct, size):
struct['size'] += size
# Lisp style
def make_sizer(size):
return [size]
def get_size(sizer):
return sizer[0]
def set_size(sizer, size):
sizer[0] = size
return sizer
def add_size(sizer, size):
return make_sizer(get_size(sizer) + size)
def destructive_add_size(sizer, size):
return set_size(sizer, get_size(sizer) + size)
# Python OO style
class Sizer(object):
def __init__(self, size):
self.size = size
def __add__(self, other):
return self.size + other
def __iadd__(self, other):
self.size += other
return self
def __repr__(self):
return "('Sizer', %d)" % self.size
def __str__(self):
return '%d' % self.size
####
def main_sizer():
print 'C style:'
size_add(size_struct, 123)
print size_struct['size']
print 'Lisp style:'
s = make_sizer(10)
print get_size(add_size(s, 123))
print get_size(s)
destructive_add_size(s, 123)
print get_size(s)
print 'Python OO style:'
s = Sizer(10)
print s + 123
print s
s += 123
print s
print repr(s)
####
if __name__ == '__main__':
main_sizer()
yipyip
Re: global vermeiden
Verfasst: Mittwoch 13. Januar 2016, 17:50
von RedGargoyle
Jetzt mal abgesehen davon, dass bei der Verwendung von global Seiteneffekte auftreten können, habe ich folgende Frage:
Was ist ganz praktisch gesehen der Unterschied zwischen den folgenden Beispielen?
Variante 1:
Code: Alles auswählen
a=0
b=0
c=0
def f():
global a,b,c
# Teil der Funktion, der auf a, b, c zugreift oder a, b, c verändert
f()
Variante 2:
Code: Alles auswählen
a=0
b=0
c=0
def ff(a,b,c):
# Teil der Funktion, der auf a, b, c zugreift oder a, b, c verändert
return a,b,c
a,b,c = ff(a,b,c)
Der Teil der Funktion, der auf a, b, c zugreift oder a, b, c verändert, könnte zum Beispiel
lauten.
Ich konnte in der Benutzung beider Varianten keinen Unterschied feststellen.
Re: global vermeiden
Verfasst: Mittwoch 13. Januar 2016, 18:30
von DasIch
Der Unterschied ist das Variante 1 Komposition verhindert. Komposition ist grundlegend in der Informatik sowohl in der Theorie als auch der Praxis. Von den Subatomaren Teilchen aus denen das Silizium besteht mit dem dein Computer gebaut wurde aufwärts bis in die Software besteht alles aus Komponenten die mit anderen Komponenten zusammengefügt werden um neue Komponenten zu erstellen die eine auf einer höheren Abstraktionsebene existieren.
Wenn du eine solche Funktion mit anderen Funktionen verbindest sickert durch das global ihr Zustand hinaus und kleckert dir die ganze Komposition voll und ruiniert alles. Du bleibst stecken und kommst keine Abstraktionsebene mehr höher. Damit wird die Funktion nahezu unbenutzbar weil du sie zwangsläufig mit anderen kombinieren musst um sie zu testen oder wiederzuverwenden. Nutzt du Sie trotzdem kannst du die Funktion nicht mehr für sich selbst betrachten, viel mehr musst du die Funktion und alles worauf sie wann und wo hingekleckert hat auch noch verstehen.
Außerdem bekommt man einen Würgereiz wenn man sowas sieht und das Problem wirklich verstanden hat weil man sich schon vor der Vorstellung des Zustands der sich überall hin verteilt anfängt zu ekeln.
Re: global vermeiden
Verfasst: Mittwoch 13. Januar 2016, 18:58
von BlackJack
@RedGargoyle: Und jetzt versuch das mal aus einer anderen Funktion heraus aufzurufen.
Re: global vermeiden
Verfasst: Mittwoch 13. Januar 2016, 19:00
von RedGargoyle
@ DasIch
Puhh, ich glaube über die Antwort muss ich erst einmal meditieren
Aber klar, kleckern mag ich echt nicht.
Trotzdem danke!
@ BlackJack
So langsam sehe ich ein, dass die Variante mit global bei Verschachtelungen zu sehr unübersichtlichem Code (und somit auch leicht zu Fehlern) führt.
Aber ich will trotzdem nochmal nachfragen: Gibt es, in der Form, in der ich die beiden Varianten angegeben habe, einen offensichtlichen Unterschied?
Re: global vermeiden
Verfasst: Mittwoch 13. Januar 2016, 19:50
von BlackJack
@RedGargoyle: Variante 1 ist offensichtlich schlechter als Variante 2, aus den ganzen Gründen aus denen ``global`` Böse™ ist.
Re: global vermeiden
Verfasst: Dienstag 9. Februar 2016, 18:02
von harryberlin
Um das Thema global (4.) aus dem Thread
viewtopic.php?f=1&t=37842&start=30 noch zu beenden.
Habe nun auch noch den weiteren Ausdruck für Eigenschaften einer Klasse gefunden, nämlich Attribut.
Ich würde es nun mit einer sogenannten variablen Klasse lösen. Z.B.
Code: Alles auswählen
class VarHandler:
def __init__(self):
self.state1 = False
self.state2 = False
self.state3 = False
self.var1 = None
variable = VarHandler()
variable.state1 = True
print variable.state1
Gibt es noch bessere Lösungen, oder findet ihr das gut?
Komisch, warum geht die Codebox nicht?
Re: global vermeiden
Verfasst: Dienstag 9. Februar 2016, 18:12
von BlackJack
@harryberlin: Codebox ist gerade kaputt.
Das was Du da jetzt geschrieben hast ist ja immer noch eine globale Variable, nämlich `variable`. Und ob das nun Sinn macht die Variablen als Attribute zu einem Objekt zusammen zu fassen hängt davon ab was die eigentlich bedeuten und ob die sinnvoll zusammengehören. Und wenn die zusammengehören, dann gibt es in der Regel auch Methoden die ebenfalls zu den Daten gehören.
Das was da steht kann man ohne Klasse und ohne globale Variablen so schreiben:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
def main():
state1 = False
state2 = False
state3 = False
var1 = None
state1 = True
print(state1)
if __name__ == '__main__':
main()
Re: global vermeiden
Verfasst: Dienstag 9. Februar 2016, 18:27
von harryberlin
ja, ich brauche es auch global.
so besser?
Code: Alles auswählen
class VarHandler:
def __init__(self):
self.state1 = False
self.state2 = False
self.state3 = False
self.var1 = None
variable = VarHandler()
def main():
variable.state1 = True
print variable.state1
if __name__ == 'main':
main()
kann man in die klasse auch functionen für set und get einbauen, wo man direkt die variable als argument übergibt?
mir würde jetzt die möglichkeit einfallen, das argument variable als string zu übergeben und mit if zu parsen, aber geht das auch einfacher.
in etwa so:
Code: Alles auswählen
def set(self,variable,value):
self.variable = value
def get(self,varaible):
return self.variable
wobei, wäre eigentlich überflüssig. weil man die vars einfach mit = setzen oder holen kann.