我正在编写一个小应用程序,必须在执行之前执行一些“健全性检查”。 (例如,完整性检查:测试某条路径是否可读/可存在)
代码:
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
功能有关。
此函数有3个参数(bool_func
,true_func
,false_func
)。如果bool_func
(这是测试函数,返回一个布尔值)失败,true_func
将被执行,否则false_func
将被执行。
1) lambda: None
有点蹩脚,因为例如如果sanity_access返回True,lambda: None
会被执行,打印输出将是:
DEBUG:sf.core.sanity:access('/home/nomemory', 0)==True
DEBUG:sf.core.sanity:exec: <lambda>
因此在日志中不太清楚执行了哪些函数。该日志仅包含<lambda>
。是否有一个默认函数什么都不做,可以作为参数传递?它是一种返回lambda中正在执行的第一个函数的名称的方法吗?
或者,如果“没有”作为参数发送,则不记录“exec”的方法?
什么是无功/无效功能?
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
无效?
答案 0 :(得分:8)
我通常会删除这篇文章因为THC4k看到了所有的复杂性并正确地重写了你的功能。然而在不同的背景下,K组合器技巧可能会派上用场,所以我会把它留下来。
没有内置可以做你想要的AFIK。我相信你想要K combinator(链接出现在另一个问题上),可以编码为
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_combinator”方法的另一个优点是您可以将其传递给函数,例如
foo(call_back1, K_combinator(None, 'name_for_logging'))
至于你的第二个陈述,lambda
中只允许使用表达式。 pass
是一个声明。因此,lambda: pass
失败。
通过删除第一个参数周围的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中。
答案 1 :(得分:8)
所有没有用途的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)
但你真的过于复杂的事情。
答案 2 :(得分:3)
你可能想重新考虑一下。
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()
可调用对象可以简化您的生活。
答案 3 :(得分:1)
>>> 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
答案 4 :(得分:1)
实际上,你想要的是一个什么也不做的函数,但是它有一个对日志有用的__name__
。 lambda函数正在做你想要的,但是execfunc.__name__
正在给"<lambda>"
。尝试其中之一:
def nothing_func():
return
def ThisAppearsInTheLog():
return
您还可以将自己的属性放在函数上:
def log_nothing():
return
log_nothing.log_info = "nothing interesting"
然后将execfunc.__name__
更改为getattr(execfunc,'log_info', '')