将类变量指定为类方法参数的默认值

tom*_*z74 46 python class variable-assignment

我想在类中构建一个方法,其中包含从此类中获取的默认值参数.一般来说,我会过滤一些数据.在我的班级里面,我有一个方法,通常我传递数据向量.有时我没有矢量,我采用模拟数据.每次我没有传递特定的矢量时,我都希望默认采用模拟数据.我认为它应该是一个简单的构造,我在我的方法定义中说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__
Run Code Online (Sandbox Code Playgroud)

我预期的输出应该是:

{'y': 2, 'x': 1, 'z': 5}
{'y': 2, 'x': 1, 'z': 3, 'b': 5}
Run Code Online (Sandbox Code Playgroud)

我试过默认分配,因为def doSomething(self, a=z):它显然不起作用.据我所知self.z,在这个范围内可见,并且将它作为默认值应该不是问题.不知道为什么我有这个错误以及如何做到这一点.这可能是一个简单的问题,但我试图找出它或找到解决方案已经有一段时间了.我发现只有其他语言的类似问题.

Dan*_*man 52

你的理解是错误的.self它本身就是该函数定义的参数,因此在这一点上它无法进入范围.它只在函数本身的范围内.

答案就是将参数默认为None,然后在方法内部检查:

def doSomething(self, a=None):
    if a is None:
        a = self.z
    self.z = 3
    self.b = a
Run Code Online (Sandbox Code Playgroud)

  • 我认为您的意思是“如果不是a:a = self.z” (2认同)

Ery*_*Sun 7

这是一个简单示例模块的代码的反汇编.代码对象是字节码的只读容器,它使用的常量和名称,以及有关局部变量数量,所需堆栈大小等的元数据.请注意,所有代码对象都编译为常量.这些是在编译时创建的.但对象class Afunction test在运行时间(例如,当模块被导入)实例化.

要创建类,请BUILD_CLASS使用名称'A',基数tuple (object,)dict包含类命名空间属性的a .这就像通过调用手动实例化类型一样type(name, bases, dict).为了制作dict,一个函数是从代码对象创建A并调用的.最后,类对象通过存储在模块命名空间中STORE_NAME.

在代码对象中A,self.z作为参数加载到堆栈中MAKE_FUNCTION.字节码op LOAD_NAMEself在当前本地(即定义的类命名空间),模块全局和内置中搜索.如果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       
Run Code Online (Sandbox Code Playgroud)

@uselpa:你的pastebin示例(为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        
Run Code Online (Sandbox Code Playgroud)

如您所见,类对象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
Run Code Online (Sandbox Code Playgroud)

这将重用已编译的代码对象__init__.__code__来创建具有__defaults__新元组的函数:

>>> Cl.__init__.__defaults__
(2,)
Run Code Online (Sandbox Code Playgroud)


use*_*lpa 5

执行定义时,默认参数仅计算一次。相反,请执行以下操作:

def doSomething(self, a=None):
    if a is None:
        a = self.z
    self.z = 3
    self.b = a
Run Code Online (Sandbox Code Playgroud)

另请参见http://docs.python.org/release/3.3.0/tutorial/controlflow.html#more-on-defining-functions