Помощь - Указатели на функции в Python - PullRequest
3 голосов
/ 31 декабря 2008

Моя идея программы:

У меня есть словарь:

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

независимо от типа, одна функция вызывается select_fun(function pointer). Внутри select_fun(function pointer) у меня будут функции diff для float, double и т. Д.

В зависимости от указателей на функции, указанная функция будет вызываться.

Я не знаю, хорошие ли у меня знания по программированию, но мне все равно нужна помощь.

Ответы [ 5 ]

20 голосов
/ 31 декабря 2008

Не могли бы вы более конкретно рассказать, что вы пытаетесь сделать? Вам не нужно делать ничего особенного, чтобы получить указатели на функции в Python - вы можете передавать функции как обычные объекты:

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
6 голосов
/ 31 декабря 2008

Вы можете использовать встроенную функцию type() для определения типа функции.

Скажем, если вы хотите проверить, содержит ли определенное имя строковые данные, вы можете сделать это:

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

Так что в вашем случае вы можете сделать это так:

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)

Тогда вы можете использовать это так:

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

У меня нет интерпретатора Python поблизости, и я не очень много программирую на Python, поэтому могут быть некоторые ошибки, но вы должны понять это.


РЕДАКТИРОВАТЬ: В соответствии с предложением @ Адама, есть встроенные константы типа, которые вы можете проверить напрямую, поэтому лучший подход будет:

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)

А поскольку сам ключ сопоставим со значением функции type (), вы можете просто сделать это:

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

Что более элегантно :-) за исключением некоторой проверки ошибок.


EDIT: А после поддержки ctypes я обнаружил, что ctypes. [Type_name_here] фактически используется как классы. Так что этот метод все еще работает, вам просто нужно использовать классы типов ctypes.c_xxx.

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)
4 голосов
/ 31 декабря 2008

Глядя на ваш пример, мне кажется, что какая-то процедура на C прямо переведена на Python.

По этой причине, я думаю, могут быть некоторые проблемы с дизайном, потому что обычно в Python вам не важен тип объекта, а только сообщения, которые вы можете ему отправить.

Конечно, есть множество исключений из этого подхода, но все же в этом случае я бы попытался инкапсулировать в некоторый полиморфизм; например.

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)

и т.д.

Опять же, все это в предположении, что вы переводите с процедурного языка на python; если это не так, то отбросьте мой ответ: -)

4 голосов
/ 31 декабря 2008

Функции являются первоклассными объектами в Python, поэтому вы можете передавать их в качестве аргументов другим функциям, как если бы вы использовали любой другой объект, например строку или целое число.

В Python нет типа с плавающей запятой одинарной точности. float Python соответствует C 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)

Существует functools.singledispatch, который позволяет создать универсальную функцию:

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

В Python 2 аналогичная функциональность доступна как pkgutil.simplegeneric().

Вот несколько примеров кода использования универсальных функций:

3 голосов
/ 31 декабря 2008

Может быть, вы хотите каждый раз вызывать один и тот же select_fun() с другим аргументом. Если вы это имеете в виду, вам нужен другой словарь:

>>> 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
>>> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...