2009-05-10 8 views
1

J'ai un petit script python que j'utilise tous les jours ...... il lit essentiellement un fichier et pour chaque ligne j'applique des fonctions de chaînes différentes comme strip(), replace(), etc. ... je suis constamment en train d'éditer le fichier et de commenter pour changer les fonctions. Selon le fichier que j'ai affaire, j'utilise différentes fonctions. Par exemple j'ai un fichier où pour chaque ligne, je dois utiliser line.replace ('', '') et line.strip() ...Définir des fonctions dynamiques à une chaîne

Quelle est la meilleure façon de faire tout cela dans le cadre de mon script? Donc, je peux juste dire attribuer des numéros à chaque fonction et simplement dire appliquer les fonctions 1 et 4 pour chaque ligne.

Répondre

2

d'abord, de nombreuses fonctions de chaîne - y compris la bande et remplacer - sont deprecated. La réponse suivante utilise des méthodes de chaîne à la place. (Au lieu de string.strip(" Hello "), j'utilise l'équivalent de " Hello ".strip().)

Voici un code qui simplifiera le travail pour vous. Le code suivant suppose que, quelles que soient les méthodes que vous appelez sur votre chaîne, cette méthode renvoie une autre chaîne.

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 

La classe existe O afin que vos noms de méthode très abrégée ne pollue pas votre espace de noms. Lorsque vous souhaitez ajouter plusieurs méthodes de chaîne, ajoutez-les au O dans le même format que ceux donnés.

La fonction process_line est l'endroit où toutes les choses intéressantes se produisent. Tout d'abord, voici une description du format de l'argument:

  • Le premier argument est la chaîne à traiter.
  • Les arguments restants doivent être donnés par paires.
    • Le premier argument de la paire est une méthode de chaîne. Utilisez les noms de méthodes raccourcies ici.
    • Le deuxième argument de la paire est une liste représentant les arguments de cette méthode de chaîne particulière.

La fonction process_line renvoie la chaîne qui émerge après avoir effectué toutes ces opérations.

Voici un exemple de code montrant comment utiliser le code ci-dessus dans vos propres scripts. J'ai séparé les arguments de process_line sur plusieurs lignes pour montrer le regroupement des arguments. Bien sûr, si vous ne faites que pirater et utiliser ce code dans des scripts quotidiens, vous pouvez compresser tous les arguments sur une seule ligne; cela le rend un peu plus facile à lire.

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 

Bien sûr, si vous vouliez très précisément utiliser des chiffres, vous pouvez nommer vos fonctions O.f1, O.f2, O.f3 ... mais je suppose que ce n'était pas l'esprit de votre question.

2

Il est possible de cartographier les opérations de chaîne aux numéros:

>>> 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' 
>>> 

Mais peut-être des descriptions de chaîne des opérations seront plus lisibles.

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

Note: Au lieu d'utiliser le module string, vous pouvez utiliser le type str pour le même effet.

>>> ops={1:str.split, 2:str.replace} 
2

Si vous insistez sur les chiffres, vous ne pouvez pas faire beaucoup mieux qu'un dict (comme Gimel indique) ou une liste de fonctions (avec des indices zéro et plus). Avec les noms, cependant, vous n'avez pas nécessairement besoin d'une structure de données auxiliaire (telle que la dictée suggérée par gimel), puisque vous pouvez simplement utiliser getattr pour récupérer la méthode à appeler depuis l'objet lui-même ou son type. .: par exemple

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 

0

pour mapper les noms (ou numéros) à différentes opérations de chaîne, je ferais quelque chose comme

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 

que vous utilisez comme celui-ci

for line in process(afile, ['strip', 'removespaces']): 
    ... 
Questions connexes