Writing common getattr () parameters and filling depending on the name attr

I am trying to create a general Python class for a Pub / Sub application, where the model definition defines three methods for each type of X resource that we have:

new_X changed_X deleted_X 

I diverted the code to one method that takes parameters about the type and action:

 def _pub_wrapper(self, verb, obj_type, id_list): ids = [str(i) for i in id_list] self._pub(ids, '{0}.{1}'.format(verb, obj_type.lower())) 

But this requires me to manually record each of the specific methods, albeit on a single line:

 def new_resources(self, id_list): self._pub_wrapper('new', 'resources', id_list) def changed_resources(self, id_list): self._pub_wrapper('changed', 'resources', id_list) 

I am trying to find a better template to distract it even more, so I do not need to manually write these one-line methods. Since the method names are mapped to the verb / type in my pub / subsystem, I was thinking of something like (pseudocode):

 def __getattr__(self, item): if name in [whitelist of approved methods]: return ??? Some sort of partially defined version of self._pub_wrapper, with verb and obj_type filled in from parsing item ??? raise AttributeError() 

This general method is ideal for calls like:

 publisher.new_resources([]) publisher.new_items([]) publisher.new_banks([]) 

without me, you need to put together each of these methods ... is there an elegant way to do this? I thought I could do this with the decorator near __getattr__ , but am not quite sure how to return the styled method. I tried the following, but the self._pub_wrapper() method was never called.

 def define_verb_and_type(*args, **kwargs): def wrap(func): def wrapped_func(*args): return func(*args, verb=kwargs['verb'], obj_type=kwargs['obj_type']) return wrapped_func return wrap def __getattr__(self, item): if item in ['new_resources', 'changed_resources', 'deleted_resources']: verb = item.split('_')[0] obj_type = item.split('_')[-1] return define_verb_and_type(self._pub_wrapper, verb, obj_type) raise AttributeError 
+5
source share
1 answer

I'm not quite sure what your code actually does, but from a simplified point of view, I get that you want to catch common calls, for example publisher.new_resources( [] ) , which should automatically generate a call to _pub_wrapper(new, resources, []) or one below _pub(...) .

Here is a working example:

 class Test: def _pub_wrapper(self, verb, obj_type, id_list): print " Called _pub_wrapper(" , verb, ", ", obj_type, ", ", id_list, ")" ids = [str(i) for i in id_list] self._pub(ids, '{0}.{1}'.format(verb, obj_type.lower())) def _pub(self, ids, something): print " Called _pub( ", self, ", ", ids, ", ", something, ")" def __getattr__(self, item): verb = item.split('_')[0] obj_type = item.split('_')[-1] if verb in ['new', 'changed', 'deleted'] and \ obj_type in ['resources', 'items', 'banks']: def wrapper(*args, **kwargs): print "Within wrapper: verb=", verb, ", obj_type=", obj_type, ", args=", args, ", kwargs=", kwargs print "Within wrapper: ", verb, ", ", obj_type, ", ", args return self._pub_wrapper(verb, obj_type, args[0]) return wrapper raise AttributeError """ def __getattr__(self, item): if item in ['new_resources', 'changed_resources', 'deleted_resources', 'changed_banks']: verb = item.split('_')[0] obj_type = item.split('_')[-1] print verb, " vs ", obj_type def wrapper(*args): print "Within wrapper: ", verb, ", ", obj_type, ", ", args[0] return self._pub_wrapper(verb, obj_type, args[0]) return wrapper raise AttributeError """ def fake_new_resources(self, id_list): self._pub_wrapper('new', 'resources', id_list) t = Test() print "Faking it... " t.fake_new_resources([]) print "New tries" t.new_resources([]) t.changed_banks([]) t.deleted_items(["hi", "bye"], 4, your=23, mine=42) 

Output generated at startup:

 Faking it... Called _pub_wrapper( new , resources , [] ) Called _pub( <__main__.Test instance at 0x1c366c> , [] , new.resources ) New tries Within wrapper: verb= new , obj_type= resources , args= ([],) , kwargs= {} Called _pub_wrapper( new , resources , [] ) Called _pub( <__main__.Test instance at 0x1c366c> , [] , new.resources ) Within wrapper: verb= changed , obj_type= banks , args= ([],) , kwargs= {} Called _pub_wrapper( changed , banks , [] ) Called _pub( <__main__.Test instance at 0x1c366c> , [] , changed.banks ) Within wrapper: verb= deleted , obj_type= items , args= (['hi', 'bye'], 4) , kwargs= {'your': 23, 'mine': 42} Called _pub_wrapper( deleted , items , ['hi', 'bye'] ) Called _pub( <__main__.Test instance at 0x1c366c> , ['hi', 'bye'] , deleted.items ) 

Code Comments

You were pretty close, but had some problems with your define_verb_and_type() and calling this. I simplified this section a bit and added loads of debugging print statements . Currently, I only code online, so I don't have a good debugger, so I use print for debugging.

One change I made was that instead of testing for item in [ ... list ...] I split the item before and tested the actual verb and obj_type . You might want to lose the test for obj_type . Testing of the working version is saved in the list in the comments block.

One question related to your code is in _pub_wrapper where you use id_list . I do not quite understand what you are trying to achieve here, and it seems to be expecting that this will either be an instance variable, or in any way see the additions / deletions to this list.

I also added a new example to display named and unnamed arguments. The first is present in the kwargs parameter, and later in the args parameter.

In other words, I don’t quite understand if I understood your question correctly and what code you want us to view. But the code presented in my answer here provides a general approach to the call you want, and hopefully helps you advance in your coding project.

+3
source

All Articles