Go Back   Rhinocerus > Newsgroup > Newsgroup comp.lang.python

Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old 02-08-2010, 09:57 AM
Klaus Neuner
Guest
 
Posts: n/a
Default use strings to call functions

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

Reply With Quote
Alt Today
Advertising
 
and become member of Rhinocerus
Standard Sponsored Links

  #2 (permalink)  
Old 02-08-2010, 10:11 AM
Bruno Desthuilliers
Guest
 
Posts: n/a
Default Re: use strings to call functions

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
Reply With Quote
  #3 (permalink)  
Old 02-08-2010, 10:26 AM
Klaus Neuner
Guest
 
Posts: n/a
Default Re: use strings to call functions

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


Reply With Quote
  #4 (permalink)  
Old 02-08-2010, 10:30 AM
Dave Angel
Guest
 
Posts: n/a
Default Re: use strings to call functions

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

Reply With Quote
  #5 (permalink)  
Old 02-08-2010, 10:37 AM
Wojciech Mu³a
Guest
 
Posts: n/a
Default Re: use strings to call functions

Klaus Neuner <klausneuner72@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.
Reply With Quote
  #6 (permalink)  
Old 02-08-2010, 10:50 AM
Tim Golden
Guest
 
Posts: n/a
Default Re: use strings to call functions

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
Reply With Quote
  #7 (permalink)  
Old 02-08-2010, 10:59 AM
Jean-Michel Pichavant
Guest
 
Posts: n/a
Default Re: use strings to call functions

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
Reply With Quote
  #8 (permalink)  
Old 02-08-2010, 11:03 AM
Stefan Behnel
Guest
 
Posts: n/a
Default Re: use strings to call functions

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
Reply With Quote
  #9 (permalink)  
Old 02-08-2010, 11:08 AM
Steve Holden
Guest
 
Posts: n/a
Default Re: use strings to call functions

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/
Reply With Quote
  #10 (permalink)  
Old 02-08-2010, 11:08 AM
Steve Holden
Guest
 
Posts: n/a
Default Re: use strings to call functions

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/

Reply With Quote
  #11 (permalink)  
Old 02-08-2010, 02:00 PM
Gerard Flanagan
Guest
 
Posts: n/a
Default Re: use strings to call functions

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

Reply With Quote
  #12 (permalink)  
Old 02-08-2010, 06:28 PM
OdarR
Guest
 
Posts: n/a
Default Re: use strings to call functions

On 8 fév, 11:57, Klaus Neuner <klausneune...@googlemail.com> 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?



and with eval(), did you try ?

import sys

def functext():
print "texte"

def funcdoc():
print "doc"

def funcabc():
print "abc"


if __name__ == "__main__":
#replace filename with suitable value
filename = sys.argv[1].split('.')[1]
try:
eval('func' + filename + '()')
except:
print 'error'

Reply With Quote
  #13 (permalink)  
Old 02-08-2010, 06:47 PM
Gary Herron
Guest
 
Posts: n/a
Default Re: use strings to call functions

OdarR wrote:
> On 8 fév, 11:57, Klaus Neuner <klausneune...@googlemail.com> 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?
>>


I may have missed a bit of this thread -- so I have to ask: Has anyone
mentioned using getattr yet? It's a way of looking up *any* attribute
using a string to specify the name. Like this for your particular example:

class Functions: # This could be a module instead of a class
def xyz(...):
...
def abc(...):
...
... and so on ...


ext = os.path.splitext(file) # Parses out the extension
fn = getattr(Functions, ext) # Lookup the correct function
fn(...) # and call it

Gary Herron


Reply With Quote
  #14 (permalink)  
Old 02-08-2010, 08:28 PM
Aahz
Guest
 
Posts: n/a
Default Re: use strings to call functions

In article <0efe23a6-b16d-4f92-8bc0-12d056bf599d@z26g2000yqm.googlegroups.com>,
OdarR <olivier.darge@gmail.com> wrote:
>
>and with eval(), did you try ?


WARNING: eval() is almost always the wrong answer to any question
--
Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/

import antigravity
Reply With Quote
  #15 (permalink)  
Old 02-08-2010, 08:39 PM
OdarR
Guest
 
Posts: n/a
Default Re: use strings to call functions

On 8 fév, 22:28, a...@pythoncraft.com (Aahz) wrote:
> In article <0efe23a6-b16d-4f92-8bc0-12d056bf5...@z26g2000yqm.googlegroups..com>,
>
> OdarR *<olivier.da...@gmail.com> wrote:
>
> >and with eval(), did you try ?

>
> WARNING: eval() is almost always the wrong answer to any question


warning : it works !
another question ?


> --
> Aahz (a...@pythoncraft.com) * * * * * <*> * * * *http://www.pythoncraft.com/
>
> import antigravity


Reply With Quote
 
Reply

Popular Tags in the Forum
functions, strings

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Los Angeles Locksmith Install deadbolts knob sets Locks Re-key locks1-877-364-5264 lifeine Newsgroup comp.lang.ruby 0 10-12-2009 01:15 AM
Seeking computer-programming job (Sunnyvale, CA) Robert Maas Newsgroup comp.lang.java.programmer 1430 07-13-2009 09:16 PM
Re: Call Execute usage/behavior on Macros Terjeson, Mark Newsgroup comp.soft-sys.sas 1 11-17-2008 02:01 PM
Re: Call Execute usage/behavior on Macros Mary Newsgroup comp.soft-sys.sas 0 11-14-2008 09:41 PM
Re: On "Call Execute" and "Resolve": Just Curious on a Friday toby dunn Newsgroup comp.soft-sys.sas 0 10-15-2005 06:46 PM



All times are GMT. The time now is 04:29 PM.


Copyright ©2009

LinkBacks Enabled by vBSEO 3.3.0 RC2 © 2009, Crawlability, Inc.