global vermeiden

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.
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

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!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Indem du der Funktion size als zusätzlichen Parameter mit gibst!
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()
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Danke!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Wenn man ``global`` vermeiden will, dann vermeidet man auch modulglobale Variablen. So hat BlackJack ``size`` gar nicht im Modul stehen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
meneliel
User
Beiträge: 256
Registriert: Montag 25. Juni 2007, 08:35
Kontaktdaten:

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.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Noch eine Möglichkeit: Eine Klasse mit Klassenweite Variablen zu nutzten.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

@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...
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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
Zuletzt geändert von snafu am Mittwoch 6. August 2008, 12:51, insgesamt 1-mal geändert.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

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 ;)
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

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
RedGargoyle
User
Beiträge: 3
Registriert: Mittwoch 13. Januar 2016, 13:12

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.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

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

@RedGargoyle: Und jetzt versuch das mal aus einer anderen Funktion heraus aufzurufen.
RedGargoyle
User
Beiträge: 3
Registriert: Mittwoch 13. Januar 2016, 13:12

@ 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?
BlackJack

@RedGargoyle: Variante 1 ist offensichtlich schlechter als Variante 2, aus den ganzen Gründen aus denen ``global`` Böse™ ist.
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

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?
empty Sig
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()
harryberlin
User
Beiträge: 227
Registriert: Donnerstag 17. Dezember 2015, 12:17

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.
empty Sig
Antworten