From: Tim Golden on 8 Feb 2010 06:50 On 08/02/2010 11:26, Klaus Neuner wrote: >> >> A file extension is not necessarily 3 chars long. > > No, of course not. But it is, if I choose to use only (self-made) file > endings that are 3 chars long. Anyway, it was just an example. > >> handlers = { >> ".txt" : handle_txt, >> ".py" : handle_py, >> # etc >> } >> > > That is exactly what I would like to avoid: Having to map the function > 'handle_txt' to '.txt'. Firstly, because I don't want to repeat > anything and secondly, because I will one day add a new function and > forget to add its name to the dictionary. (This is not severe if there > is only one dictionary for mapping functions, but it will make life a > lot harder, if a lot of mappings of this kind are used.) > > What I want is calling the string directly. In Prolog, I would use > something like: > > get_file_ending(File, Ending), > Predicate =.. [Ending, File], > call(Predicate). You basically need a getattr lookup. If you're prepared to instantiate a class or to import a handlers module then you can just look up against that: <handlers.py> def handle_py (stuff): "print handling py" def handle_default (stuff): "print handling default" </handlers.py> <main> import handlers ext = "py" handler = getattr (handlers, "handle_" + ext, handlers.handle_default) handler ("stuff") </main> You can do the equivalent by having a Handlers class with the appropriate methods (handle_py, etc.) and which you then instantiate. If you want to keep everything in one module, you should be able to achieve the same effect by looking the module up in sys.modules and then proceeding as above: <whatever.py> import sys def handle_py (stuff): print "handling py" def handle_default (stuff): print "handling default" ext = "py" me = sys.modules[__name__] handler = getattr (me, "handle_" + ext, me.handle_default) handler ("blah") </whatever.py> (All untested...) TJG
From: Jean-Michel Pichavant on 8 Feb 2010 06:59 Klaus Neuner wrote: > Hello, > > I am writing a program that analyzes files of different formats. I > would like to use a function for each format. Obviously, functions can > be mapped to file formats. E.g. like this: > > if file.endswith('xyz'): > xyz(file) > elif file.endswith('abc'): > abc(file) > > ... > > Yet, I would prefer to do something of the following kind: > > func = file[-3:] > apply_func(func, file) > > Can something of this kind be done in Python? > > Klaus > > You won't need anything else than defining the proper function to support the extension with the following code: import os class Handlers: class NoHandler(Exception): pass @staticmethod def txt(fileName): print 'I am processing a txt file' @staticmethod def tar(fileName): print 'I am processing a tar file' @classmethod def default(cls, fileName): raise cls.NoHandler("I don't know how to handle %s " % fileName) for fileName in ['/tmp/test.txt', '/tmp/sdfsd.sfds']: _, extension = os.path.splitext(fileName) func = getattr(Handlers, extension.replace('.', ''), Handlers.default) try: func(fileName) except Handlers.NoHandler, exc: print exc JM
From: Stefan Behnel on 8 Feb 2010 07:03 Klaus Neuner, 08.02.2010 11:57: > I am writing a program that analyzes files of different formats. I > would like to use a function for each format. Obviously, functions can > be mapped to file formats. E.g. like this: > > if file.endswith('xyz'): > xyz(file) > elif file.endswith('abc'): > abc(file) > > ... > > Yet, I would prefer to do something of the following kind: > > func = file[-3:] > apply_func(func, file) > > Can something of this kind be done in Python? Others have already pointed you to the approach of using a dict, or a module/class namespace with functions/methods to do this. Either of the latter two would be my favourite, depending on the complexity of the handlers. A class is more suitable as a container for short, highly correlated handlers, whereas a module makes more sense for handlers that do rather different things, or that are longer than a single function. A mixture of the two, e.g. a module of classes, where an entire class is used to implement a complete handler over several methods (potentially including some inheritance hierarchy between handlers that share functionality) might also be a solution. Note that objects can be callable in Python (special method __call__), you can exploit that here. What you are implementing here is commonly called a dispatch mechanism, BTW. There are several ways to do that, also within in Python. A web search should reveal some more. Stefan
From: Steve Holden on 8 Feb 2010 07:08 Klaus Neuner wrote: >> A file extension is not necessarily 3 chars long. > > No, of course not. But it is, if I choose to use only (self-made) file > endings that are 3 chars long. Anyway, it was just an example. > >> handlers = { >> ".txt" : handle_txt, >> ".py" : handle_py, >> # etc >> } >> > > That is exactly what I would like to avoid: Having to map the function > 'handle_txt' to '.txt'. Firstly, because I don't want to repeat > anything and secondly, because I will one day add a new function and > forget to add its name to the dictionary. (This is not severe if there > is only one dictionary for mapping functions, but it will make life a > lot harder, if a lot of mappings of this kind are used.) > > What I want is calling the string directly. In Prolog, I would use > something like: > > get_file_ending(File, Ending), > Predicate =.. [Ending, File], > call(Predicate). > > -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/ Holden Web LLC http://www.holdenweb.com/ UPCOMING EVENTS: http://holdenweb.eventbrite.com/
From: Gerard Flanagan on 8 Feb 2010 10:00
Klaus Neuner wrote: > Hello, > > I am writing a program that analyzes files of different formats. I > would like to use a function for each format. Obviously, functions can > be mapped to file formats. E.g. like this: > > if file.endswith('xyz'): > xyz(file) > elif file.endswith('abc'): > abc(file) > > ... > > Yet, I would prefer to do something of the following kind: > > func = file[-3:] > apply_func(func, file) > As mentioned, a dictionary dispatch will do what you want, but you can also use the self-registering technique outlined here: http://effbot.org/zone/metaclass-plugins.htm [Fredrik Lundh] (For Plugin, read Handler in this case.) One idea might be to have Handler classes such as: class TextHandler(HandlerType): extensions = ['', 'txt', 'rst'] def run(self, *args, **kw): .... do stuff then the __init__ of HandlerType's metaclass: def __init__(cls, name, bases, attrs): for ext in attrs.get('extensions', []): registry[ext] = cls then use like: registry['txt']().run() If you don't need state, you could perhaps make 'run' a staticmethod and store it rather than the class, eg. registry[ext] = cls.run and then just: registry['txt']() hth G.F ------------------------------------------------------------------------ registry = {} class HandlerType(object): class __metaclass__(type): def __init__(cls, name, bases, attrs): for ext in attrs.get('extensions', []): registry[ext] = cls class TextHandler(HandlerType): extensions = ['', 'txt'] print registry |