[Python] Hoe refereer je binnen een object naar een object?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Sando
  • Registratie: Januari 2007
  • Niet online

Sando

Sandoichi

Topicstarter
Ik spreek een aardig woordje Python. Ik heb bijvoorbeeld de Arcade Browser voor XBMC geschreven. Maar er is één probleem waar ik steeds weer tegenaan loop. Ik weet niet waarom ik er steeds weer van uitga dat zoiets moet kunnen, want het kan dus niet.

Waarom kan dit niet en hoe moet het wel?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Greeter:
    def __init__(self):
        t = Thinker()
        t.think()

    def greet(self):
        print "Hoi"

class Thinker:
    def __init__(self):
        pass

    def think(self):
        global g
        g.greet() # NameError: global name 'g' is not defined

g = Greeter()

🇪🇺 Buy from EU (GoT)


Acties:
  • 0 Henk 'm!

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 10-08 02:59

Gerco

Professional Newbie

Ik weet niet precies wat je wilt bereiken, maar het risico nemend dat ik een open deur intrap wil ik toch even zeggen dat je dit wellicht zo wilt doen:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Greeter:
    def __init__(self):
        t = Thinker(self)
        t.think()

    def greet(self):
        print "Hoi"

class Thinker:
    def __init__(self, greeter):
        self.greeter = greeter

    def think(self):
        self.greeter.greet()

g = Greeter()


Mijn Python is wat roestig dus let niet al te erg op de syntax. Je geeft de Thinker dus een reference naar een Greeter en die gebruik je in je think() method. Je kan ook de Greeter een parameter aan think() maken, maar dat is een keuze dit je per geval moet maken.

[ Voor 27% gewijzigd door Gerco op 03-06-2010 15:40 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Acties:
  • 0 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Met ^^

Als dat is wat je probeert te vragen iig.

Een global gebruiken is sowieso niet de beste oplossing, pak dan liever nog een borg pattern.

Blog [Stackoverflow] [LinkedIn]


Acties:
  • 0 Henk 'm!

  • Sando
  • Registratie: Januari 2007
  • Niet online

Sando

Sandoichi

Topicstarter
Bedankt voor het meedenken!

Ik wilde toevallig net gaan editten dat ik die manier inderdaad wel had bedacht en dat ik wat meer moest toelichten, maar je was er snel bij. :)

Wat ik wil, zo simpel mogelijk uitgeschreven in dit voorbeeld, is een object aanroepen binnen een ander object, zonder dit object bij het instantiëren zelf door te geven.

Als ik bijvoorbeeld op een gegeven moment heb:
code:
1
2
3
4
g = Greeter()
s = Shouter()
p = Pooper()
# ...
en ik wil in Thinker() allemaal child-functies aanroepen, moet ik ze dan werkelijk allemaal door gaan geven bij het instantiëren van Thinker()? Waarom werkt global in dit geval niet?

-edit-

En Wolfboy is daar weer snel bij. Borg pattern ken ik niet, even googlen..

-edit-

Ah, ik heb liever Singleton pattern want anders moet ik weer gaan nadenken. |:( Maar dan nog staat mijn vraag.

[ Voor 18% gewijzigd door Sando op 03-06-2010 15:53 ]

🇪🇺 Buy from EU (GoT)


Acties:
  • 0 Henk 'm!

Verwijderd

Ben je misschien op zoek naar een equivalent van static classes?
http://code.activestate.c...-class-methods-in-python/ zoiets?
Of ik begrijp je verkeerd, ah ik las: zonder dit object te instantieren 8)7

[ Voor 63% gewijzigd door Verwijderd op 03-06-2010 15:57 ]


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23:10

Janoz

Moderator Devschuur®

!litemod

Sando schreef op donderdag 03 juni 2010 @ 15:48:
Als ik bijvoorbeeld op een gegeven moment heb:
code:
1
2
3
4
g = Greeter()
s = Shouter()
p = Pooper()
# ...
en ik wil in Thinker() allemaal child-functies aanroepen, moet ik ze dan werkelijk allemaal door gaan geven bij het instantiëren van Thinker()? Waarom werkt global in dit geval niet?
stel je hebt:

code:
1
2
3
p1 = Pooper()
p2 = Pooper()
p3 = Pooper()


