0

I am attempting to write a program to perform arithmetic mod n, given n. I was wondering if there is any way within Python (preferably 2.7) to dynamically define a function such that its behavior depends on the name used to call it. More concretely, I would like to define a function named "*mod", where * is an integer, that then does arithmetic mod *. Perhaps more clearly, I would like to write one function definition for *mod that defines the functions 2mod, 3mod, 4mod, and so on. Is this possible? I apologize if a similar question has already been asked or if my answer is readily available in documentation; I tried to search for it, but I didn't know exactly how to describe the functionality that I'm looking for, so I may have missed it.

Thanks!

BobbyPin
  • 59
  • 6
  • 2
    Identifiers (including function names) in Python cannot begin with a number. Why do you want to do that instead of making a function that takes the number as an argument? – BrenBarn Jul 10 '13 at 08:11
  • 1
    In this particular case there's no reason why you might not want to use the ``%`` operator directly. – Markus Unterwaditzer Jul 10 '13 at 08:37

4 Answers4

4

You don't want to do that. Just make a simple function and pass both numbers as arguments:

def mod(x, n):
    return x % n

print mod(5, 2)
# 1
TerryA
  • 58,805
  • 11
  • 114
  • 143
3

Well, if you really, really want to, look at this quick hack. It uses a wrapper class to wrap the module in a class, so you can use __getattr__:

import sys
import functools

def add(a, b):
    return a + b

def sub(a, b):
    return a - b

class Wrapper(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped
    def __getattr__(self, name):
        try:
            # quick hack. Don't try this at home :-)
            f = ''.join(x for x in name if not x.isdigit())
            n = ''.join(x for x in name if x.isdigit())
            return functools.partial(getattr(self.wrapped, f), int(n))
        except:
            return getattr(self.wrapped, name)

sys.modules[__name__] = Wrapper(sys.modules[__name__])

Now, when you call e.g. add10(12) on this module, the result is 22. Note that method names must not start with a number, but you could use names like _add and call the methods like _55add(45) and so on.

But I would follow Haidro advice: You don't want to do that. Just calling the method with two arguments is a lot simpler.

Community
  • 1
  • 1
sloth
  • 99,095
  • 21
  • 171
  • 219
  • This is really clever, especially the trick of modifying the module in `sys.modules` to become an active code item! As noted in your link, this requires that the magic be `import`ed, so that it winds up in a module so that the `sys.modules` trick can do its thing. I wouldn't use it, but it really does illustrate Python Power! :-) – torek Jul 10 '13 at 08:38
1

Using globals, lambda:

for i in range(2, 5):
    globals()['mod{}'.format(i)] = lambda x, n=i: x % n

assert mod2(4) == 0
assert mod2(3) == 1
assert mod3(2) == 2
assert mod3(1) == 1
assert mod4(1) == 1
assert mod4(2) == 2
assert mod4(3) == 3
assert mod4(9) == 1
falsetru
  • 357,413
  • 63
  • 732
  • 636
0

You could achieve this by generating the functions as a string, and then exec this string to get the function in the current namespace. Something like:

n = 2
s = 'def mod%i(x):' % n
s += '    return x %% %i' % n
exec s

This would define the function mod2(x)

falsetru
  • 357,413
  • 63
  • 732
  • 636
Ludo
  • 813
  • 1
  • 9
  • 21