Help needed - function apparently global cannot be called.

Ian hobson42 at gmaiil.com
Tue Sep 7 16:00:37 CEST 2010


  Hi Bruno,

Thanks for your quick response.  I still do not understand.

On 07/09/2010 11:50, Bruno Desthuilliers wrote:
> Ian Hobson a écrit :
>> Hi all you experts,
>>
>> This has me beat. Has anyone any ideas about what might be going wrong?
>>
>> This is code from within a windows service (hence no print statements 
>> - no sys.stdout to print on!).
>>
>> I am trying to trace through to find where the code is not working. 
>> No stdout so I have to log to a file.
>
> Then you'd be better using the logging module from the stdlib. And 
> FWIW,  you should try to make you code testable in a non-service 
> context...
Thanks for the tip. "Batteries included" means there are so many 
batteries you miss some.

The Module I am trying to use works perfectly as a free standing routine.

>
>> I have the following code fragments.
>>
>> def log(message):
>>     f = open('d:\logfile.txt','a')
>>     f.write(message + "\n")
>>     f.close()
>>
>> from DelNotePrinter import DelNotePrinter
>
> <OT>
> The convention is to use all_lower_names for modules - having modules 
> and classes with the same (case-sensitive) name can be very misleading.
> </OT>
The convention is a good one.
>
>> note the order of the above - log is defined before the import.
>
> And ? Do you think it will affect the imported module in any way ? 
> Like, say, magically "inject" your log function in the DelNotePrinter 
> module ?-)
Just that log is defined before the global log is encountered to that if 
the compiler needed to set up a link at compile time it was able to do so.

>
>
>> Later in the  source
>
> Where ?
>
About 350 lines further down.
>> I have
>>
>>         log('disPrint is:'+disPrint)
>>         log('count is:'+count)
>
> Do yourself a favor and learn string formating...
Agreed. :) - These are debug statements to discover what is going on.

I have had so much trouble with problems NOT being reported, that I 
avoid anything that I am not 100% sure must work.

>
>>         log(repr(DelNotePrinter))
>>         printer = DelNotePrinter(disPrint,int(count))
>
>
>> The DelNotePrinter.py file cannot us log even though it is declared
>> as global.
>
> In Python, "global" means "module-level", and it's only necessary when 
> you want to rebind a module-level name from within a function or method.
Exactly! I want to bind the name log to the function I wrote.
So I carefully placed log in global scope and told the compiler that 
when I referred to log I meant the global one I wrote.
I expected that to bind log to the function I wrote.
The compiler did not complain it was undefined (which would have caused 
a trackback on the Event log).

But neither was the routine called.   :(

I still don't understand what is going wrong.
>
>  The code is...
>>
>> # coding=utf8
>> #    DelNotePrinter = code to print delivery notes
>>   assorted imports removed for space reasons
>
> Some of these imports surely explain why you don't just get a 
> NameError when trying to call log() - wild guess : you have some "from 
> xxx import *" statement that does import another callable named 'log'.
>
I don't think so. The lines are

import sys
import datetime
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from DataBaseClass import DataBase

I know all PyQt classes begin with Q.  Database I wrote, and it has no 
log in it.

>> class DelNotePrinter(object):
>>     ''' Print Delivery Note on A5 in portrait '''
>>     def __init__(self,printer,copies):
>>         ''' create printer and painter '''
>>         global font,sm,log
>>         log('DelNotePrinter: starting')
>
>
>>         self.printer = QPrinter(QPrinter.HighResolution)
>
> If you want to access a name (function, class, whatever) defined in 
> another module, you have to explicitely import it.
>
>>
>> The file the log writes contains..
>> disPrint is:HP Deskjet 6940 series
>> count is:1
>> <class 'DelNotePrinter.DelNotePrinter'>
>>
>> The > is followed by a newline and end of file! Where is the 
>> DelNotePrinter: starting message?
>
> We can't tell - but you can get at least some hint, cf below
>
>> If I replace the opening of __init__ with
>>     global font,sm,log
>>         f = open('d:\logfile.txt','a')
>>         f.write('DelNotePrinter: starting' + "\n")
>>         f.close()
>>         self.printer = QPrinter(QPrinter.HighResolution)
>>
>> then the message IS written to the log file.
>
> Obviously, yes. Now please add this to your code:
>
> class DelNotePrinter(object):
>     ''' Print Delivery Note on A5 in portrait '''
>     def __init__(self,printer,copies):
>         ''' create printer and painter '''
>         global font,sm,log
>         f = open('d:\logfile.txt','a')
>         f.write('DelNotePrinter: starting' + "\n")
>
>         # check what "log" is bound to in the currrent namespace
>         f.write(
>            "DelNotePrinter : log is '%s' from '%s'" % (
>               log, log.__module__
>               ))
>         f.close()
>         self.printer = QPrinter(QPrinter.HighResolution)
>
I tried that (using copy/paste) and got no output! So I modified is 
slightly to

         global log
         f = open('d:\logfile.txt','a')
         f.write("test message\n")
         f.write(
            "DelNotePrinter : log is '%s' from '%s'" % (
               log, log.__module__
               ))
         f.close()
         self.printer = QPrinter(QPrinter.HighResolution)

I get my "test message" and then nothing.  When I close the service, the 
next
log message comes from the closing code.

There are no errors reported, no messages, no Event log entries and 
nothing further happens. Its as if the thread died.

>> I have read http://docs.python.org/reference/simple_stmts.html#global 
>> very carefully and I still don't understand.
>
> The statement definition makes no sense if you don't understand 
> namespaces and bindings:
>
> http://docs.python.org/reference/executionmodel.html#naming-and-binding
>
Thanks for the pointer. What a truly execrable piece of writing - full 
of over-long sentences and multiple subordinate clauses. It routinely 
uses terms before definition, and sometimes without definition.  It is 
astonishingly bad.

The third sentence reads "Each occurrence of a name in the program text 
refers to the /binding/ of that name established in the innermost 
function block containing the use."  What does that mean? It appears to 
mean that it is the assignment in the innermost function block that 
binds for all uses, not the first, not module blocks, not class blocks 
and not code blocks - but the innermost function block. That might be 
correct, but somehow I doubt it, for it would mean that earlier bindings 
are ignored or invalidated or not used or something - even if the inner 
block is not executed.

I am not stupid and English is my mother tongue, and I have read that 
page many times.  The implications of the passage are still opaque to me.

How can I call a global function placed at the top of the source.  Do I 
really have to move a 4 line function into its own file and import it 
again and again and again?

Regards

Ian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20100907/12dd0ce4/attachment.html>


More information about the Python-list mailing list