Op welke van die poopers moeten thinker nu eigenlijk de methoden aanroepen?

Ik denk dat je probleem op dit moment vooral wordt veroorzaakt doordat je het verschil tussen een class en een object niet helemaal scherp op je netvlies hebt.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Sando
  • Registratie: Januari 2007
  • Niet online

Sando

Sandoichi

Topicstarter
Zit ik fout met mijn terminologie? :o
code:
1
2
3
4
class Bla: # Bla is een klasse
    __init__(self):
        pass
b = Bla() # b is een object
Janoz schreef op donderdag 03 juni 2010 @ 15:56:
Op welke van die poopers moeten thinker nu eigenlijk de methoden aanroepen?
Alle 3. Het voorbeeld wordt er niet anders om.. in essentie.

@ctor: Gewoon dynamisch in dit geval, toch bedankt :)

[ Voor 39% gewijzigd door Sando op 03-06-2010 16:06 ]

🇪🇺 Buy from EU (GoT)


Acties:
  • 0 Henk 'm!

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

De oplossing van Gerco is _de_ oplossing denk ik in dit geval. Of het moet op een of andere manier lazy uitgevoerd worden, maar je wil de greeter al hebben voor die bestaat (of in ieder geval... voor die klaar is met instantieren want je roept think() aan tijdens de instantiatie.

Blog [Stackoverflow] [LinkedIn]


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 06:08

RayNbow

Kirika <3

Gerco geeft hierboven al de juiste aanpak. Om te begrijpen waarom "global g" in je oorspronkelijke code niet werkt, moet je weten dat class-definities en functie-definities in feite soort van speciale statements zijn die worden uitgevoerd.

Voorbeeld:
C:\>python
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...   print 'Statements in class block worden direct uitgevoerd ' + \
...   'in een eigen namespace'
...
Statements in class block worden direct uitgevoerd in een eigen namespace
>>>


De think() methode van Thinker wordt dus tijdens de definitie van Thinker direct vertaald naar een function object. Omdat in think() "global g" staat, wordt tijdens de vertaling gekeken of er wel een variabel g bestaat.

Eens kijken of mensen de volgende error snappen... :p
(Wolfboy is uitgesloten van deelname :+)
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Greeter:
    def __init__(self):
        t = Thinker()
        t.think()
    
    def greet(self):
        print "Hoi"

g = None

class Thinker:
    def __init__(self):
        pass
    
    def think(self):
        global g
        g.greet()

g = Greeter()  # NoneType error

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23:10

Janoz

Moderator Devschuur®

!litemod

Sando schreef op donderdag 03 juni 2010 @ 16:05:
Alle 3. Het voorbeeld wordt er niet anders om.. in essentie.
Mwah, ik geef het vooral aan om je (hopelijk) te laten zien waar je denkfout zit.

Jij verwacht dat de aanroep op 1 methode binnen de class er voor gaat zorgen dat python alle op dat moment in het geheugen aanwezige instanties van die class op gaat zoeken om daar vervolgens die methode op uit te voeren?

Nogmaals. Ik vermoed dat het misgaat doordat je niet scherp hebt dat er een verschil is tussen een class en de instantie van die class.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Sando
  • Registratie: Januari 2007
  • Niet online

Sando

Sandoichi

Topicstarter
RayNbow schreef op donderdag 03 juni 2010 @ 16:10:
Voorbeeld:
C:\>python
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...   print 'Statements in class block worden direct uitgevoerd ' + \
...   'in een eigen namespace'
...
Statements in class block worden direct uitgevoerd in een eigen namespace
>>>
Wat slim aangegeven! Nu snap ik precies wat het probleem is. En nu begrijp ik dat ik er dus niet omheen kom om alles aan elkaar door te geven. :( Naja zo'n ramp is dat nou ook weer niet, de grootste ramp was dat ik niet begreep waarom.

Je NonType fout is me wel een raadsel. 8)7
Janoz schreef op donderdag 03 juni 2010 @ 16:12:
[...]
Jij verwacht dat de aanroep op 1 methode binnen de class er voor gaat zorgen dat python alle op dat moment in het geheugen aanwezige instanties van die class op gaat zoeken om daar vervolgens die methode op uit te voeren?

Nogmaals. Ik vermoed dat het misgaat doordat je niet scherp hebt dat er een verschil is tussen een class en de instantie van die class.
Nee, ik vermoed dat jij mijn schip harder ziet zinken dan het geval is. Ik verwijs duidelijk naar éen instantie van een klasse waarvan ik het (een) object niet expliciet door wil geven tijdens het instantiëren, en verderop noem ik illustratief drie objecten om aan te geven waarom niet. (als ik functies in hondert objecten wil aanroepen moet ik hondert objecten doorgeven tijdens het instantiëren, imo niet prettig vergeleken bij gewoon denken dat je global zou moeten kunnen gebruiken. Maar deze discussie is inmiddels obsolete, ik begrijp het probleem nu. :) )

