我想在类中构建一个方法,其中默认值参数取自此类。一般来说,我会过滤一些数据。在我的班级里面,我有一个方法,通常我传递数据向量。有时我没有矢量,我采用模拟数据。每次我没有传递特定的矢量时,我都希望默认采用模拟数据。我认为它应该是一个简单的构造,在我的方法定义中我说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
在此范围内可见,并且将其作为默认值应该不是问题。不知道为什么我有这个错误以及如何做到这一点。这可能是一个简单的问题,但我试图找出它或找到解决方案已经有一段时间了。我发现只有其他语言的similar个问题。
答案 0 :(得分:46)
你的理解是错误的。 self
本身就是该函数定义的参数,因此在这一点上它无法进入范围。它只在函数本身的范围内。
答案只是将参数默认为None
,然后在方法内检查:
def doSomething(self, a=None):
if a is None:
a = self.z
self.z = 3
self.b = a
答案 1 :(得分:7)
这是一个简单示例模块的代码的反汇编。代码对象是字节码的只读容器,它使用的常量和名称,以及有关局部变量数量,所需堆栈大小等的元数据。请注意,所有代码对象都编译为常量。这些是在编译时创建的。但是对象class A
和function test
在执行时被实例化(例如,在导入模块时)。
要创建课程,BUILD_CLASS
将使用名称'A'
,基础tuple
(object,)
和包含类名称空间属性的dict
。这类似于通过调用type(name, bases, dict)
手动实例化类型。要创建dict
,将从代码对象A
创建一个函数并进行调用。最后,类对象通过STORE_NAME
存储在模块命名空间中。
在代码对象A
中,self.z
作为MAKE_FUNCTION
的参数加载到堆栈中。字节码op LOAD_NAME
将在当前本地(即定义的类命名空间),模块全局和内置中搜索self
。如果未在global或builtins范围中定义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:您的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
如您所见,类对象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,)
答案 2 :(得分: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。
答案 3 :(得分:1)
如果self.z
为a
/ None
/ False
,则会插入empty_value
:
def doSomething(self, a=None):
self.z = 3
self.b = (a or self.z)