如何在Python中创build一个匿名函数而不用洗礼呢?

是否有可能把一个函数在数据结构中,而没有先用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? 

lambda函数的主体是严格限制的,所以我不能使用它们。

编辑:作为参考,这更像是我遇到问题的现实生活中的代码。

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

这是基于Udi的很好的答案 。

我觉得创build匿名函数的难度有点儿大了。 你真正想要做的是保持相关的代码在一起,并使代码整洁。 所以我认为装饰者可能会为你工作。

 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 

更好地干的方式来解决你的实际问题:

 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, ]] 

如果你想保持一个干净的命名空间,使用del:

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

继续采用模块化自包含解决scheme的Gareth清洁方法:

 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) 

正如你所说,这是不能做到的。 但你可以近似它。

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

myprint在这里是有效匿名的,因为创build它的variables作用域不再可以被调用者访问。 (请参阅Python中的闭包 。)

如果担心污染名称空间,请在另一个函数内部创build函数。 那么你只是“污染”了create_functions函数的本地名称空间,而不是外部名称空间。

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

你不应该这样做,因为eval是邪恶的,但你可以在运行时使用FunctionType编译函数代码并compile

 >>> def f(msg): print msg >>> type(f) <type 'function'> >>> help(type(f)) ... class function(object) | function(code, globals[, name[, argdefs[, closure]]]) | | Create a function object from a code object and a dictionary. | The optional name string overrides the name from the code object. | The optional argdefs tuple specifies the default argument values. | The optional closure tuple supplies the bindings for free variables. ... >>> help(compile) Help on built-in function compile in module __builtin__: compile(...) compile(source, filename, mode[, flags[, dont_inherit]]) -> code object Compile the source string (a Python module, statement or expression) into a code object that can be executed by the exec statement or eval(). The filename will be used for run-time error messages. The mode must be 'exec' to compile a module, 'single' to compile a single (interactive) statement, or 'eval' to compile an expression. The flags argument, if present, controls which future statements influence the compilation of the code. The dont_inherit argument, if non-zero, stops the compilation inheriting the effects of any future statements in effect in the code calling compile; if absent or zero these statements do influence the compilation, in addition to any features explicitly specified. 

正如所有的lambda是唯一的方法,但你不得不考虑lambda限制,但如何避免它们 – 例如,你可以使用列表,字典,理解等来做你想要的:

 funcs = [lambda x,y: x+y, lambda x,y: xy, lambda x,y: x*y, lambda x: x] funcs[0](1,2) >>> 3 funcs[1](funcs[0](1,2),funcs[0](2,2)) >>> -1 [func(x,y) for x,y in zip(xrange(10),xrange(10,20)) for func in funcs] 

编辑打印(尝试查看pprint模块 )和控制stream程:

 add = True (funcs[0] if add else funcs[1])(1,2) >>> 3 from pprint import pprint printMsg = lambda isWarning, msg: pprint('WARNING: ' + msg) if isWarning else pprint('MSG:' + msg) 

Python真的,真的不想这样做。 它不仅没有任何方法来定义多行匿名函数,但函数定义不返回函数,所以即使这是语法上有效的…

 mylist.sort(key=def _(v): try: return -v except: return None) 

…它仍然无法工作。 (虽然我猜如果它在语法上是有效的,他们会使函数定义返回函数,所以它工作。)

所以你可以编写你自己的函数来从一个string(使用exec当然),并传入一个三重引用的string函数。 这在句法上有点难看,但起作用:

 def function(text, cache={}): # strip everything before the first paren in case it's "def foo(...):" if not text.startswith("("): text = text[text.index("("):] # keep a cache so we don't recompile the same func twice if text in cache: return cache[text] exec "def func" + text func.__name__ = "<anonymous>" cache[text] = func return func # never executed; forces func to be local (a tiny bit more speed) func = None 

用法:

 mylist.sort(key=function("""(v): try: return -v except: return None""")) 

做一个匿名函数的唯一方法是lambda ,正如你所知,它们只能包含一个expression式。

你可以用相同的名字创build一些函数,所以至less你不必为每个函数都考虑新的名字。

拥有真正的匿名函数会很棒,但是Python的语法不能轻易支持它们。

就我个人而言,我只是将它命名为使用它,而不是担心“挂在”。 通过稍后重新定义或使用del将命名空间从名称空间中删除的build议,您将获得的唯一一件事情是,如果有人稍后出现并移动一些代码而无需gro what自己的东西,则可能会出现混淆或错误这样做。

你可以使用exec

 def define(arglist, body): g = {} exec("def anonfunc({0}):\n{1}".format(arglist, "\n".join(" {0}".format(line) for line in body.splitlines())), g) return g["anonfunc"] f_list = [define("msg", "print(msg)")] f_list[0]('hi') 

像你提到的,唯一的select是使用lambdaexpression式。 没有这个,这是不可能的。 这是python的工作方式。

如果你的函数足够复杂,不适合lambda函数,那么为了可读性,最好在正常的块中定义它。