Scoping question (Python scripts)
I'm unclear on how scoping is handled in Python scripts. ===== ## parameters = name print "Hello %s" % name return printed ===== works as a script but: ===== ## parameters = name print function() print "Hello %s" % name return printed def function(): return "Goodbye" ===== does not -- because 'function' is not found. However: ===== ## parameters = name def function(): return "Goodbye" # Main print function() print "Hello %s" % name return printed ===== is OK, as 'function' is defined above the main stuff. However I can't get 'function' to see another function e.g.: ===== ## parameters = name def add2(a): return a+2 def function(): n = add2(3) return "Goodbye" # Main print function() print "Hello %s" % name return printed ===== 'add2' won't be found, I guess because it's "two levels deep" (??). However, it'll work if I make 'add2' internal to 'function'... ===== ## parameters = name def function(): def add2(a): return a+2 n = add2(3) return "Goodbye" # Main print function() print "Hello %s" % name return printed ===== So what are the rules here? I'm used to Python modules with one shared scope for all top-level function defs, no matter what level they're called from. Why can't 'add2' be defined at the same level as 'function' (above), or is there syntax to make this work (I've been trying stuff like script.add2(3) or context.add2(3) but that doesn't help). Help? Kirby
On Mon, Apr 09, 2001 at 12:38:55AM -0700, Kirby Urner wrote:
I'm unclear on how scoping is handled in Python scripts.
===== ## parameters = name print "Hello %s" % name return printed =====
works as a script but:
===== ## parameters = name print function() print "Hello %s" % name return printed
def function(): return "Goodbye" =====
does not -- because 'function' is not found. However:
===== ## parameters = name def function(): return "Goodbye"
# Main print function() print "Hello %s" % name return printed
=====
is OK, as 'function' is defined above the main stuff. However I can't get 'function' to see another function e.g.:
===== ## parameters = name
def add2(a): return a+2
def function(): n = add2(3) return "Goodbye"
# Main print function() print "Hello %s" % name return printed
=====
'add2' won't be found, I guess because it's "two levels deep" (??). However, it'll work if I make 'add2' internal to 'function'...
===== ## parameters = name
def function(): def add2(a): return a+2
n = add2(3) return "Goodbye"
# Main print function() print "Hello %s" % name return printed
=====
So what are the rules here? I'm used to Python modules with one shared scope for all top-level function defs, no matter what level they're called from. Why can't 'add2' be defined at the same level as 'function' (above), or is there syntax to make this work (I've been trying stuff like script.add2(3) or context.add2(3) but that doesn't help).
This sounds like your typical Python nested namespaces problem, which is solved in Python 2.1 in an optional __future__ module, and standard fare in Python 2.2. A python Script is a function in itself, so it's namespace isn't the global module space you are expecting. Normally, you would indeed expect function() and add2() to be visible throughout your script, as they have been defined at the module level. However, a Python Script isn't defined at the module level; it is defined as a function within a module. you should mentally indent the whole code and add 'function <id of PS here>(<paramater list here>):' before it. So, here only the local scole rules apply: only names that have been declared before you are visible, and you get a new local namespace when calling a function. Python 2.1 solves this problem by introducing nested scopes. I assume that because Zope 2.4 will probably require Python 2.1, the problem will disappear (if Python Scripts do a 'from __future__ import nested_scopes). For now however, you'll have to live with this problem, or see if you can manipulate globals() in Python Scripts (not sure if you can). A good overview of what nested scopes are about, see: http://www.amk.ca/python/2.1/index.html#SECTION000300000000000000000 The original PEP is at: http://python.sourceforge.net/peps/pep-0227.html And finally, the official documentation can be found at: http://python.sourceforge.net/devel-docs/ref/nested-scopes.html -- Martijn Pieters | Software Engineer mailto:mj@digicool.com | Digital Creations http://www.digicool.com/ | Creators of Zope http://www.zope.org/ ---------------------------------------------
At 11:39 AM 4/9/2001 +0200, Martijn Pieters wrote: <<SNIP>>
A python Script is a function in itself, so it's namespace isn't the global module space you are expecting. Normally, you would indeed expect function() and add2() to be visible throughout your script, as they have been defined at the module level. <<SNIP>> -- Martijn Pieters | Software Engineer mailto:mj@digicool.com | Digital Creations http://www.digicool.com/ | Creators of Zope http://www.zope.org/ ---------------------------------------------
Thank you sir, this was a trully helpful clue. This explains a lot of my mental difficulties. Here's another question along the same lines -- directed to anyone (like, I understand if you're busy). Even in an earlier Python like 1.5.2 I believe it's legal to write a function like this: ========== def f(): class test: def d(self,n): return n+100 def c(self,n): n = n + self.d(n) return n+10 om = test() j = om.c(3) return j ========== There's a class defined internally to the function. The above works for me in regular Python (2.1 beta -- but I'm not depending on nested scopes, no importing from __future___, and no warnings for not). However, if I strip off the top line and make the rest be a "function body" ala a Zope script (de-indent the rest of the lines), like this: ========== class test: def d(self,n): return n+100 def c(self,n): n = n + self.d(n) return n+10 om = test() j = om.c(3) return j ========== ...then when I try to save it I get: Forbidden operation STORE_NAME at line 4 Forbidden operation STORE_NAME at line 7 So is there something about Python classes that they can't be defined internally to an ordinary function/script? I've been seeing a lot of text about "publishing a product" which involves doing some bookkeeping stuff I was hoping to avoid. The on-line docs seem to go from "Hello world" type scripts (and vaccinating a hippo) to publishing products, without a whole lot in between (and so my train of thought keeps falling through the cracks). Kirby
On Mon, Apr 09, 2001 at 08:56:54AM -0700, Kirby Urner wrote:
Here's another question along the same lines -- directed to anyone (like, I understand if you're busy).
Even in an earlier Python like 1.5.2 I believe it's legal to write a function like this:
==========
def f():
class test:
def d(self,n): return n+100
def c(self,n): n = n + self.d(n) return n+10
om = test() j = om.c(3) return j
==========
There's a class defined internally to the function. The above works for me in regular Python (2.1 beta -- but I'm not depending on nested scopes, no importing from __future___, and no warnings for not).
However, if I strip off the top line and make the rest be a "function body" ala a Zope script (de-indent the rest of the lines), like this:
==========
class test:
def d(self,n): return n+100
def c(self,n): n = n + self.d(n) return n+10
om = test() j = om.c(3) return j
==========
...then when I try to save it I get:
Forbidden operation STORE_NAME at line 4 Forbidden operation STORE_NAME at line 7
So is there something about Python classes that they can't be defined internally to an ordinary function/script?
I *think* this is because you are not allowed to manipulate classes from Python Script What I think happens is that the special Python bytecompiler used to parse and compile the above Python Script is that as soon as you get to the 'def d(self, n):' statement, you are trying to store a new method in the 'test' class, which the compiler has been told you are not allowed to do. Because you try and do this twice, you get two errors. As for the reason why: if you could manipulate classes in the Zope framework, you'd probably be able to break the security somewhere with a well aimed method in a key class. This would not be a good idea, so Ethan wisely disabled that. This restriction could posibly be loosened to allow for locally defined classes, but I have no experience with restricting python bytecode compilations.
I've been seeing a lot of text about "publishing a product" which involves doing some bookkeeping stuff I was hoping to avoid.
The on-line docs seem to go from "Hello world" type scripts (and vaccinating a hippo) to publishing products, without a whole lot in between (and so my train of thought keeps falling through the cracks).
There are a great deal many more documents; try the Zope Book, and Itamar's Developers Guide is also excellent: http://www.zope.org/Members/michel/ZB http://itamarst.org/learningzope/ In the meantime, you can use External Methods to accomplish things in an unrestricted environment. -- Martijn Pieters | Software Engineer mailto:mj@digicool.com | Digital Creations http://www.digicool.com/ | Creators of Zope http://www.zope.org/ ---------------------------------------------
From: "Kirby Urner" <pdx4d@teleport.com>
So is there something about Python classes that they can't be defined internally to an ordinary function/script?
They cannot usefully be defined in a Script, and Scripts aren't geared towards that sort of use. Defining classes is the sort of thing that ZClasses and filesystem Products are good for. There are a number of Howtos on zope.org that explain how to write simple Products and ZClasses. What sort of problem are you trying to solve? Cheers, Evan @ digicool
At 01:18 PM 4/9/2001 -0400, Evan Simpson wrote:
From: "Kirby Urner" <pdx4d@teleport.com>
So is there something about Python classes that they can't be defined internally to an ordinary function/script?
They cannot usefully be defined in a Script, and Scripts aren't geared towards that sort of use. Defining classes is the sort of thing that ZClasses and filesystem Products are good for. There are a number of Howtos on zope.org that explain how to write simple Products and ZClasses.
What sort of problem are you trying to solve?
At this point I'm prototyping/learning and wanted to generate a 100-digit probably-prime number using Python. Every time you reload the page, you get a different number, computed on the fly. Here's the URL (takes a few seconds to load/reload): http://freezope2.nipltd.net/pdx4d/content/primes/bigprime The code originally comes from a Python module I wrote outside of Zope (in 2.1, so I had to change some syntax) with several function defs. I was treating a Zope script object as a Python module but have since learned from Martijn Pieters that it's to be treated as a single function. Either way, I would rather keep all the code in one place, versus parsing each little function out to a separate script file and using context.function(n) calls to tie them together (I'd done it that way somewhere along the learning curve, but prefer the current "internal defs" solution, with all code in one file). So the solution I have right now uses the nested functions structure, but I thought maybe I could get around this with a class structure. Guess not -- unless I go to the next level. I'm learning in a free Zope hosting system as well as on my local machine. I'm not sure whether I'll be able to define any "External Methods" on the free host (sounds like something the ISP would not allow). I've read 'how-tos' about publishing a Product but have yet to venture over this bridge (presuming this test environment will let me). I'd just read the Zope Book about vaccinating the hippo, and was trying to hover at that beginner level of simplicity as long as possible, using nothing more than a basic Python script object invoked by DTML. It works as is, but I wondered if this was the optimum way of doing it. Kirby
Cheers,
Evan @ digicool
Kirby Urner wrote:
I'm learning in a free Zope hosting system as well as on my local machine. I'm not sure whether I'll be able to define any "External Methods" on the free host (sounds like something the ISP would not allow).
Correct, External methods require you to have FileSystem access to the server, which is obviously something we can't offer on FreeZope ;-) cheers, Chris
participants (4)
-
Chris Withers -
Evan Simpson -
Kirby Urner -
Martijn Pieters