Setting a variable in the global scope

Posted by Icewolf on Thu 06 May 2010 03:32 PM — 16 posts, 76,807 views.

#0
I know one can set global variables in the module's global scope, that is, using global().

But how can a module set a variable into the __ax_main__ scope??? something like:


module A:
import __ax_main__
__ax_main__.aaa = 111


in mushclient's script:
import A
dir() # I want "aaa" to be here
#1
I found out that the global name space (or __main__ in a non-activeX version python) can be accessed via:

ax._scriptEngine_.globalNameSpaceModule
USA #2
Messing around with the globals' is not such a great idea within Python/MUSHclient scope.

The Garbage collection in Python will just clear out the globals after a time of not being accessed.

For whatever reason you're doing this, a better way would most likely be to initialize your own 'scope', class, or dictionary containing variables key/value pairs.
USA #3
Quote:
The Garbage collection in Python will just clear out the globals after a time of not being accessed.

No, garbage collection has nothing whatsoever to do with the time at which a variable was last accessed. As long as there is a reference to a piece of memory, it will remain present.

That said, it is indeed often better to not try to rely too much on the "true global" scope.
#4
Thanks for the replies. Yes, I know what I'm doing here:)

First of all, I agree with David that GC is not an issue, as long as you keep a reference to the object.

Second, I'm exposing *a few* *functions* into the global name space because when Mushclient's trigger/alias/timer fires, and if you set it to call-back a function, then Mushclient only knows to search in ax._scriptEngine_.globalNameSpaceModule for that function.

(BTW, it must be a function, and cannot be a *callable object*.)

If I'm writing all the script in the file that is included directly by Mushclient, then I can just use "globals()" to access the global symbol table. Or, if we are just using the "normal" python, we can "import __main__" and set an object to __main__'s attribute.

However, this does not work in Mushclinet (or activeScript), because:

1. "__main__" seems not to be the real global name space. (ax._scriptEngine_.globalNameSpaceModule is)

2. From a module other than the one directly included by the mushclient, one cannot use the "globals()" trick.

Therefore, if one wants his/her codes to be modular, and wants to use the trigger/alias/timer's callback feature, here's the only way I've seen so far:

1. Expose a global trigger/alias/timer function dispatcher (or delegation), which will be called by any fired trigger/alias/timer.

2. This dispatcher looks up a table, according to the fired trigger/alias/timer's name, to invoke the real callback function.

Thanks,

KL
USA #5
Good workaround. Maybe we could convince Nick to add a function that returns the real globals dictionary, so that you can add these callbacks yourself. There might be some security concerns to think about, but your use case seems pretty good to me.
#6
David Haley said:

Good workaround. Maybe we could convince Nick to add a function that returns the real globals dictionary, so that you can add these callbacks yourself. There might be some security concerns to think about, but your use case seems pretty good to me.


I would never refuse any effort to enhance Mushclient's Python experience:) However I do doubt if this issue is within the scope of Mushclient - it seems that a WSH (which uses activeScript to call python) also has a similar behavior. Maybe we should blame M$ on this?
USA #7
Icewolf said:

... it seems that a WSH (which uses activeScript to call python) also has a similar behavior. Maybe we should blame M$ on this?


Seeing how MS coded neither activeScript.py or Python, I say we blame Obama. Your globals have been taxed so that they can be given to namespaces with fewer variables.
Australia Forum Administrator #8
David Haley said:

Good workaround. Maybe we could convince Nick to add a function that returns the real globals dictionary, so that you can add these callbacks yourself.


I don't begin to imagine how I might do that. The interface to the WSH is rather simple (and confusing I have to say).

I'm not sure if the problems you describe are the fault of Python, ActivePython, or the Windows Script Host design. However I think we can let Obama off the hook.
USA #9
Well, I'll preface this by saying that I know nothing about ActivePython or WSH. But what you'd need to do would be to give access to the Python global dictionary, one way or another, even just to add entries to it. If all you have is a pretty simple interface, it might be impossible.
#10
Nick Gammon said:

David Haley said:

Good workaround. Maybe we could convince Nick to add a function that returns the real globals dictionary, so that you can add these callbacks yourself.


I don't begin to imagine how I might do that. The interface to the WSH is rather simple (and confusing I have to say).

I'm not sure if the problems you describe are the fault of Python, ActivePython, or the Windows Script Host design. However I think we can let Obama off the hook.


It would be nice to know how Mushclient make a judge that whether the subroutine specified in a trigger/timer/alias 's "script" is valid or not. Therefore we will know why is that a valid __callable__ python object (but not function) cannot be viewed as a valid subroutine by Mushclient.
USA #11
If it's any consolation, you can't use a Lua table with a __call metamethod as a script callback either.
#12
Twisol said:

If it's any consolation, you can't use a Lua table with a __call metamethod as a script callback either.


It would be interesting to know the reason under the "coincidence"
Australia Forum Administrator #13
Icewolf said:

It would be nice to know how Mushclient make a judge that whether the subroutine specified in a trigger/timer/alias 's "script" is valid or not. Therefore we will know why is that a valid __callable__ python object (but not function) cannot be viewed as a valid subroutine by Mushclient.


It calls IDispatch::GetIDsOfNames to see if the dispatch pointer for the script engine can be used to convert that name into a dispatch ID. This is required for that script function to be subsequently called using the OLE routines.

http://msdn.microsoft.com/en-us/library/aa909091.aspx

This does not apply to Lua (which you are not asking about) as that does not use OLE for its scripting implementation.

In the case of Lua (as Twisol alluded to the __call metamethod) it simply checks if the named function is available in global Lua script space (after resolving nesting, eg. string.upper would work, although "string" is a table, and "upper" is a function inside that table).
USA #14
That got me wondering, and upon testing it I found something weird...


/print(pcall(imaginaryfunc("hi")))


I was expecting to see "false attempt to call global 'imaginaryfunc' (a nil value)" but it still gives the standard World Errors (noted in orange, not cadetblue). Can you use pcall from the command line?


So my thought was to use a pcall(TablewithCallmeta(arg)) which should pass your check, since pcall is a function.

I was going to suggest wrapping the attempt to call m_strProcedure in a pcall. Is it better to exclude code that would work in an attempt to filter out ones that don't?

Australia Forum Administrator #15
I got this (in orange):


Run-time error
World: SmaugFUSS
Immediate execution
[string "Command line"]:1: attempt to call global 'imaginaryfunc' (a nil value)
stack traceback:
        [string "Command line"]:1: in main chunk


WillFa said:

So my thought was to use a pcall(TablewithCallmeta(arg)) which should pass your check, since pcall is a function.


The issue isn't whether or not it is a function, but whether it is a function at global scope. For example, hotspot callback functions need to be found at global scope (in Lua) so they can't be local functions (and I imagine a similar thing applies to Python).

What you may be able to do is make a stub function in global scope which calls the function you really want called. In fact, in Lua since you can assign functions as they are first-class values, there is no reason the function that is detected by MUSHclient (eg. when loading a trigger) has to be the same one later on. In Lua's case they are simply called by name later on, in the case of the WSH they are called by dispatch ID (the ID being the thing that is checked for as described above).

So depending on the internals of the script engine, if you can make it resolve a dispatch ID to be something else later, the function it calls might vary. Or, just use a stub function.