通过“无”作为函数参数(其中参数是函数)

发布于 2024-09-20 00:04:29 字数 1792 浏览 5 评论 0原文

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

代码:

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 有点蹩脚,因为例如如果 sanity_access 返回 True,lambda: None 就会被执行,并打印输出将会是:

DEBUG:sf.core.sanity:access('/home/nomemory', 0)==True
DEBUG:sf.core.sanity:exec: <lambda>

所以日志中不会很清楚执行了什么函数。日志将仅包含 。是否有一个默认函数不执行任何操作并且可以作为参数传递?这是返回 lambda 内执行的第一个函数的名称的方法吗?

或者如果“无”作为参数发送,则不记录“exec”的方法?

函数的 none / do-nothing 等价物是什么?

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 不起作用?

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_check function.

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_func gets executed, else the false_func gets executed.

1) lambda: None is a little lame , because for example if the sanity_access returns True, lambda: None gets executed, and the output printed will be:

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 ?

Or a way not to log that "exec" if 'nothing' is sent as a paramter ?

What's the none / do-nothing equivalent for functions ?

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: pass instead of lambda: None not working ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

旧人哭 2024-09-27 00:04:29

所有没有任何作用的 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)

但是您确实使事情变得过于复杂了。

What's with all the lambdas that serve no purpose? Well, maybe optional arguments will help you a bit:

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 really overcomplicating things.

爱你是孤单的心事 2024-09-27 00:04:29

更新

我通常会删除这篇文章,因为 THC4k 看透了所有的复杂性并正确地重写了你的函数。然而,在不同的上下文中,K 组合器技巧可能会派上用场,所以我将保留它。


没有内置函数可以完成您想要的 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()

,如果这只是一次性的,那么你可以这样做

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 中。

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.


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

 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,

foo(call_back1, K_combinator(None, 'name_for_logging'))

as for your second statement, only expressions are allowed in lambda. pass is a statement. Hence, lambda: pass fails.

You can slightly simplify your call to sanity check by removing the lambda around the first argument.

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 boolfunc wasn't doing anything because sanity_check wasn't adding any arguments to the call. Might as well just call instead of wrapping it in a lambda.

新一帅帅 2024-09-27 00:04:29

您可能需要重新考虑这一点。

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

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

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.

如果没有你 2024-09-27 00:04:29
>>> 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
>>> 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
梦与时光遇 2024-09-27 00:04:29

实际上,您想要的是一个不执行任何操作的函数,但有一个对日志有用的 __name__ 。 lambda 函数正在做正是您想要的事情,但是 execfunc.__name__ 给出的是""。尝试以下其中一项:

def nothing_func():
    return
def ThisAppearsInTheLog():
    return

您还可以在函数上添加自己的属性:

def log_nothing():
       return
log_nothing.log_info = "nothing interesting"

然后将 execfunc.__name__ 更改为 getattr(execfunc,'log_info', '')

Actually, what you want is a function which does nothing, but has a __name__ which is useful to the log. The lambda function is doing exactly what you want, but execfunc.__name__ is giving "<lambda>". Try one of these:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文