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()
:wink:
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

Code: Alles auswählen

    a+=1
    c=b+2
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.