将'None'作为函数参数传递(参数为函数)
我正在写一个小应用程序,它在执行之前需要进行一些“合理性检查”。(比如,合理性检查的例子:测试某个路径是否可读、可写或是否存在)
代码如下:
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)
我想问的问题和 sanity_check
函数有关。
这个函数有三个参数(bool_func
、true_func
、false_func
)。如果 bool_func
(这是一个测试函数,会返回一个布尔值)失败了,就会执行 true_func
,否则就执行 false_func
。
1) lambda: None
有点无趣,因为比如说如果合理性检查返回 True,那么 lambda: None
就会被执行,输出的内容会是:
DEBUG:sf.core.sanity:access('/home/nomemory', 0)==True
DEBUG:sf.core.sanity:exec: <lambda>
这样在日志中就不太清楚到底执行了哪个函数。日志里只会显示 <lambda>
。有没有什么默认的函数可以什么都不做,并且可以作为参数传入?有没有办法在 lambda 里返回第一个被执行的函数的名字?
或者有没有办法在传入“什么都不做”的参数时,不记录“执行”的日志?
对于函数来说,什么是“什么都不做”的等价物?
sanity_check(lambda: sanity_access(PATH['userhome'], os.F_OK), \
<do nothing, but show something more useful than <lambda>>, sys.exit)
另外一个问题,为什么 lambda: pass
而不是 lambda: None
不起作用?
5 个回答
你可能需要重新考虑一下这个问题。
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()
可调用对象可以让你的生活更简单。
更新
我本来想删掉这篇帖子,因为THC4k看透了所有复杂的东西,并正确地重写了你的函数。不过在不同的情况下,K组合子这个技巧可能会派上用场,所以我就留着它了。
据我所知,没有内置的功能可以做到你想要的。我觉得你想要的是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()
当然,如果这只是一次性的需求,你可以直接这样做:
def none_function():
return None
但那样你就不能说“K组合子”了。使用'K组合子'的另一个好处是你可以把它传递给函数,比如:
foo(call_back1, K_combinator(None, 'name_for_logging'))
至于你的第二个说法,lambda
中只允许表达式。pass
是一个语句,所以lambda: pass
会失败。
你可以稍微简化一下对sanity check的调用,去掉第一个参数周围的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)
这样更容易理解(主要是把三元运算符展开成if语句)。boolfunc
没有起作用,因为sanity_check
没有给调用添加任何参数。与其把它包裹在lambda中,不如直接调用。
这些没什么用的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)
不过,你真的把事情搞得太复杂了。