-1

I need to define a class which extends python's standard math module, without instantiating it (no need for that, all methods in the class are static):

import math

class more_math(math):

    @staticmethod
    def add_func(x):
        return math.sqrt(x)+1

The code above doesn't run properly (script exits), with the error:

TypeError: Error when calling the metaclass bases
    module.__init__() takes at most 2 arguments (3 given)

When the class declaration above is set to class more_math:, more_math.add_func(x) is called without error. However, more_math.sqrt(x) [sqrt is a method of math] can't be called, as more_math doesn't have math as its base class.

Ideas on how could this be setup properly?

martineau
  • 119,623
  • 25
  • 170
  • 301
GG_Python
  • 3,436
  • 5
  • 34
  • 46

3 Answers3

2

Think long and hard about whether you actually need to provide the functions math implements. You almost certainly don't; you probably just need to provide your extras. That said, if you do need to provide a more_math module that implements all the standard math functions too, the easiest way to do this is to do a from math import *. This will bring every function the math module defines into your module. This is considered very bad practice, because it pollutes the namespace of your module and can make it difficult to tell what is actually being used. However, in this case, pollution of your module's namespace is exactly what you want.

gbe
  • 671
  • 3
  • 11
  • While the answer above is great guidance, i've probably not communicated the question properly: I want more_math to hold all the functionality of math + added functions. I really don't want to change math [basically _ever_, which is what @gbe is saying above]. – GG_Python Oct 27 '16 at 22:44
  • 2
    @GG_Python: I think you've misunderstood where this answer is suggesting doing the `from math import *`. If you do that in a `more_math` module, that module will expose all of the functions and constants from `math` in addition to whatever else you define. That seems like exactly what you're asking for. – Blckknght Oct 27 '16 at 22:55
0

As @user2357112 commented math is a module and not a class. You can create a more_math module simply by creating a more_math.py file with:

from math import *

def add_func(x):
    return sqrt(x)+1

this module can be imported with import more_math or from more_math import add_func.

Jan Kuiken
  • 1,930
  • 17
  • 17
0

math isn't a class, it's an instance of class types.ModuleType. You can verify this with isinstance(math, types.ModuleType) which will return True. Normally you can't define a subclass that inherits from an instance of another class. However, it is possible with a bit of hackery.
(I got the idea from a recipe for inheriting from an instances on the ActiveState website.)

Since it is a hack, one might not want to use it in production code. However I thought you (and other readers) might find it a least interesting, if not useful.

Script more_math.py:

from copy import deepcopy
import math
import sys

def class_from_instance(instance):
    copy = deepcopy(instance.__dict__)

    def __init__(self, *args, **kwargs):
        super(InstanceFactory, self).__init__(*args, **kwargs)
        self.__dict__.update(copy)

    InstanceFactory = type('InstanceFactory',
                           (instance.__class__,),
                           {'__init__': __init__})
    return InstanceFactory

class MoreMathModule(class_from_instance(math)):
    @staticmethod
    def added_func(x):
        return math.sqrt(x)+1

# Replace this module with an instance of the class above.
ref, sys.modules[__name__] = sys.modules[__name__], MoreMathModule('more_math')

if __name__ == '__main__':
    import more_math
    x = 42
    print('more_math.sqrt({}) -> {:.6f}'.format(x, more_math.sqrt(x)))
    print('more_math.added_func({}) -> {:.6f}'.format(x, more_math.added_func(x)))

Output:

more_math.sqrt(42) -> 6.480741
more_math.added_func(42) -> 7.480741
martineau
  • 119,623
  • 25
  • 170
  • 301