From: Klaus Neuner on
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

From: Bruno Desthuilliers on
Klaus Neuner a �crit :
> 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:]

A file extension is not necessarily 3 chars long.

> apply_func(func, file)
>
> Can something of this kind be done in Python?

The simplest (and canonical) solution is to use a dict:

def handle_txt(path):
# code here

def handle_py(path):
# code here

etc...

def handle_default(path):
# for anything else


handlers = {
".txt" : handle_txt,
".py" : handle_py,
# etc
}


import os

def handle_file(path):
dummy, ext = os.path.splitext(path)
handler = handlers.get(ext, handle_default)
return handler(path)

HTH
From: Klaus Neuner on
>
> 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).


From: Dave Angel on
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 perhaps were intending to use the file extension , rather than the
last three characters of the name. If so, consider os.path.splitext().
And you shouldn't shadow the builtin *file* type with a variable of the
same name.

More directly to your question, best suggestion is to build a (const)
dictionary:

apply_func = { "xyz":xyz, "abc":abc }

which maps the strings to functions. This line can be at outer scope,
as long as it follows all the appropriate function definitions. Notice
that the individual functions need not be in the same module, if you use
a fully qualified name in the dictionary. And of course, there's no
necessity of naming the function exactly the same as the extension. So
you could implement the functions in another module 'implem", and use
the following:

import implem
apply_func = { "xyz":implem.process_xyz_files,
"abc":implem.process_abc_files }

Now, you use it by something like:
dummy, func_ext = os.path.splitext(my_filename)
apply_func(func_ext, my_filename)

(all code untested)

DaveA

From: Wojciech Muła on
Klaus Neuner <klausneuner72(a)googlemail.com> wrote:

> > 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.

Use dictionary mantained by runtime:

def handle(extensions):
funname = "handle_" + extension
return globals()[funname]

handle('txt') # => function handle_txt

w.