将“None”作为函数参数传递(其中参数是函数)

2024-05-13 18:02:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在写一个小应用程序,必须执行一些'健全检查'才进入执行。(例如,健全性检查:测试某个路径是否可读/写/存在)

代码:

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_functrue_funcfalse_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中正在执行的第一个函数的名称的方法吗?

或者如果“nothing”作为参数发送,则不记录该“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不起作用?


Tags: lambda函数importlogfalsetrueaccessos
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()

可调用对象可以简化您的生活。

那些毫无用处的羔羊怎么了?好吧,也许可选参数可以帮你一点:

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)

但你真的是太复杂了。

更新

我通常会删除这篇文章,因为THC4k看穿了所有的复杂性,并正确地重写了您的函数。不过,在另一种情况下,K组合技巧可能会派上用场,所以我就不提了。


你想要什么就做什么。我相信您需要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包装它。

相关问题 更多 >