Определение динамических функций для строки - PullRequest
1 голос
/ 10 мая 2009

У меня есть небольшой скрипт на python, который я использую каждый день ...... он в основном читает файл, и для каждой строки я в основном применяю различные строковые функции, такие как strip (), replace () и т.д .... Я постоянно редактирую файл и комментирование для изменения функций. В зависимости от файла, с которым я имею дело, я использую разные функции. Например, я получил файл, в котором для каждой строки мне нужно использовать line.replace ('', '') и line.strip () ...

Какой лучший способ сделать все это как часть моего сценария? Так что я могу просто сказать, присваивать номера каждой функции и просто сказать, применять функции 1 и 4 для каждой строки.

Ответы [ 4 ]

2 голосов
/ 10 мая 2009

Если вы настаиваете на числах, вы не можете сделать намного лучше, чем надиктовать (как предполагает Гимел) или список функций (с индексами от нуля и выше). Однако с именами вам не обязательно нужна вспомогательная структура данных (например, предложенный gimel dict), поскольку вы можете просто использовать getattr для извлечения метода, вызываемого из самого объекта или его типа. E.g.:

def all_lines(somefile, methods):
  """Apply a sequence of methods to all lines of some file and yield the results.
  Args:
    somefile: an open file or other iterable yielding lines
    methods: a string that's a whitespace-separated sequence of method names.
        (note that the methods must be callable without arguments beyond the
         str to which they're being applied)
  """
  tobecalled = [getattr(str, name) for name in methods.split()]
  for line in somefile:
    for tocall in tobecalled: line = tocall(line)
    yield line
2 голосов
/ 10 мая 2009

Прежде всего, многие строковые функции, включая удаление и замену, устарели . В следующем ответе используются строковые методы. (Вместо string.strip(" Hello ") я использую эквивалент " Hello ".strip().)

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

class O(object):
    c = str.capitalize
    r = str.replace
    s = str.strip

def process_line(line, *ops):
    i = iter(ops)
    while True:
        try:
            op = i.next()
            args = i.next()
        except StopIteration:
            break
        line = op(line, *args)
    return line

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

Функция process_line - это то, где происходят все интересные вещи. Во-первых, вот описание формата аргумента:

  • Первый аргумент - строка для обработки.
  • Остальные аргументы должны быть заданы парами.
    • Первый аргумент пары - это строковый метод. Используйте сокращенные имена методов здесь.
    • Второй аргумент пары - это список, представляющий аргументы этого конкретного строкового метода.

Функция process_line возвращает строку, которая появляется после выполнения всех этих операций.

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

f = open("parrot_sketch.txt")
for line in f:
    p = process_line(
        line,
        O.r, ["He's resting...", "This is an ex-parrot!"],
        O.c, [],
        O.s, []
    )
    print p

Конечно, если вы очень конкретно хотели использовать цифры, вы могли бы назвать свои функции O.f1, O.f2, O.f3 ... но я предполагаю, что это не дух вашего вопроса.

2 голосов
/ 10 мая 2009

Строковые операции можно отобразить в числа:

>>> import string
>>> ops = {1:string.split, 2:string.replace}
>>> my = "a,b,c"
>>> ops[1](",", my)
[',']
>>> ops[1](my, ",")
['a', 'b', 'c']
>>> ops[2](my, ",", "-")
'a-b-c'
>>> 

Но, возможно, строковые описания операций будут более читабельными.

>>> ops2={"split":string.split, "replace":string.replace}
>>> ops2["split"](my, ",")
['a', 'b', 'c']
>>> 

Примечание: Вместо использования модуля string вы можете использовать тип str для того же эффекта.

>>> ops={1:str.split, 2:str.replace}
0 голосов
/ 10 мая 2009

Чтобы сопоставить имена (или числа) с различными строковыми операциями, я бы сделал что-то вроде

OPERATIONS = dict(
    strip = str.strip,
    lower = str.lower,
    removespaces = lambda s: s.replace(' ', ''),
    maketitle = lamdba s: s.title().center(80, '-'),
    # etc
)

def process(myfile, ops):
    for line in myfile:
        for op in ops:
            line = OPERATIONS[op](line)
        yield line

который вы используете вот так

for line in process(afile, ['strip', 'removespaces']):
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...