54 votes

Comment faire fonctionner une fonction anonyme en Python sans la baptiser?

Est-il possible de mettre une fonction dans une structure de données sans lui donner un nom avec def ?

 # This is the behaviour I want. Prints "hi".
def myprint(msg):
    print msg
f_list = [ myprint ]
f_list[0]('hi')
# The word "myprint" is never used again. Why litter the namespace with it?
 

Le corps d'une fonction lambda est sévèrement limité, je ne peux donc pas les utiliser.

Edit: Pour référence, cela ressemble plus au code de la vie réelle où j'ai rencontré le problème.

 def handle_message( msg ):
    print msg
def handle_warning( msg ):
    global num_warnings, num_fatals
    num_warnings += 1
    if ( is_fatal( msg ) ):
        num_fatals += 1
handlers = (
    ( re.compile( '^<\w+> (.*)' ), handle_message ),
    ( re.compile( '^\*{3} (.*)' ), handle_warning ),
)
# There are really 10 or so handlers, of similar length.
# The regexps are uncomfortably separated from the handler bodies,
# and the code is unnecessarily long.

for line in open( "log" ):
    for ( regex, handler ) in handlers:
        m = regex.search( line )
        if ( m ): handler( m.group(1) )
 

39voto

Gareth Rees Points 31350

Ceci est basé sur la bonne réponse d'Udi .

Je pense que la difficulté de créer des fonctions anonymes est un peu déroutant. Ce que vous voulez vraiment faire est de garder le code associé ensemble et de le rendre propre. Je pense donc que les décorateurs peuvent travailler pour vous.

 import re

# List of pairs (regexp, handler)
handlers = []

def handler_for(regexp):
    """Declare a function as handler for a regular expression."""
    def gethandler(f):
        handlers.append((re.compile(regexp), f))
        return f
    return gethandler

@handler_for(r'^<\w+> (.*)')
def handle_message(msg):
    print msg

@handler_for(r'^\*{3} (.*)')
def handle_warning(msg):
    global num_warnings, num_fatals
    num_warnings += 1
    if is_fatal(msg):
        num_fatals += 1
 

16voto

Udi Points 6298

Un moyen plus sec pour résoudre votre problème actuel:

 def message(msg):
    print msg
message.re = '^<\w+> (.*)'

def warning(msg):
    global num_warnings, num_fatals
    num_warnings += 1
    if ( is_fatal( msg ) ):
        num_fatals += 1
warning.re = '^\*{3} (.*)'

handlers = [(re.compile(x.re), x) for x in [
        message,
        warning,
        foo,
        bar,
        baz,
    ]]
 

14voto

Udi Points 6298

Poursuivant l' approche propre de Gareth avec une solution modulaire autonome:

 import re

# in util.py
class GenericLogProcessor(object):

    def __init__(self):
      self.handlers = [] # List of pairs (regexp, handler)

    def register(self, regexp):
        """Declare a function as handler for a regular expression."""
        def gethandler(f):
            self.handlers.append((re.compile(regexp), f))
            return f
        return gethandler

    def process(self, file):
        """Process a file line by line and execute all handlers by registered regular expressions"""
        for line in file:
            for regex, handler in self.handlers:
                m = regex.search(line)
                if (m):
                  handler(m.group(1))      

# in log_processor.py
log_processor = GenericLogProcessor()

@log_processor.register(r'^<\w+> (.*)')
def handle_message(msg):
    print msg

@log_processor.register(r'^\*{3} (.*)')
def handle_warning(msg):
    global num_warnings, num_fatals
    num_warnings += 1
    if is_fatal(msg):
        num_fatals += 1

# in your code
with open("1.log") as f:
  log_processor.process(f)
 

13voto

Udi Points 6298

Si vous voulez conserver un espace de noms propre, utilisez del:

 def myprint(msg):
    print msg
f_list = [ myprint ]
del myprint
f_list[0]('hi')
 

9voto

robert Points 10493

Comme vous l'avez dit, cela ne peut être fait. Mais vous pouvez vous en approcher.

 def create_printer():
  def myprint(x):
    print x
  return myprint

x = create_printer()
 

myprint est effectivement anonyme ici, car la portée de la variable dans laquelle elle a été créée n'est plus accessible à l'appelant. (Voir les fermetures en Python .)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X