Как эмулировать указатель на функцию в стиле C с помощью функций Python - PullRequest
0 голосов
/ 22 декабря 2018

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

def process_record(header, needle, pattern):
    sequence = needle
    for idx in [m.start() for m in re.finditer(pattern, needle)]:
        offset = idx + len(pattern)
        sequence = sequence[:idx] + needle[idx:offset].lower() + sequence[offset:]
    sys.stdout.write('%s\n%s\n' % (header, sequence))

Это прекрасно работает, например:

>>> process_record('>foo', 'ABCDEF', 'BCD')
>foo
AbcdEF

То, что я хотел бы сделать, это обобщить это, передать в качестве параметра строковую функцию (в данном случае lower, но это может быть любая функция примитивного типа или класса).Что-то вроде:

def process_record(header, needle, pattern, fn):
    sequence = needle
    for idx in [m.start() for m in re.finditer(pattern, needle)]:
        offset = idx + len(pattern)
        sequence = sequence[:idx] + needle[idx:offset].fn() + sequence[offset:]
    sys.stdout.write('%s\n%s\n' % (header, sequence))

Это не работает (вот почему я задаю вопрос), но, надеюсь, это демонстрирует идею, чтобы попытаться обобщить то, что функция делает так, чтобы она была читабельной.

Один из вариантов, который я полагаю, - написать вспомогательную функцию, которая обертывает stringInstance.lower() и передает копии строк, что неэффективно и неуклюже.Я надеюсь, что есть более элегантный подход, о котором знают эксперты Python.

С C, например, я бы передал указатель на функцию, которую я хочу запустить в качестве параметра, на process_record() и запустил быуказатель на функцию непосредственно на интересующую переменную.

Каков синтаксис для того же самого при использовании строковых примитивных функций (или похожих на примитивных или других классах) в Python?

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Ваш пример немного сложен, поэтому я бы разбил его на два разных вопроса:

1) Как вы можете предоставить функции в качестве аргументов?

Функции являются объектами, как все остальное, иможет быть передан как ожидалось, например:

 def apply(val, func):
    # e.g. ("X", string.lower) -> "x"
    #      ("X", lambda x: x * 2) -> "XX"
     return func(val)

В вашем примере вы могли бы сделать

def process_record(..., func):
    ...
       sequence = ... func(needle[idx:offset]) ...
    ...

Альтернативный метод, который я бы не рекомендовал, был бы что-то вроде

def apply_by_name(val, method_name):
    # e.g. ("X", "lower") -> "x"
    return getattr(val, method_name)()

2) Как применить эффект к каждому совпадению регулярного выражения в строке?

Для этого я бы порекомендовал встроенную функцию 'sub', которая также принимает строкикак функции.

>>> re.sub('[aeiou]', '!', 'the quick brown fox')
'th! q!!ck br!wn f!x'

def foo(match):
   v = match.group()
   if v == 'i': return '!!!!!!!'
   elif v in 'eo': return v * 2
   else: return v.upper()

>>> re.sub('[aeiou]', foo, 'the quick brown fox')
'thee qU!!!!!!!ck broown foox'

Надеюсь, это поможет!

0 голосов
/ 22 декабря 2018

В общем, используйте этот подход:

def call_fn(arg, fn):
    return fn(arg)

call_fn('FOO', str.lower) # 'foo'

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

...