user46646
user46646

Reputation: 159401

Help--Function Pointers in Python

My idea of program:

I have a dictionary:

options = { 'string' : select_fun(function pointer),
'float' : select_fun(function pointer),
'double' : select_fun(function pointer)
}

whatever type comes single function select_fun(function pointer) gets called. Inside select_fun(function pointer),I will have diff functions for float, double and so on.

Depending on function pointers, specified function will get called.

I don't know whether my programming knowledge is good or bad, still I need help.

Upvotes: 3

Views: 26819

Answers (5)

jfs
jfs

Reputation: 414585

Functions are the first-class objects in Python therefore you can pass them as arguments to other functions as you would with any other object such as string or an integer.

There is no single-precision floating point type in Python. Python's float corresponds to C's double.

def process(anobject):
    if isinstance(anobject, basestring):
       # anobject is a string
       fun = process_string
    elif isinstance(anobject, (float, int, long, complex)):
       # anobject is a number
       fun = process_number
    else:
       raise TypeError("expected string or number but received: '%s'" % (
           type(anobject),))
    return fun(anobject)

There is functools.singledispatch that allows to create a generic function:

from functools import singledispatch
from numbers import Number

@singledispatch
def process(anobject): # default implementation
    raise TypeError("'%s' type is not supported" % type(anobject))

@process.register(str)
def _(anobject):
   # handle strings here
   return process_string(anobject)

process.register(Number)(process_number) # use existing function for numbers

On Python 2, similar functionality is available as pkgutil.simplegeneric().

Here's a couple of code example of using generic functions:

Upvotes: 4

chakrit
chakrit

Reputation: 61518

You can use the type() built-in function to detect the type of the function.

Say, if you want to check if a certain name hold a string data, you could do this:

if type(this_is_string) == type('some random string'):
    # this_is_string is indeed a string

So in your case, you could do it like this:

options = { 'some string'     : string_function,
            (float)(123.456)  : float_function,
            (int)(123)        : int_function
          }

def call_option(arg):

    # loop through the dictionary
    for (k, v) in options.iteritems():

        # if found matching type...
        if type(k) == type(arg):

            # call the matching function
            func = option[k]
            func(arg)

Then you can use it like this:

call_option('123')       # string_function gets called
call_option(123.456)     # float_function gets called
call_option(123)         # int_function gets called

I don't have a python interpreter nearby and I don't program in Python much so there may be some errors, but you should get the idea.


EDIT: As per @Adam's suggestion, there are built-in type constants that you can check against directly, so a better approach would be:

from types import *

options = { types.StringType  : string_function,
            types.FloatType   : float_function,
            types.IntType     : int_function,
            types.LongType    : long_function
          }

def call_option(arg):
    for (k, v) in options.iteritems():

        # check if arg is of type k
        if type(arg) == k:

            # call the matching function
            func  = options[k]
            func(arg)

And since the key itself is comparable to the value of the type() function, you can just do this:

def call_option(arg):
    func = options[type(arg)]
    func(arg)

Which is more elegant :-) save for some error-checking.


EDIT: And for ctypes support, after some fiddling around, I've found that ctypes.[type_name_here] is actually implented as classes. So this method still works, you just need to use the ctypes.c_xxx type classes.

options = { ctypes.c_long     : c_long_processor,
            ctypes.c_ulong    : c_unsigned_long_processor,
            types.StringType  : python_string_procssor
          }

call_option = lambda x: options[type(x)](x)

Upvotes: 6

rob
rob

Reputation: 37644

Looking at your example, it seems to me some C procedure, directly translated to Python.

For this reason, I think there could be some design issue, because usually, in Python, you do not care about type of an object, but only about the messages you can send to it.

Of course, there are plenty of exceptions to this approach, but still in this case I would try encapsulating in some polymorphism; eg.

class StringSomething(object):
  data = None
  def data_function(self):
     string_function_pointer(self.data)

class FloatSomething(object):
  data = None
  def data_function(self):
     float_function_pointer(self.data)

etc.

Again, all of this under the assumption you are translating from a procedural language to python; if it is not the case, then discard my answer :-)

Upvotes: 4

gimel
gimel

Reputation: 86422

Maybe you want to call the same select_fun() every time, with a different argument. If that is what you mean, you need a different dictionary:

>>> options = {'string' : str, 'float' : float, 'double' : float }
>>> options
{'double': <type 'float'>, 'float': <type 'float'>, 'string': <type 'str'>}
>>> def call_option(val, func):
...     return func(val)
... 
>>> call_option('555',options['float'])
555.0
>>> 

Upvotes: 3

Adam Rosenfield
Adam Rosenfield

Reputation: 400454

Could you be more specific on what you're trying to do? You don't have to do anything special to get function pointers in Python -- you can pass around functions like regular objects:

def plus_1(x):
    return x + 1

def minus_1(x):
    return x - 1

func_map = {'+' : plus_1, '-' : minus_1}

func_map['+'](3)  # returns plus_1(3) ==> 4
func_map['-'](3)  # returns minus_1(3) ==> 2

Upvotes: 20

Related Questions