嵌套类的范围?
- 2025-03-05 09:14:00
- admin 原创
- 94
问题描述:
我正在尝试理解 Python 中嵌套类的作用域。这是我的示例代码:
class OuterClass:
outer_var = 1
class InnerClass:
inner_var = outer_var
类的创建没有完成,并且我收到错误:
<type 'exceptions.NameError'>: name 'outer_var' is not defined
尝试inner_var = Outerclass.outer_var
无效。我得到:
<type 'exceptions.NameError'>: name 'OuterClass' is not defined
outer_var
我正在尝试从访问静态InnerClass
。
有办法吗?
解决方案 1:
class Outer(object):
outer_var = 1
class Inner(object):
@property
def inner_var(self):
return Outer.outer_var
这与其他语言中的类似方法不太一样,它使用全局查找而不是限定对的访问范围outer_var
。(如果您更改名称Outer
绑定到的对象,则此代码将在下次执行时使用该对象。)
如果你希望所有Inner
对象都引用一个Outer
因为outer_var
实际上是一个实例属性:
class Outer(object):
def __init__(self):
self.outer_var = 1
def get_inner(self):
return self.Inner(self)
# "self.Inner" is because Inner is a class attribute of this class
# "Outer.Inner" would also work, or move Inner to global scope
# and then just use "Inner"
class Inner(object):
def __init__(self, outer):
self.outer = outer
@property
def inner_var(self):
return self.outer.outer_var
请注意,嵌套类在 Python 中并不常见,并且不会自动暗示类之间存在任何特殊关系。最好不要嵌套。(如果需要,您仍然可以将类属性设置Outer
为。)Inner
解决方案 2:
我认为你可以简单地这样做:
class OuterClass:
outer_var = 1
class InnerClass:
pass
InnerClass.inner_var = outer_var
您遇到的问题是由于以下原因造成的:
块是作为一个单元执行的一段 Python 程序文本。以下是块:模块、函数体和类定义。
(...)
范围定义块内名称的可见性。
(...)
类块中定义的名称的范围仅限于类块;它不会扩展到方法的代码块——这包括生成器表达式,因为它们是使用函数范围实现的。这意味着以下内容将失败:
class A: a = 42 b = list(a + i for i in range(10))
http://docs.python.org/reference/executionmodel.html#naming-and-binding
上面的意思是:
函数体是一个代码块,而方法是一个函数,那么在类定义中存在的函数体之外定义的名称不会扩展到函数体。
根据您的情况进行解释:
类定义是一个代码块,那么在外部类定义中存在的内部类定义之外定义的名称不会扩展到内部类定义。
解决方案 3:
如果你不使用嵌套类,情况可能会更好。如果必须嵌套,请尝试以下方法:
x = 1
class OuterClass:
outer_var = x
class InnerClass:
inner_var = x
或者在嵌套之前声明这两个类:
class OuterClass:
outer_var = 1
class InnerClass:
inner_var = OuterClass.outer_var
OuterClass.InnerClass = InnerClass
(此后,del InnerClass
如果您需要的话,就可以这么做。)
解决方案 4:
最简单的解决方案:
class OuterClass:
outer_var = 1
class InnerClass:
def __init__(self):
self.inner_var = OuterClass.outer_var
它要求你明确表达,但不需要花费太多精力。
解决方案 5:
在 Python 中,可变对象作为引用传递,因此您可以将外部类的引用传递给内部类。
class OuterClass:
def __init__(self):
self.outer_var = 1
self.inner_class = OuterClass.InnerClass(self)
print('Inner variable in OuterClass = %d' % self.inner_class.inner_var)
class InnerClass:
def __init__(self, outer_class):
self.outer_class = outer_class
self.inner_var = 2
print('Outer variable in InnerClass = %d' % self.outer_class.outer_var)
解决方案 6:
所有解释都可以在Python 文档 Python 教程中找到
对于您的第一个错误<type 'exceptions.NameError'>: name 'outer_var' is not defined
。解释是:
在方法内部引用数据属性(或其他方法!)没有捷径。我发现这实际上提高了方法的可读性:浏览方法时不会混淆局部变量和实例变量。
引自Python 教程 9.4
对于你的第二个错误<type 'exceptions.NameError'>: name 'OuterClass' is not defined
当类定义正常离开(通过结束)时,将创建一个类对象。
引自Python 教程 9.3.1
因此,当您尝试时inner_var = Outerclass.outer_var
,Quterclass
尚未创建,这就是为什么name 'OuterClass' is not defined
对于您的第一个错误,更详细但乏味的解释:
尽管类可以访问封闭函数的作用域,但它们并不充当嵌套在类中的代码的封闭作用域:Python 会在封闭函数中搜索引用的名称,但从不搜索任何封闭类。也就是说,类是局部作用域,可以访问封闭局部作用域,但它并不充当进一步嵌套代码的封闭局部作用域。
引自Learning.Python(5th).Mark.Lutz
解决方案 7:
class c_outer:
def __init__(self, name:str='default_name'):
self._name = name
self._instance_lst = list()
self._x = self.c_inner()
def get_name(self):
return(self._name)
def add_inner_instance(self,name:str='default'):
self._instance_lst.append(self.c_inner(name))
def get_instance_name(self,index:int):
return(self._instance_lst[index].get_name())
class c_inner:
def __init__(self, name:str='default_name'):
self._name = name
def get_name(self):
return(self._name)
outer = c_outer("name_outer")
outer.add_inner_instance("test1")
outer.add_inner_instance("test2")
outer.add_inner_instance("test3")
inner_1 = outer.c_inner("name_inner1")
inner_2 = outer.c_inner("name_inner2")
inner_3 = outer.c_inner("name_inner3")
print(outer.get_instance_name(index=0))
print(outer.get_instance_name(1))
print(outer._instance_lst[2]._name
print(outer.get_name())
print(inner_1.get_name())
print(inner_2.get_name())
测试1 测试2 测试3 name_outer name_inner1 name_inner2 name_inner3
扫码咨询,免费领取项目管理大礼包!