1

I am creating a simple package called pyma, available on pypi.

I offer a way to calculate an exponential moving average over N day with a function called NDayEMA(n, data). (in fact, it's a class called NDayEMA, with a function called compute() but it is irrelevant here.)

I am trying to create a dynamically named function at run-time as shortcut for users.

For example:

NDayEMA(30, data) 

and

EMA30(data)

would be the same and

EMA23(data)
EMA1023(data)
EMA12(data)

would also be available.

I understand I will need some reg-ex and processing, which is not required in your answer; I will get it myself! I am searching for how to receive the name of a function provide by the user and create a function with that name without raising error messages.

Here is a PHP equivalent from the Laravel PHP framework.

$user = DB::table('users')->where_email_and_password('example@gmail.com', 'secret');
Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
PyWebDesign
  • 187
  • 1
  • 11

2 Answers2

6

This doesn't exactly answer your question, but I'd recommend against doing what you're asking. You already have a method that takes a number and data as an argument, so turning the number into different method names doesn't seem to be any more convenient than your current method.

Ari
  • 2,311
  • 1
  • 17
  • 17
  • Ok, I understand what you mean. I still find this feature quite elegant for the user. Does it have any real drawback? or just have some bad work/value ratio? What about Laravel uses of dynamically named function, is it bad? – PyWebDesign Jan 05 '14 at 22:10
  • The drawback is that you'd be using a lot of hacky metaprogramming techniques that could slow down your library but without any of the benefit it would sometimes bring. Rails and some other frameworks do fancy things with find_by dynamic methods, but that is a tradeoff they decided to make; they are actually moving away from doing that as much because it generally hurts maintainability, makes documentation lookup harder, and is often slower than other equivalents. – Ari Jan 06 '14 at 03:16
2

I agree with Ari -- what you're trying to do doesn't really bring you any advantages, so probably isn't worth doing.

However, if you absolutely want to, you can abuse module loading/__getattr__ and hack a solution as described in this post.

Basically, if we had a file named foo.py that looked like this:

def hello(n):
    print n

class NDayEMA(object):
    def __init__(self, n, day):
        self.n = n
        self.day = day

Then, you would need to change the contents of foo.py to look like this:

import sys

class Testing(object):
    @staticmethod
    def hello(n):
        print n

    class NDayEMA(object):
        def __init__(self, n, day):
            self.n = n
            self.day = day

    def __getattr__(self, attr):
        if attr.startswith('EMA'):
            n = int(attr[3:])
            return lambda day: self.NDayEMA(n, day)
        else: 
            raise AttributeError

sys.modules[__name__] = Testing()

The __getattr__ method is called whenever you attempt to call an attribute or method which is missing within an object. However, there is no such thing as a __getattr__ function that works for modules. Therefore, what we have to do is transform our module into a class, and then replace the module with the class at the very end.

We can now import foo and do the following:

import foo

foo.hello(3)

a = foo.EMA39('test')
b = foo.EMA1000('test')

print a.n
print b.n

print 'done'
Community
  • 1
  • 1
Michael0x2a
  • 58,192
  • 30
  • 175
  • 224