how to overload sqrt in a module?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Sun Mar 5 08:17:42 EST 2006


On Sat, 04 Mar 2006 23:07:12 -0800, Michael McNeil Forbes wrote:

> On Fri, 3 Mar 2006, Steven D'Aprano wrote:
> 
>> ... you can do this:
>>
>> import my_module
>> my_module.set_environment("math") # or cmath, or numeric, or whatever
>>
>> Your my_module will be like this:
>>
>> # Warning: untested code.
>> ENVIRON = None  # global variables sometimes have their uses
>>
>> def f(x):
>>    if ENVIRON is None:
>>        raise ValueError("Uninitialised module!")
>>        # or use a custom exception
>>    return ENVIRON.sqrt(x)
>>
>> def set_environment(name):
>>    global ENVIRON
>>    ENVIRON = __import__(name)
>>
>>
>> Does this help?
> 
> Yes.  However, this raises a question: Is this any different than 
> directly modifying the globals, or is it just syntactic sugar.

The keyword "global" instructs Python to make all references to the
following name come from the global namespace. It is the correct way to
do it (but not necessarily the *only* correct way, or *always* the
correct way). In something as tiny as your example:

> def set_environment(name):
>      globals()['ENVIRON'] = __import__(name)

it may not make any practical difference which method you use. But in
larger, more complex code, you are creating a rod for your own back. Try
running these three functions, and explain the difference in their
behaviour.

def f1():
    global parrot
    parrot = 3
    parrot += 1
    print "parrot is %d" % parrot

def f2():
    globals()["parrot"] = 3
    globals()["parrot"] += 1
    print "parrot is %d" % parrot

def f3():
    globals()["parrot"] = 3
    parrot += 1
    print "parrot is %d" % parrot


Directly modifying the globals is playing around with Python's internals.
You are allowed to do that, and sometimes it is the right thing to do,
otherwise Guido wouldn't have made globals() writable. 

E.g. you have code where you want -- heaven knows why -- a name to refer
to both a local and a global variable. This will work:

def func():
    x = 5  # x is local
    globals()['x'] = 3  # but this x is global


I don't know whether writing to globals() is guaranteed to work for all
variants of Python (CPython, Jython, PyPy, IronPython ... ) or if it is
likely to change in Python 3. But even if modifying globals() is
officially allowed, it still has a whiff of the sort of code-smell that
Joel Spolsky talks about:

http://www.joelonsoftware.com/articles/Wrong.html

In my opinion, manipulating globals() is one of those things that ring
warning bells in my head. It might not be *wrong*, exactly, but I'll want
to pay extra attention to any function that does that.


-- 
Steven.




More information about the Python-list mailing list