Python 传递“无”作为函数参数(其中参数是一个函数)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3730831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing 'None' as function parameter (where parameter is a function)
提问by Andrei Ciobanu
I am writing a small app that has to perform some 'sanity checks' before entering execution. (eg. of a sanity check: test if a certain path is readable / writable / exists)
我正在编写一个小应用程序,在进入执行之前必须执行一些“健全性检查”。(例如,健全性检查:测试某个路径是否可读/可写/存在)
The code:
编码:
import logging
import os
import shutil
import sys
from paths import PATH
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('sf.core.sanity')
def sanity_access(path, mode):
ret = os.access(path, mode)
logfunc = log.debug if ret else log.warning
loginfo = (os.access.__name__, path, mode, ret)
logfunc('%s(\'%s\', %s)==%s' % loginfo)
return ret
def sanity_check(bool_func, true_func, false_func):
ret = bool_func()
(logfunc, execfunc) = (log.debug, true_func) if ret else \
(log.warning, false_func)
logfunc('exec: %s', execfunc.__name__)
execfunc()
def sanity_checks():
sanity_check(lambda: sanity_access(PATH['userhome'], os.F_OK), \
lambda: None, sys.exit)
My question is related to the sanity_checkfunction.
我的问题与sanity_check功能有关。
This function takes 3 parameters (bool_func, true_func, false_func). If the bool_func(which is the test function, returning a boolean value) fails, true_funcgets executed, else the false_funcgets executed.
此函数需要 3 个参数 ( bool_func, true_func, false_func)。如果bool_func(这是测试函数,返回一个布尔值)失败,则true_func执行,否则false_func执行。
1)lambda: Noneis a little lame , because for example if the sanity_access returns True, lambda: Nonegets executed, and the output printed will be:
1)lambda: None有点蹩脚,因为例如,如果 sanity_access 返回 True,则会lambda: None被执行,并且打印的输出将是:
DEBUG:sf.core.sanity:access('/home/nomemory', 0)==True
DEBUG:sf.core.sanity:exec: <lambda>
So it won't be very clear in the logs what function got executed. The log will only contain <lambda>. Is there a default function that does nothing and can be passed as a parameter ? Is it a way to return the name of the first function that is being executed inside a lambda ?
所以在日志中不会很清楚执行了什么函数。日志将只包含<lambda>. 是否有一个什么都不做并且可以作为参数传递的默认函数?是否可以返回在 lambda 中执行的第一个函数的名称?
Or a way not to log that "exec" if 'nothing' is sent as a paramter ?
或者如果“没有”作为参数发送时不记录“exec”的方法?
What's the none / do-nothing equivalent for functions ?
函数的 none / do-nothing 等价物是什么?
sanity_check(lambda: sanity_access(PATH['userhome'], os.F_OK), \
<do nothing, but show something more useful than <lambda>>, sys.exit)
Additional question, why is lambda: passinstead of lambda: Nonenot working ?
附加问题,为什么lambda: pass不是lambda: None不工作?
采纳答案by Jochen Ritzel
What's with all the lambdas that serve no purpose? Well, maybe optional arguments will help you a bit:
所有无用的 lambda 表达式是怎么回事?好吧,也许可选参数会对您有所帮助:
def sanity_check( test, name='undefined', ontrue=None, onfalse=None ):
if test:
log.debug(name)
if ontrue is not None:
ontrue()
else:
log.warn( name )
if onfalse is not None:
onfalse()
def sanity_checks():
sanity_check(sanity_access(PATH['userhome'], os.F_OK), 'test home',
onfalse=sys.exit)
But you are reallyovercomplicating things.
但是你真的把事情复杂化了。
回答by aaronasterling
update
更新
I would normally delete this post because THC4k saw through all the complexity and rewrote your function correctly. However in a different context, the K combinator trick might come in handy, so I'll leave it up.
我通常会删除这篇文章,因为 THC4k 看穿了所有的复杂性并正确地重写了你的函数。然而,在不同的上下文中,K 组合器技巧可能会派上用场,所以我将把它搁置一旁。
There is no builtin that does what you want AFIK. I believe that you want the K combinator(the link came up on another question) which can be encoded as
没有内置可以做你想要的 AFIK。我相信你想要K 组合器(链接出现在另一个问题上),它可以编码为
def K_combinator(x, name):
def f():
return x
f.__name__ = name
return f
none_function = K_combinator(None, 'none_function')
print none_function()
of course if this is just a one off then you could just do
当然,如果这只是一次关闭,那么你可以这样做
def none_function():
return None
But then you don't get to say "K combinator". Another advantage of the 'K_combinator' approach is that you can pass it to functions, for example,
但是你不能说“K组合器”。'K_combinator' 方法的另一个优点是您可以将其传递给函数,例如,
foo(call_back1, K_combinator(None, 'name_for_logging'))
as for your second statement, only expressions are allowed in lambda. passis a statement. Hence, lambda: passfails.
至于你的第二个语句,在lambda. pass是一个声明。因此,lambda: pass失败。
You can slightly simplify your call to sanity check by removing the lambda around the first argument.
您可以通过删除第一个参数周围的 lambda 来稍微简化对健全性检查的调用。
def sanity_check(b, true_func, false_func):
if b:
logfunc = log.debug
execfunc = true_func
else:
logfunc = log.warning
execfunc = false_func
logfunc('exec: %s', execfunc.__name__)
execfunc()
def sanity_checks():
sanity_check(sanity_access(PATH['userhome'], os.F_OK),
K_combinator(None, 'none_func'), sys.exit)
This is more readable (largely from expanding the ternary operator into an if). the boolfuncwasn't doing anything because sanity_checkwasn't adding any arguments to the call. Might as well just call instead of wrapping it in a lambda.
这更具可读性(主要是将三元运算符扩展为 if)。在boolfunc没有做任何事情,因为sanity_check不添加任何参数调用。也可能只是调用而不是将其包装在 lambda 中。
回答by pyfunc
>>> import dis
>>> f = lambda: None
>>> dis.dis(f)
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
>>> g = lambda: Pass
>>>
>>>
>>> dis.dis(g)
1 0 LOAD_GLOBAL 0 (Pass)
3 RETURN_VALUE
>>> g = lambda: pass
File "<stdin>", line 1
g = lambda: pass
^
SyntaxError: invalid syntax
回答by S.Lott
You might want to rethink this.
您可能需要重新考虑这一点。
class SanityCheck( object ):
def __call__( self ):
if self.check():
logger.debug(...)
self.ok()
else:
logger.warning(...)
self.not_ok()
def check( self ):
return True
def ok( self ):
pass
def not_ok( self ):
sys.exit(1)
class PathSanityCheck(SanityCheck):
path = "/path/to/resource"
def check( self ):
return os.access( path, os.F_OK )
class AnotherPathSanityCheck(SanityCheck):
path = "/another/path"
def startup():
checks = ( PathSanityCheck(), AnotherPathSanityCheck() )
for c in checks:
c()
Callable objects can simplify your life.
可调用对象可以简化您的生活。
回答by greggo
Actually, what you want is a function which does nothing, but has a __name__which is useful to the log. The lambda function is doingexactly what you want, but execfunc.__name__is giving "<lambda>". Try one of these:
实际上,你想要的是一个什么都不做,但有一个__name__对日志有用的函数。lambda 函数正在做你想要的,但execfunc.__name__给"<lambda>". 尝试以下方法之一:
def nothing_func():
return
def ThisAppearsInTheLog():
return
You can also put your own attributes on functions:
您还可以将自己的属性放在函数上:
def log_nothing():
return
log_nothing.log_info = "nothing interesting"
Then change execfunc.__name__to getattr(execfunc,'log_info', '')
然后execfunc.__name__改为 getattr(execfunc,'log_info', '')

