分配类变量作为默认值,以类方法参数(assigning class variable as defa

2019-07-20 21:44发布

我想建立与此类取默认值的参数在类中的方法。 总的来说,我做过滤一些数据。 在我的班级我有而正常情况下我通过数据载体的方法。 有时候,我没有载体和我带的模拟数据。 每次我没有通过一个特定的载体,我想在默认情况下采取模拟数据。 我认为这应该是一个简单的构造,其中我的方法定义里面我说a=self.vector 。 但由于某些原因,我有一个错误NameError: name 'self' is not defined 。 简化的结构是:

class baseClass(object):  # This class takes an initial data or simulation
    def __init__(self):
        self.x = 1
        self.y = 2

class extendedClass(baseClass): # This class does some filtering
    def __init__(self):
        baseClass.__init__(self)
        self.z = 5
    def doSomething(self, a=self.z):
        self.z = 3
        self.b = a

if __name__ == '__main__':
    a = extendedClass()
    print a.__dict__
    a.doSomething()
    print a.__dict__

我预期的输出应该是:

{'y': 2, 'x': 1, 'z': 5}
{'y': 2, 'x': 1, 'z': 3, 'b': 5}

我试图默认分配为def doSomething(self, a=z):很明显这并不永远工作。 据我了解self.z是在此范围内可见的,不应该把它作为一个默认值的问题。 不知道为什么我有这样的错误,以及如何做到这一点。 这可能是一个简单的问题,但我揣摩出或找到不缺了一段时间已经解决。 我发现类似的问题,只为其他语言。

Answer 1:

你的理解是错误的。 self本身就是一个参数,该函数的定义,那么有没有办法可以在这一点上是在范围内。 这是只有在函数内部的范围。

答案很简单,就是默认的参数None ,然后检查,该方法中:

def doSomething(self, a=None):
    if a is None:
        a = self.z
    self.z = 3
    self.b = a


Answer 2:

下面的代码为一个简单的例子模块拆卸。 A码对象为字节码时,它使用的常数和名称,和元数据的本地变量的数量,所需的堆栈大小等的只读容器注意,所有代码对象的被编译为常数。 这些都是在编译时创建的。 但对象class Afunction test是在执行时(例如,当模块被导入)实例化。

为了使课堂, BUILD_CLASS取名字'A' ,该基地tuple (object,) ,以及dict包含类的命名空间的属性。 这就像通过调用手动实例化一个类型type(name, bases, dict) 。 为了使dict ,从编码对象创建一个功能A叫。 最后,类对象被存储在经由模块命名空间STORE_NAME

在代码对象Aself.z装入堆栈作为参数上MAKE_FUNCTION 。 字节码运算LOAD_NAME将搜索self当前当地人(即正在定义的类命名空间),该模块全局变量,和内置函数。 如果这显然不能self未在全局或内建范围定义; 它显然不是在本地范围内定义。

如果没有成功,但是,该功能将与创建(self.z,)作为其__defaults__属性,然后存储到本地名称test

>>> code = compile('''
... class A(object):
...   def test(self, a=self.z): pass
... ''', '<input>', 'exec')

>>> dis.dis(code)
  2           0 LOAD_CONST               0 ('A')
              3 LOAD_NAME                0 (object)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               1 (<code object A ...>)
             12 MAKE_FUNCTION            0
             15 CALL_FUNCTION            0
             18 BUILD_CLASS         
             19 STORE_NAME               1 (A)
             22 LOAD_CONST               2 (None)
             25 RETURN_VALUE

>>> dis.dis(code.co_consts[1]) # code object A
  2           0 LOAD_NAME                0 (__name__)
              3 STORE_NAME               1 (__module__)

  3           6 LOAD_NAME                2 (self)
              9 LOAD_ATTR                3 (z)
             12 LOAD_CONST               0 (<code object test ...>)
             15 MAKE_FUNCTION            1
             18 STORE_NAME               4 (test)
             21 LOAD_LOCALS         
             22 RETURN_VALUE       

@uselpa:您的引擎收录的例子(改写2.X):

>>> code = compile('''
... default = 1
... class Cl(object):
...     def __init__(self, a=default):
...         print a
... Cl()
... default = 2
... Cl()
... ''', '<input>', 'exec')
>>> dis.dis(code)
  2           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (default)

  3           6 LOAD_CONST               1 ('Cl')
              9 LOAD_NAME                1 (object)
             12 BUILD_TUPLE              1
             15 LOAD_CONST               2 (<code object Cl ...>)
             18 MAKE_FUNCTION            0
             21 CALL_FUNCTION            0
             24 BUILD_CLASS         
             25 STORE_NAME               2 (Cl)

  6          28 LOAD_NAME                2 (Cl)
             31 CALL_FUNCTION            0
             34 POP_TOP             

  7          35 LOAD_CONST               3 (2)
             38 STORE_NAME               0 (default)

  8          41 LOAD_NAME                2 (Cl)
             44 CALL_FUNCTION            0
             47 POP_TOP             
             48 LOAD_CONST               4 (None)
             51 RETURN_VALUE        

正如你所看到的,类对象Cl (和函数对象__init__ )只实例化和存储到本地名称'Cl'一次。 该模块在运行时依次执行,所以随后重新绑定的名称default将对默认值没有影响__init__

你可以使用以前编译代码和一个新的默认值动态实例化一个新功能:

>>> default = 1
>>> class Cl(object):
...     def __init__(self, a=default):
...         print a
... 

>>> from types import FunctionType
>>> default = 2
>>> Cl.__init__ = FunctionType(
...   Cl.__init__.__code__, globals(), '__init__', (default,), None)
>>> c = Cl()
2

这重用从已编译的代码对象__init__.__code__创建功能与新的__defaults__元组:

>>> Cl.__init__.__defaults__
(2,)


Answer 3:

默认参数得到评估一次,在执行的定义。 相反,这样做:

def doSomething(self, a=None):
    if a is None:
        a = self.z
    self.z = 3
    self.b = a

又见http://docs.python.org/release/3.3.0/tutorial/controlflow.html#more-on-defining-functions 。



Answer 4:

这将插入self.z如果aNone / False / empty_value

def doSomething(self, a=None):
        self.z = 3
        self.b = (a or self.z)


文章来源: assigning class variable as default value to class method argument