假设您有一个python方法,它将类型作为参数;是否可以确定给定的类型是否是嵌套类? 例如。在这个例子中:
def show_type_info(t):
print t.__name__
# print outer class name (if any) ...
class SomeClass:
pass
class OuterClass:
class InnerClass:
pass
show_type_info(SomeClass)
show_type_info(OuterClass.InnerClass)
我希望调用show_type_info(OuterClass.InnerClass)
来显示InnerClass是在OuterClass中定义的。
答案 0 :(得分:13)
AFAIK,给定一个类而没有其他信息,你无法判断它是否是一个嵌套类。但是,see here表示您可以使用装饰器来确定这一点。
问题是嵌套类只是一个普通类,它是外部类的属性。您可能期望工作的其他解决方案可能不会 - 例如,inspect.getmro
仅为您提供基类,而不是外部类。
此外,很少需要嵌套类。我会强烈重新考虑在每个特殊情况下这是一个很好的方法,你会觉得很想使用它。
答案 1 :(得分:5)
内部类在Python中没有提供特殊的特性。它只是类对象的属性,与整数或字符串属性没有区别。您的OuterClass / InnerClass示例可以完全重写为:
class OuterClass(): pass
class InnerClass(): pass
OuterClass.InnerClass= InnerClass
InnerClass无法知道它是否在另一个类中声明,因为它只是一个普通的变量绑定。使绑定方法了解其拥有者“自我”的魔力在这里不适用。
John发布的链接中的内部类装饰魔术是一种有趣的方法,但我不会按原样使用它。它不会缓存为每个外部对象创建的类,因此每次调用outerinstance.InnerClass时都会得到一个新的InnerClass:
>>> o= OuterClass()
>>> i= o.InnerClass()
>>> isinstance(i, o.InnerClass)
False # huh?
>>> o.InnerClass is o.InnerClass
False # oh, whoops...
此外,它尝试复制使用getattr / setattr在内部类上使外部类变量可用的Java行为的方式非常狡猾,并且实际上是不必要的(因为更多的Pythonic方式是明确地调用i .__ outer __。attr )。
答案 2 :(得分:4)
实际上,嵌套类与任何其他类没有什么不同 - 它恰好被定义在除顶级命名空间之外的其他地方(在另一个类中)。如果我们将描述从“嵌套”修改为“非顶级”,那么您可能已经足够接近您需要的内容。
例如:
import inspect
def not_toplevel(cls):
m = inspect.getmodule(cls)
return not (getattr(m, cls.__name__, []) is cls)
这适用于常见情况,但在定义后重命名或以其他方式操作的情况下,它可能无法执行您想要的操作。例如:
class C: # not_toplevel(C) = False
class B: pass # not_toplevel(C.B) = True
B=C.B # not_toplevel(B) = True
D=C # D is defined at the top, but...
del C # not_toplevel(D) = True
def getclass(): # not_toplevel(getclass()) = True
class C: pass
答案 3 :(得分:1)
谢谢大家的回答
我发现这种可能的解决方案使用元类;我已经做了更多的顽固而不是真正的需要,并且它以一种不适用于python 3的方式完成。
我想分享这个解决方案,所以我在这里发布。
#!/usr/bin/env python
class ScopeInfo(type): # stores scope information
__outers={} # outer classes
def __init__(cls, name, bases, dict):
super(ScopeInfo, cls).__init__(name, bases, dict)
ScopeInfo.__outers[cls] = None
for v in dict.values(): # iterate objects in the class's dictionary
for t in ScopeInfo.__outers:
if (v == t): # is the object an already registered type?
ScopeInfo.__outers[t] = cls
break;
def FullyQualifiedName(cls):
c = ScopeInfo.__outers[cls]
if c is None:
return "%s::%s" % (cls.__module__,cls.__name__)
else:
return "%s.%s" % (c.FullyQualifiedName(),cls.__name__)
__metaclass__ = ScopeInfo
class Outer:
class Inner:
class EvenMoreInner:
pass
print Outer.FullyQualifiedName()
print Outer.Inner.FullyQualifiedName()
print Outer.Inner.EvenMoreInner.FullyQualifiedName()
X = Outer.Inner
del Outer.Inner
print X.FullyQualifiedName()
答案 4 :(得分:0)
如果您没有自己设置,我不相信有任何方法可以确定该类是否嵌套。无论如何,Python类不能用作命名空间(或者至少不容易),我想说最好的办法就是使用不同的文件。
答案 5 :(得分:0)
从Python 3.3开始,有一个新属性__qualname__
,它不仅提供类名,还提供外部类的名称:
在您的示例中,这将导致:
assert SomeClass.__qualname__ == 'SomeClass'
assert OuterClass.InnerClass.__qualname__ == 'OuterClass.InnerClass'
如果某个类的__qualname__
不包含'。'这是一个外层阶层!