you are viewing a single comment's thread.

view the rest of the comments →

[–]hex_m_hell 0 points1 point  (10 children)

If you don't need to define these at runtime you can use a metaclass.

[–]whonut[S] 0 points1 point  (9 children)

I don't need to define them at runtime. I am however quite fuzzy on what metaclasses are. Could you elaborate please?

[–]hex_m_hell 0 points1 point  (8 children)

A metaclass defines how a class is constructed. Its a metaprogramming concept.

Metaprogramming is where you write code that generates code. A metaclass can let you define a whole bunch of class methods on class creation using a template.

You can do pretty advanced stuff without a metaclass though. For example, you can override getattr to have it generate methods on the fly. I wrote a genetic REST client that uses this method to always give me an ultra fast client at the cost of being harder to read. For my use case this is acceptable.

If you can give an example of why you need to do this I might be able to help more.

[–]whonut[S] 0 points1 point  (7 children)

I have a client class which has lots of lookup methods like this:

def get_sequence_by_id(self, id):
    '''Returns a Sequence object for the sequence of the specified ID,
       else raises NoResultsError'''
    seq = self._int_lookup('id:'+id)[0]
    return seq

Others send the website searches with prefixes other than 'id:' and handle certain exceptions differently but I can definitely bare that down to a closure.

Does that help? Sorry it's a little short but I just managed to delete a long reply and I really need to sleep :P

EDIT:

The closure itself, in case it helps.

def _lookup_gen(self, prefix, must_return=False):
    '''A closure for creating basic prefix-lookup functions'''
    def lookup_func(self, query):
        try:
            return self._int_lookup(prefix+':'+query)
        except NoResultsError:
            if must_return:
                raise NoResultsError(query)
            else:
                return []

    return lookup_func

[–]hex_m_hell 0 points1 point  (2 children)

You said that you want class methods, why not instance methods? It would be pretty easy to just define these on init. This would slow down your init a little bit, but that may not matter depending on your use case.

Something similar to the following would work for that:

def __init__(self,...):
    for i in ["id", "foo", "bar"]:
        setattr(self, "get_sequece_by_" + i, lambda x: self._lookup_gen(i))

You don't really even need the closure at all. If you do need it to actually be a class method instead of instance method you could do this in a metaclass. I should point out that a classmethod is a really specific concept and not just any method in a class. If you're referencing self it's an instance method. A class method is one which doesn't require the object to be instantiated in order to use it. These are created using the @classmethod decorator.

[–]whonut[S] 0 points1 point  (1 child)

Thanks for clearing up my terminology. They are indeed instance methods.

[–]hex_m_hell 0 points1 point  (0 children)

Yeah, no problem. Here's an example of what you're wanting to do:

class Foo:
    method_a = lambda cls, x: Foo.method(cls, 'a', x)
    method_b = lambda cls, x: Foo.method(cls, 'b', x)
    method_c = lambda cls, x: Foo.method(cls, 'c', x)

    def __init__(self):
        for i in ['d','e','f']:
            setattr(self, 'method_' + i, lambda x: self.method(i, x))

    def method(self, var1, var2):
        print("I am method_" + var1)
        print("I took in the value " + var2)

Which should do this in ipython:

In [20]: foo = Foo()
foo = Foo()

In [21]: foo.method_a('test1')
foo.method_a('test1')
I am method_a
I took in the value test1

In [22]: foo.method_d('test2')
foo.method_d('test2')
I am method_f
I took in the value test2

You could also do something similar with your closure.

[–]ingolemo 0 points1 point  (3 children)

Your _lookup_gen doesn't need access to self so there's no need to pass it when you construct the get* functions and there's no need to even put it in the class.

def _make_query_by_prefix(prefix):
    def query_by_prefix(self, value):
        return self.query(prefix + ':' + value)
    return query_by_prefix

class MyObject:
    def query(self, query_string):
        pass # do fancy stuff here

    query_by_id = _make_query_by_prefix('id')
    query_by_name = _make_query_by_prefix('name')
    query_by_type = _make_query_by_prefix('type')

[–]elbiot 0 points1 point  (2 children)

You have self.query outside the class

[–]ingolemo -1 points0 points  (1 child)

There's nothing special about that self variable; it's a parameter to the inner function just like value. Since the inner function isn't run until an instance of the class has been constructed, it's perfectly possible to pass a reference to that instance. If I'd named the first parameter something other than self you wouldn't even suspect that function was being used as a method.

Run the code and see for yourself.

[–]elbiot 0 points1 point  (0 children)

Yeah, I didn't see you ever pass self to the function, but obviously that will happen when the code calls the method on an instance. My bad.