btw, Python is een dynamische taal, volgens mij heb jij de laatste tijd teveel c++ geprogrammeerd of je geeft mensen gewoon het nadeel van de twijfel. ;)

-ed- typo

🇪🇺 Buy from EU (GoT)


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23:10

Janoz

Moderator Devschuur®

!litemod

Sando schreef op donderdag 03 juni 2010 @ 16:42:
Nee, ik vermoed dat jij mijn schip harder ziet zinken dan het geval is. Ik verwijs duidelijk naar éen instantie van een klasse waarvan ik het (een) object niet expliciet door wil geven tijdens het instantiëren, en verderop noem ik illustratief drie objecten om aan te geven waarom niet.
Je verwijst helemaal niet duidelijk naar 1 instantie. Je verwijst naar een variabele naam die in een compleet andere context ergens gezet wordt en op de vraag of het om die instantie of om alle instanties gaat geef je aan dat het eigenlijk alle instanties moet zijn.
btw, Python is een dynamische taal, volgens mij heb jij de laatste tijd teveel c++ geprogrammeerd of je geeft mensen gewoon het nadeel van de twijfel. ;)
Geen c++, voornamelijk Java. Maar dat een taal dynamisch is betekent nog niet dat je dan maar compleet het hele oo principe los moet gaan laten (encapsulation in dit specifieke geval)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 06:08

RayNbow

Kirika <3

Sando schreef op donderdag 03 juni 2010 @ 16:42:
Je NonType fout is me wel een raadsel. 8)7
Ik was slordig en is het eig. een AttributeError: 'NoneType' object has no attribute 'think'

Maar goed, het antwoord:
spoiler:
g = None voordat de constructor van Greeter is uitgevoerd, maar ook tijdens het uitvoeren van de constructor. De constructor roept t.think() aan terwijl g nog steeds None is. None heeft geen greet() methode. De variabele g verwijst pas naar een Greeter nadat de constructor klaar is. Helaas kan de constructor nooit netjes het einde bereiken, dus blijft g None.

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Sando
  • Registratie: Januari 2007
  • Niet online

Sando

Sandoichi

Topicstarter
@RayNbow: Haha, bedankt voor je educatieve raadseltje. :D Dat had ik eigenlijk moeten 'zien', maar mijn referentiekader keek even niet verder dan de =, stom :P
Misschien kan ik nog op het nippertje iets slims zeggen door mijn vermoeden uit te spreken dat je toch eerst de NameError krijgt omdat je ook hier eerst de Gerco methode moet toepassen.

@Janoz: Nee hoor ik zeg niet dat iets eigenlijk iets anders is. Ik schrijf heel duidelijk in code precies wat ik bedoel, en als jij denkt dat ik iets anders bedoel ga je daar eigenlijk al de mist in. Toegegeven ben ik geen gecertificeerd docent en schort het aan mijn uiteenzettingsvermogen, maar de rest snapt mij ook meteen zonder gekkigheid. :)

🇪🇺 Buy from EU (GoT)


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23:10

Janoz

Moderator Devschuur®

!litemod

Euhm, de rest geeft toch ook aan dat je het niet met een global, maar met een parameter moet doen?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Sando
  • Registratie: Januari 2007
  • Niet online

Sando

Sandoichi

Topicstarter
Ja precies, het idee achter global is duidelijk toch? Alleen wilde ik het met een object ipv string/integer/tuple/etc doen en dat kan dus niet. C'est tout.

🇪🇺 Buy from EU (GoT)

Pagina: 1