473,513 Members | 2,263 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

how to overload sqrt in a module?

I would like to write a module that provides some mathematical functions
on top of those defined in math, cmath etc. but I would like to make it
work with "any" type that overloads the math functions.

Thus, I would like to write:

module_f.py
----
def f(x):
""" Compute sqrt of x """
return sqrt(x)
from math import *
import module_f
module_f.f(3) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "module_f.py", line 2, in f
return sqrt(x)
NameError: global name 'sqrt' is not defined

I understand why sqrt is not in scope, but my question is: what is the
best way to do this?

Here is one fairly ugly solution:

module_g.py
-----------
def g(x,math):
return math.sqrt(x)
import math, cmath, module_g
module_g.g(2,math) 1.4142135623730951 module_g.g(-2,cmath)

1.4142135623730951j

I am sure there is a better way of doing this that makes use of the
type of the argument (Dynamical scoping would solve the
problem but we don't want to go there...). Note that the following
function would work fine

def f(x):
return abs(x)

because of the special member __abs__ attached to the type. There is no
corresponding member for sqrt, sin etc.

What is the "proper" pythonic way to do this?

Michael.
Mar 3 '06 #1
13 3752
Michael McNeil Forbes wrote:
I would like to write a module that provides some mathematical functions
on top of those defined in math, cmath etc. but I would like to make it
work with "any" type that overloads the math functions.

Thus, I would like to write:

module_f.py
----
def f(x):
""" Compute sqrt of x """
return sqrt(x)
from math import *
import module_f
module_f.f(3)


Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "module_f.py", line 2, in f
return sqrt(x)
NameError: global name 'sqrt' is not defined

I understand why sqrt is not in scope, but my question is: what is the
best way to do this?


You need to import math in the module that uses it. Imports in one
module don't (in general) affect the variables available in another module.

module_f.py
----
from math import sqrt # more explicit than from math import *
def f(x):
""" Compute sqrt of x """
return sqrt(x)

Kent
Mar 3 '06 #2
>> I would like to write a module that provides some mathematical functions on
top of those defined in math, cmath etc. but I would like to make it work
with "any" type that overloads the math functions.

Thus, I would like to write:

module_f.py
----
def f(x):
""" Compute sqrt of x """
return sqrt(x)
> from math import *
> import module_f
> module_f.f(3)


Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "module_f.py", line 2, in f
return sqrt(x)
NameError: global name 'sqrt' is not defined

I understand why sqrt is not in scope, but my question is: what is the best
way to do this?


You need to import math in the module that uses it. Imports in one module
don't (in general) affect the variables available in another module.

module_f.py
----
from math import sqrt # more explicit than from math import *
def f(x):
""" Compute sqrt of x """
return sqrt(x)

Kent


I know, but the point is that I want to allow the user of the module to be
able to specify which sqrt function should be used depending on the type
of x. Importing math in the module would prevent the user from using f()
with complex types (or dimensioned types for another example).

That is why I suggested the ugly, but functional solution

module_g.py
-----------
def g(x,a_math):
"""Compute sqrt of x using a_math.sqrt)
return a_math.sqrt(x)

The user can at least specify to use cmath instead of math:
import cmath, module_g
module_g.g(8j,cmath)

(2+2j)

Michael.

Mar 3 '06 #3
Michael McNeil Forbes wrote:
Here is one fairly ugly solution:

module_g.py
-----------
def g(x,math):
return math.sqrt(x)

import math, cmath, module_g
module_g.g(2,math)
1.4142135623730951
module_g.g(-2,cmath)


1.4142135623730951j

I am sure there is a better way of doing this that makes use of the
type of the argument (Dynamical scoping would solve the
problem but we don't want to go there...). Note that the following
function would work fine

def f(x):
return abs(x)

because of the special member __abs__ attached to the type. There is no
corresponding member for sqrt, sin etc.

What is the "proper" pythonic way to do this?


Use the appropriate library which already implements the features you want.

In [8]: class A(object):
...: def __init__(self, x):
...: self.x = x
...: def sqrt(self):
...: return 2*self.x
...:
...:

In [9]: a = A(10)

In [10]: import numpy

In [11]: numpy.sqrt(a)
Out[11]: 20

In [12]: numpy.sqrt(10)
Out[12]: 3.1622776601683795

In [13]: numpy.sqrt(10j)
Out[13]: (2.2360679774997898+2.2360679774997898j)

--
Robert Kern
ro*********@gmail.com

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter

Mar 3 '06 #4
> Michael McNeil Forbes wrote:
Here is one fairly ugly solution:

module_g.py
-----------
def g(x,math):
return math.sqrt(x)

> import math, cmath, module_g
> module_g.g(2,math)
1.4142135623730951
> module_g.g(-2,cmath)


1.4142135623730951j

What is the "proper" pythonic way to do this?

On Thu, 2 Mar 2006, Robert Kern wrote:
Use the appropriate library which already implements the features you want.

In [8]: class A(object):
...: def __init__(self, x):
...: self.x = x
...: def sqrt(self):
...: return 2*self.x
...:
...:

In [9]: a = A(10)

In [10]: import numpy

In [11]: numpy.sqrt(a)
Out[11]: 20

In [12]: numpy.sqrt(10)
Out[12]: 3.1622776601683795

In [13]: numpy.sqrt(10j)
Out[13]: (2.2360679774997898+2.2360679774997898j)

--
Robert Kern


Thanks. This solution is essentially to make sure that all "numeric"
objects have .sqrt etc. members, and then use a library which check
against builtin types and custom types with these extensions.

That works, as long as the appropriate library exists (or I write it
myself) (and this works in my case: I did not realize that the numpy/scipy
functions worked this way.)

Are there any other more generic solutions (without having to write
"custom" functions like numpy.sqrt)?

Michael
Mar 3 '06 #5
Michael McNeil Forbes wrote:
Are there any other more generic solutions (without having to write
"custom" functions like numpy.sqrt)?


No. *Someone* always has to write those "custom" functions. In the case of len()
and abs(), that someone was Guido. For numpy.sqrt(), that someone was Travis
Oliphant. For anything else you want, that someone is probably you.

--
Robert Kern
ro*********@gmail.com

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter

Mar 3 '06 #6
>> Are there any other more generic solutions (without having to write
"custom" functions like numpy.sqrt)?


No. *Someone* always has to write those "custom" functions. In the case of len()
and abs(), that someone was Guido. For numpy.sqrt(), that someone was Travis
Oliphant. For anything else you want, that someone is probably you.


Thanks Guido! Thanks Travis:-)

What I was thinking was: is there some way to pass a parameter to the
module on import so that the module can then use the correct environment.

If I could pass a dictionary to the module with all of the overloaded
functions, then they could become part of the module's environment and
used appropriately. I could not find a way of passing such a dictionary.

Michael.
Mar 3 '06 #7
> On Thu, 2 Mar 2006 16:12:53 -0800, Michael McNeil Forbes wrote:
I would like to write a module that provides some mathematical functions
on top of those defined in math, cmath etc. but I would like to make it
work with "any" type that overloads the math functions.
On Fri, 3 Mar 2006, Dennis Lee Bieber wrote: Since Python doesn't dispatch based on parameter types, there are
only two choices that I can see...

Either the CALLER already knows what the arguments are, and has
coded an explicit call to the version of the function desired...
The caller does know in my case, but wants to reuse old code that performs
a complicated computation using the standard math functions. I was
thinking that maybe there was some way for the caller to pass the
appropriate functions to the module on import, but could not find a way of
doing this.
OR, the caller imports and calls your special module, and your
special module has to import ALL possible override modules and supply a
function that determines which of the modules is to be used...


This is essentially what numpy.sqrt() etc. does as pointed out by Robert
Kern. The numpy.sqrt() seems to check if the argument is real, complex,
or some other type and calls either math.sqrt, cmath.sqrt or x.sqrt()
appropriately. This works for my problem: I just wondered if there was a
more generic solution without having to do this work.

Thanks,
Michael.
Mar 3 '06 #8
On Thu, 02 Mar 2006 19:24:48 -0800, mforbes wrote:

[snip]
I know, but the point is that I want to allow the user of the module to be
able to specify which sqrt function should be used depending on the type
of x. Importing math in the module would prevent the user from using f()
with complex types (or dimensioned types for another example).


If I don't misunderstood the problem, you can define an "init" method for
your module_g

(code not tested)

module_g.py
-----------

_functions = {}
def init(mathmodule):
_function['sqrt'] = getattr(mathmodule, 'sqrt', None)

def _get(name):
try:
return _functions[name]
except KeyError:
raise TypeError("you have to initialize module_g")

def sqrt(x):
return _get('sqrt')(x)

main.py
-------

import math
import module_g

module_g.init(math)
print module_g.sqrt(2)
HTH

Mar 3 '06 #9
On Thu, 02 Mar 2006 22:35:51 -0800, Michael McNeil Forbes wrote:
What I was thinking was: is there some way to pass a parameter to the
module on import so that the module can then use the correct environment.

If I could pass a dictionary to the module with all of the overloaded
functions, then they could become part of the module's environment and
used appropriately. I could not find a way of passing such a dictionary.


Not on import, but 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?
--
Steven.

Mar 3 '06 #10
On Fri, 3 Mar 2006, david mugnai wrote:

[snip]

If I don't misunderstood the problem, you can define an "init" method for
your module_g

(code not tested)

module_g.py
-----------

_functions = {}
def init(mathmodule):
_function['sqrt'] = getattr(mathmodule, 'sqrt', None)

def _get(name):
try:
return _functions[name]
except KeyError:
raise TypeError("you have to initialize module_g")

def sqrt(x):
return _get('sqrt')(x)

main.py
-------

import math
import module_g

module_g.init(math)
print module_g.sqrt(2)


Thanks, this gets me close. Is there anything really bad about the
following? It works exactly as I would like, but I don't want to get in
trouble down the road:

module_f
--------
import math as my_math

def set_math(custom_math):
globals()['my_math'] = custom_math

def f(x):
return my_math.sqrt(x)
import module_f
module_f.f(2) 1.4142135623730951 import cmath
module_f.set_math(cmath)
module_f.f(2j)

(1+1j)

Or, if one wants to use the "from __ import *" form:

from math import *

def set_math(custom_math):
globals().update(custom_math.__dict__)

def f(x):
return sqrt(x)

Michael
Mar 5 '06 #11
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.

import math as my_math

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

Thanks,
Michael.
Mar 5 '06 #12
Michael McNeil Forbes wrote:
Is there anything really bad about the
following? It works exactly as I would like, but I don't want to get in
trouble down the road:

module_f
--------
import math as my_math

def set_math(custom_math):
globals()['my_math'] = custom_math
This seems clearer to me:
def set_math(custom_math):
global my_math
my_math = custom_math
Or, if one wants to use the "from __ import *" form:

from math import *

def set_math(custom_math):
globals().update(custom_math.__dict__)


This will cause interesting trouble if custom_math doesn't implement all
the functions you use from math.

Kent
Mar 5 '06 #13
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.

Mar 5 '06 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
12025
by: Equis Uno | last post by:
Hi there, I just figured out how to use __add__() to overload the "+" operator for objects of a class. According to googel queries, I see other functions available to me for overloading other...
10
7302
by: pauldepstein | last post by:
I am writing a program which will use the ceiling and floor of square roots. If a positive integer is an exact square (and is not overly huge), does sqrt return an integer-valued real? Or...
7
6759
by: Aric | last post by:
Hi, I'm a bit new to programming in general, really I've just picked it up as a hobby, and so I've started by reading "Practical C Programming" by Steve Oualline. Things have been going fine in...
13
2697
by: Vladimir Granitsky | last post by:
Hi guys, Please, look at the code below and try to step into it. The compiled code calls the loosely typed method public void Method1(object o) !?!? Am I right that C# compiler does wrong...
12
6291
by: Thomas Zhu | last post by:
hello all, n is an 32bit-integer, how to calculate sqrt(n) I know high(n) is the the value, but how to use bit operation to implement this function. thanks in advance. yours Yin
13
4940
by: siggi | last post by:
Hi all, this is a newbie question on : Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) on win32 PC with WinXP In http://www.python.org/doc/2.3.5/lib/module-math.html I read:
30
3998
by: copx | last post by:
I am writing a program which uses sqrt() a lot. A historically very slow function but I read on CPUs with SSE support this is actually fast. Problem: C's sqrt() (unlike C++ sqrt()) is defined to...
13
10459
by: =?Utf-8?B?RXRoYW4gU3RyYXVzcw==?= | last post by:
Hi, Why does Math.Sqrt() only accept a double as a parameter? I would think it would be just as happy with a decimal (or int, or float, or ....). I can easily convert back and forth, but I am...
6
4154
by: Blue sky | last post by:
Hi ,I think the follow program is right in logical But why the compiler output :"square:declared identifier" #include<stdio.h> #include<math.h> int main() { double x1;
0
7388
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
1
7114
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
7541
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5693
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5098
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
3240
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3230
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
807
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
461
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.