【问题标题】:empty function object in pythonpython中的空函数对象
【发布时间】:2014-02-18 00:20:11
【问题描述】:

我听说 python 函数是对象,类似于列表或字典等。但是,用函数执行此类操作的类似方式是什么?

# Assigning empty list to 'a'
a = list()

# Assigning empty function to 'a'
a = lambda: pass
# ???

你会怎么做?此外,这是必要的还是适当的? 这是我想用它来获得更好的上下文的意义:

我有一个QListWidget 用于选择与字典中的键关联的项目。这本字典中的值也是字典,其中包含项目的某些属性,我可以添加这些属性。这些某些属性存储为键,并通过调用不同的函数来初始化或更新其中的值。因此,我在窗口中存储了一个变量,当按下按钮告诉该脚本要更新哪个属性时,该变量会更新。

如您所见,我想存储函数以根据情况使用正确的函数映射到数据。

# Get selection from the list
name = selected_item
# Initialize an empty function
f = lambda: pass
# Use property that is being added now, which was updated by the specific button that was pushed
property_list = items[name][self.property_currently_being_added]
if self.property_currently_being_added == "prop1":
    f = make_property1()
elif self.property_currently_being_added == "prop2":
    f = make_property2()
elif self.property_currently_being_added == "prop3":
    f = make_property3()
elif self.property_currently_being_added == "prop4":
    f = make_property4()

# map the certain function to the data which was retrieved earlier
added_property = map(f, data)
property_list.append(added_property)

【问题讨论】:

  • 为什么你认为你需要一个“空”函数?您当然可以做到这一点,正如您所写的那样,但您为什么需要这样做?您的函数在尚未正确定义时是否会被调用?
  • 我同意亨利的观点,似乎没有什么大理由要这样做。在您的示例中,您可以简单地执行else: raise ValueError 等。如果self.property_currently_being_added == None 或what-have-you,您似乎不希望此功能继续。
  • 另外,没有理由必须是 lambda。你可以很容易地写def f(): pass,效果相同。使用lambda 的唯一原因是(a)您不想给函数命名(此处不适用;您立即将其分配给f); (b) 你需要在一个表达式中定义它,而不是一个语句(这里不适用;你直接在赋值语句中使用它);或者 (c) 你正在和一位讨厌 Python 并且宁愿教授 Scheme 的教授上课(大概不适用于这里)。
  • 你可以做一个身份函数。但是你真的用 lambda 找错了树。
  • 只是为了好玩,如果你真的想要一个真正空函数对象,试试这个:c = types.CodeType(0, 0, 0, 0, 0, b'', (), (), (), '<main>', 'f', 0, b''),然后f = types.FunctionType(c, {})。当然,这个函数所做的只是在被调用时引发一个SystemError……但是你期望一个空函数有多大用处? :)

标签: python function design-patterns


【解决方案1】:

首先,这不起作用的原因:

a = lamdba: pass

... 是lambda 只允许一个表达式,并定义了一个函数来返回表达式的值。由于pass 是语句,而不是表达式,因此这是非法的。

但是,这很好用:

a = lambda: None

在 Python 中,没有return 语句的函数总是返回None。所以,这些是等价的:

def a(): return None
def a(): pass

但是,我不明白你为什么要把它写成一个 lambda 和一个赋值; def 更短,更易读,并为您提供了一个具有好名字的自省函数对象(a 而不是<lambda>),等等。使用lambda 的唯一原因是当您不想给函数命名时,或者当您需要在表达式中定义函数时。显然,这些都不正确,因为您在赋值语句中直接使用了lambda。所以,只需使用def


同时,这在某种意义上是一个“空函数”,或者至少是尽可能空的(正如你可以看到的,例如,调用dis.dis(a),它仍然需要两个字节码才能做任何事情,但最终会掉下来并返回None),但这对您的情况没有用。你不想要一个“空函数”。如果你尝试将a 传递给map,你只会得到TypeError,因为你试图用一个参数调用一个没有参数的函数。 (因为这就是 map 所做的。)

您可能想要的是一个 identity 函数,它只是按原样返回其参数。像这样:

def a(x): return x

但我不确定这就是你想要的。在这种情况下,您想按原样附加data 吗?或者您是否想做一些不同的事情,比如提前返回,或者引发异常,或者不附加任何内容,或者......?


最后,我完全不明白你为什么想要一个函数。如果您没有要映射的内容,为什么不直接打电话给map?你有一个非常好的else 子句,它已经捕捉到了这种情况(如果你想做的是提前返回或加注,那么特别方便......)。或者,如果您愿意,您可以从f = None 开始,然后使用if f: 来决定是否映射。或者,如果你真的想要:

added_property = [f(element) if f else element for element in data]

……或……

added_property = map(f, data) if f else data

最后一点,您可能需要一个dict,而不是一遍又一遍地重复同一件事的长if/elif链:

propfuncs = {'prop1': make_property1(),
             'prop2': make_property2(),
             'prop3': make_property3(),
             'prop4': make_property4()}

然后,所有繁琐的东西都变成了这两行:

f = propfuncs.get(self.property_currently_being_added)
added_property = map(f, data) if f else data

当然,更好的设计可能是将所有这些 make_propertyN 函数替换为您称为 make_property(1)make_property('prop1') 的单个函数……但如果没有看到它们实际做了什么,我无法确定那个。

【讨论】:

  • 谢谢@abarnert 这是一个很好的答案。很好地调用propfuncs 的想法,我认为这可能会有所帮助。 make_propertyN() 函数实际上只是初始化其他嵌套字典的函数,但我认为这对于我的具体情况来说是一个很好的方法,希望它也能帮助沿着这条路线的其他人。
【解决方案2】:

为了完整起见,由于标题是“python中的空函数对象”,更一般的情况是带有任意数量参数的空函数对象,所以你可以在any中使用它 回调。就是这个:

callback = lambda *_, **__: None

解释在这里:http://echochamber.me/viewtopic.php?t=64825

【讨论】:

    【解决方案3】:

    我很惊讶地发现你甚至可以做到……

    def a(): "This is a test"
    
    a()
    

    【讨论】:

      【解决方案4】:

      这感觉就像你正在寻找一个 Nothing 函子,我猜如果你了解 Monads,你甚至不需要一个空函数,因为灵感 PyMonad 有一个很好的 Nothing实现,我通常喜欢创建自己的,但这是一个很好的起点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-07
        • 1970-01-01
        • 2017-06-09
        • 2016-05-24
        • 1970-01-01
        • 2023-03-28
        • 2014-09-02
        相关资源
        最近更新 更多