【问题标题】:Using an attribute of the current class instance as a default value for method's parameter [duplicate]使用当前类实例的属性作为方法参数的默认值[重复]
【发布时间】:2012-10-23 03:45:52
【问题描述】:

可能重复:
default value of parameter as result of instance method

虽然可以在 python 中为函数参数设置默认值:

def my_function(param_one='default')
    ...

似乎无法访问当前实例(self):

class MyClass(..):

    def my_function(self, param_one=self.one_of_the_vars):
        ...

我的问题:

  • 我无法访问当前实例来设置函数中的默认参数,这是真的吗?
  • 如果不可能:原因是什么?是否可以想象在未来的 python 版本中这将成为可能?

【问题讨论】:

  • 这有点不同,阿什维尼。那篇文章问的是实例方法,这是关于实例属性的。两者都有问题的原因是相同的,是的,但问题肯定是不同的。
  • @Maxwell 但有点相同,因为他试图在默认参数值中使用self.someattribute
  • @Ashwini 当然,但这不是投票作为重复关闭的理由,因为要求它是一个完全重复,涵盖完全相同内容,并且这个问题的答案可以与其他问题的答案一起合并。 “可能合并”的表述中隐含的是,这些合并的问题不应像拇指酸痛一样突出,因为它们不回答问题。
  • @lazyr 它没有投票,是别人投票的。我刚刚添加了评论。
  • 重点是默认参数是在define time设置的,但是self直到runtime才存在。

标签: python function default default-parameters


【解决方案1】:

写成:

def my_function(self, param_one=None): # Or custom sentinel if None is vaild
    if param_one is None:
        param_one = self.one_of_the_vars

而且我认为可以肯定地说这在 Python 中永远不会发生,因为 self 在函数启动之前并不真正存在......(你不能在它自己的定义中引用它 - 比如其他一切)

例如:你不能做d = {'x': 3, 'y': d['x'] * 5}

【讨论】:

  • 这是一个很好的答案。我认为编写一个函数会更有启发性:def my_func(a, foo=a.bar): ... 并显示该函数如何不起作用,因为a 是函数的参数,但foo 的默认值在函数为定义。很高兴看到self 实际上并没有什么特别之处。它只是函数调用中的一个参数,就像其他所有东西一样——(它恰好是一个在你执行 instance.method() 时隐式传递的参数)。
  • 为了完整起见:如果您的one_of_the_vars 恰好是在 SAME 类中定义的常量属性,那么您可以通过def my_function(self, param_one=ONE_OF_THE_CONSTANTS) 在您的方法中简单地引用它。它会起作用的。
【解决方案2】:

参数的默认值在“编译”时评估一次。所以很明显你不能访问self。经典示例是 list 作为默认参数。如果在其中添加元素,则参数的默认值会发生变化!

解决方法是使用另一个默认参数,通常是None,然后检查并更新变量。

【讨论】:

  • 但是使用列表作为默认参数值会导致Least Astonishment
  • 我不知道你想说什么......它遵循规则,但如果你不知道规则,那肯定是一个很大的惊喜
【解决方案3】:

它比你想象的要多得多。考虑默认值是 static(=指向 one 对象的常量引用)并存储在定义中的某处;在方法定义时进行评估;作为的一部分,而不是实例。由于它们是恒定的,它们不能依赖于self

这是一个例子。这是违反直觉的,但实际上非常有意义:

def add(item, s=[]):
    s.append(item)
    print len(s)

add(1)     # 1
add(1)     # 2
add(1, []) # 1
add(1, []) # 1
add(1)     # 3

这将打印1 2 1 1 3

因为它的工作方式与

相同
default_s=[]
def add(item, s=default_s):
    s.append(item)

显然,如果你修改default_s,它会保留这些修改。

有多种解决方法,包括

def add(item, s=None):
    if not s: s = []
    s.append(item)

或者你可以这样做:

def add(self, item, s=None):
    if not s: s = self.makeDefaultS()
    s.append(item)

那么makeDefaultS方法就可以访问self了。

另一种变化:

import types
def add(item, s=lambda self:[]):
    if isinstance(s, types.FunctionType): s = s("example")
    s.append(item)

这里s的默认值是一个工厂函数

您可以结合所有这些技术:

class Foo:
    import types
    def add(self, item, s=Foo.defaultFactory):
        if isinstance(s, types.FunctionType): s = s(self)
        s.append(item)

    def defaultFactory(self):
        """ Can be overridden in a subclass, too!"""
        return []

【讨论】:

  • 我不知道我会在这里使用术语 constants 因为你可以改变对象。但是指出当函数定义时默认值与关键字相关联是有帮助的。
  • 谢谢,是的,我的意思是 static
  • @mgilson 它是一个常量对象引用;如果对象是可变的,它可以被改变,但引用不能被改变。虽然术语 constant 可能会让人感到困惑,但如果您将其视为参考,它是合适的。
  • 我还添加了更多解决方案来获得所需的行为:工厂函数,或将默认值初始化委托给单独的方法。
  • @l4mpi -- 你说它是一个常量 reference 是绝对正确的,但我认为这个词对于可能会问这样一个问题的人来说仍然令人困惑.
【解决方案4】:

您在这里做出了多个错误的假设 - 首先,函数属于一个类而不是一个实例,这意味着所涉及的实际函数对于一个类的任何两个实例都是相同的。其次,默认参数在编译时评估并且是常量(如常量对象引用 - 如果参数是可变对象,您可以更改它)。因此,您无法在默认参数中访问self,并且永远也无法访问。

【讨论】:

    猜你喜欢
    • 2015-02-27
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    相关资源
    最近更新 更多