[Python] Direct access to objects?

For questions about using Classic.

Post » Mon Sep 06, 2010 2:57 am

Let's say we have a layout with a Text object named "Text" and create a script in the script editor:

[code:3ijtereh]
def sayBoo():
Text.Text = "Boo!"

sayBoo()
[/code:3ijtereh]

We place this script under a "start of layout"-event and run the app. The text is set to "Boo!", just like it was intended.

If we now save this script as a module named "boo.py" in the appropriate folder and replace the script in the script editor with

[code:3ijtereh]
import boo

boo.sayBoo()
[/code:3ijtereh]

and run it, we get the error "global name 'Text' is not defined". Obviously, the interpreter is not aware anymore, that Text is a reference to the text object. Of course, by extending the function with a parameter textobject and in the code using this reference (textobject.Text = "Boo!") it works again.

But what to do, if there is no input possible? Is there another way to reference an object? The above was just an example, what I really would like to access from within my own module are a few attributes from System, like System.AppPath

The script editor resolves the references on the first code layer correctly, so there must be a way. Can someone point me to the right direction?
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Mon Sep 06, 2010 1:20 pm

That's because you can't have cross-module variables in Python.

The only way (read: very bad hack) to do it is using __builtin__ which is global in all modules:

boo.py[code:jgr2l8p6]
import __builtin__

def sayBoo():
__builtin__.Text.Text = "Boo!"
[/code:jgr2l8p6]editor:
[code:jgr2l8p6]
import __builtin__
import boo

__builtin__.Text = Text
boo.sayBoo()
[/code:jgr2l8p6]

See here for reference

But having to pass around objects like this is very ugly.

At this point I prefer using parameters:

boo.py
[code:jgr2l8p6]
def sayBoo(o):
o.Text = "Boo!"
[/code:jgr2l8p6]

editor:
[code:jgr2l8p6]
import boo

boo.sayBoo(Text)
[/code:jgr2l8p6]
B
1
G
2
Posts: 9
Reputation: 643

Post » Mon Sep 06, 2010 4:19 pm

Thank you very much for the answer :)

__builtin__ won't help in this case, because it refers to previously defined identifiers in modules. The objects of Construct are not defined in a module and can't be. Construct's objects are referenced through their names and they can change from session to session. Take the first example:

[code:1n5z6rp3]def sayBoo():
Text.Text = "Boo!"

sayBoo()[/code:1n5z6rp3]

If you now rename the text object in Construct to "tBoo", you get the same "global name" error. As soon as you update your script to "tBoo.Text = "Boo!" it works again.

The editor seems to map words to object references on the fly. I hoped I could have access to this mapping too (because 'System' is a built in object that will never change its name it would be easy to access without being too "hacky")
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Mon Sep 06, 2010 9:38 pm

Taking Keeper's idea and cutting out the middleman, makes for one step after importing "boo". This is probably the least "hacky" way to go about it, and it keeps the code looking clean.

boo.py
[code:3csgmg65]def sayBoo():
Text.Text = "Boo!"[/code:3csgmg65]
editor:
[code:3csgmg65]import boo
boo.Text = Text

boo.sayBoo()[/code:3csgmg65]

And if the Text object is renamed only one line needs to be modified in the editor from
[code:3csgmg65]boo.Text = Text[/code:3csgmg65] to [code:3csgmg65]boo.Text = tBoo[/code:3csgmg65]
B
79
S
24
G
54
Posts: 4,746
Reputation: 40,755

Post » Tue Sep 07, 2010 8:32 am

And by taking R0J0hound's idea you can pass around all variables using globals()

boo.py
[code:3onb2jrp]
def sayBoo():
vars['Text'].Text = "Boo!"
[/code:3onb2jrp]
event
[code:3onb2jrp]
import boo
boo.vars = globals()

boo.sayBoo()
[/code:3onb2jrp]

You still have to touch the code if you rename your objects but this way you can cycle on them since globals() returns a dict
B
1
G
2
Posts: 9
Reputation: 643

Post » Tue Sep 07, 2010 10:12 am

Fantastic guys!

Thank you so much, globals() is a very good approach. Only "System" isn't referenced, but maybe I find it when I don't look for it ;)
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Tue Sep 07, 2010 10:32 am

You can access System using globals() this way:
[code:37kwdjs9]
def sayBoo():
Text = vars['Text']
System = vars['System']
Text.Text = "Screen is %d,%d" % (System.DisplayWidth, System.DisplayHeight)
[/code:37kwdjs9]
B
1
G
2
Posts: 9
Reputation: 643

Post » Wed Sep 08, 2010 12:15 pm

[quote="Keeper":39u3aevf]You can access System using globals() this way:
[code:39u3aevf]
def sayBoo():
Text = vars['Text']
System = vars['System']
Text.Text = "Screen is %d,%d" % (System.DisplayWidth, System.DisplayHeight)
[/code:39u3aevf][/quote:39u3aevf]
Great! Thank you, Keeper, I'd say this is as close as possible to what I had in mind. Someone should start a wiki about Python with Construct, globals() should be more prominent :D
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Wed Sep 08, 2010 12:33 pm

Glad to be of help :P
But remember to organize your code and try to understand/use classes: they can make your life a lot easier!

boo.py
[code:3g03cgkv]
class Boo:
def __init__(self, Text, System):
self.Text = Text
self.System = System
def sayBoo(self):
self.Text.Text = "Screen is %d,%d" % (self.System.DisplayWidth, self.System.DisplayHeight)
[/code:3g03cgkv]

event
[code:3g03cgkv]
from boo import Boo
cboo = Boo(Text, System)
cboo.sayBoo()
[/code:3g03cgkv]
:mrgreen:
B
1
G
2
Posts: 9
Reputation: 643

Post » Wed Sep 08, 2010 1:03 pm

[quote="Keeper":25apxpgq]Glad to be of help :P
But remember to organize your code and try to understand/use classes: they can make your life a lot easier![/quote:25apxpgq]
I'm pretty familiar with Python and the concepts of modules, classes, methods, functions and oop. The background for my question was, that I'm coding a system that might be of help for many Constructors, and I want to establish it with the least effort for them as possible. The complete system shall run with no more than two (visible) scripts:

Start of layout:
[code:25apxpgq]
from fancypkgname import attractivemodulename

myclass = attractivemodulename.coolclass(globals())
[/code:25apxpgq]

Always:
[code:25apxpgq]myclass.update()[/code:25apxpgq]

They should not have to alter the code everytime they use it in another project. That was the intention ;)
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Next

Return to Help & Support using Construct Classic

Who is online

Users browsing this forum: No registered users and 8 guests