Python lambdas,用于

Python lambdas,用于,python,python-3.x,lambda,duck-typing,Python,Python 3.x,Lambda,Duck Typing,通常在Python中,使用duck类型很有帮助,例如,假设我有一个对象spam,它的prompt属性控制应用程序中的提示文本。通常,我会这样说: spam.prompt = "fixed" 对于固定提示。但是,也可以实现动态提示-虽然由于duck类型,我无法将spam类更改为使用函数作为提示,但由于用户使用的spam对象调用str,我可以创建动态提示,如下所示: class MyPrompt: def __str__( self ): return eggs.get_u

通常在Python中,使用duck类型很有帮助,例如,假设我有一个对象
spam
,它的
prompt
属性控制应用程序中的提示文本。通常,我会这样说:

spam.prompt = "fixed"
对于固定提示。但是,也可以实现动态提示-虽然由于duck类型,我无法将spam类更改为使用函数作为
提示
,但由于用户使用的spam对象调用
str
,我可以创建动态提示,如下所示:

class MyPrompt:
    def __str__( self ):
        return eggs.get_user_name() + ">"

spam.prompt = MyPrompt()
可以扩展此主体以使任何属性成为动态的,例如:

class MyEnabled:
    def __bool__( self ):
        return eggs.is_logged_in()

spam.enabled = MyEnabled()
但有时,将此内联会更简洁,即

spam.prompt = lambda: eggs.get_user_name() + ">"
spam.enabled = eggs.is_logged_in
这些当然不起作用,因为lambda的
\uuuu str\uuuu
或函数的
\uuuuu bool\uuuu
都不会返回调用的实际值


我觉得解决这个问题的方法应该很简单,是我遗漏了什么,还是每次都需要将函数包装到类中?

您需要的是计算属性。Python对计算属性的支持是,它有一个通用实现

现在的诀窍是,如文档所述(参见上面的链接),描述符只有在它们是类属性时才起作用。您的代码片段不完整,因为它不包含
spam
对象的定义,但我假设它是一个类实例,因此您不能只执行
spam.something=property(…)
——因为描述符协议不会在
property()
上调用

这里的解决方案是传统的“策略”设计模式:使用属性(或自定义描述符,但如果只有两个这样的属性,则内置的
属性
将很好地工作),它将委托给“策略”功能:

def default_prompt_strategy(obj):
    return "fixed"

def default_enabled_strategy(obj):
    return False


class Spam(object):
    def __init__(self, prompt_strategy=default_prompt_strategy, enabled_strategy=default_enabled_strategy):
        self.prompt = prompt_strategy
        self.enabled = enabled_strategy

    @property
    def prompt(self):
        return self._prompt_strategy(self)

    @prompt.setter
    def prompt(self, value):
        if not callable(value):
            raise TypeError("PromptStrategy must be a callable")
        self._prompt_strategy = value

    @property
    def enabled(self):
        return self._enabled_strategy(self)

    @enabled.setter
    def enabled(self, value):
        if not callable(value):
            raise TypeError("EnabledtStrategy must be a callable")
        self._enabled_strategy = value



class Eggs(object):
    def is_logged_in(self):
        return True

    def get_user_name(self):
        return "DeadParrot"

eggs = Eggs()

spam = Spam(enabled_strategy=lambda obj: eggs.is_logged_in())   
spam.prompt = lambda obj: "{}>".format(eggs.get_user_name()) 

跳过lambda,只使用
spam.prompt=eggs.get\u user\u name()+“>”
-在方法的末尾放一对括号来实际调用它:
spam.enabled=eggs.is\u logged\u in()
您可以查看
@属性的装饰器。@Heike或更一般的描述符协议(属性
类型只是描述符的一个通用应用程序)。@Heike还注意到,描述符仅在类属性时调用,而不是在实例属性时调用,因此这里的解决方案需要的不仅仅是使用描述符;-)@Brunodesshuilliers我理解描述符是类属性。我的意思是OP可以修改
垃圾邮件的类定义,并使用
@property
垃圾邮件创建setter/getter.prompt
spam.enabled
。我认为在
垃圾邮件中应该是
self.\u init\uu
策略=prompt\u策略
等等。,不是
self.prompt=prompt\u strategy
@Heike nope,它不应该-属性是绑定描述符(它们实现
\uuu set\uuuuu(self,obj,value)
),因此通过调用属性的setter,分配给
self.prompt
etc的工作与预期一样。