【问题标题】:python: determine if a class is nestedpython:确定一个类是否嵌套
【发布时间】:2010-10-12 22:55:34
【问题描述】:

假设你有一个获取类型作为参数的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 中定义的。

【问题讨论】:

  • self.__class__.__name__ 有什么问题?您获取这些信息的目的是什么?
  • @S.Lott:“self.__class__.__name__ 有什么问题”是什么意思?对不起,我不明白你的问题...
  • @orsogufo:什么是“错误”--不起作用--不合适--没有帮助--坏了--没有做你想做的--是格式不正确——self.__class__.__name__“错误”?这有点不对劲,但我不知道你不喜欢什么。请澄清。
  • “我想要做的是在不使用单独文件的情况下拥有相当于 c++ 命名空间”——这不是一个好方法。文件是一个很好的命名空间。使用它们。每个其他 Python 程序员都会这样做。

标签: python introspection inner-classes


【解决方案1】:

从 Python 3.3 开始有一个新属性__qualname__,它不仅提供类名,还提供外部类的名称:

在您的示例中,这将导致:

assert SomeClass.__qualname__ == 'SomeClass'
assert OuterClass.InnerClass.__qualname__ == 'OuterClass.InnerClass'

如果类的__qualname__ 不包含'.'它是一个外部类!

【讨论】:

    【解决方案2】:

    谢谢大家的回答。
    我使用元类找到了这个可能的解决方案;我所做的更多是出于固执而不是真正的需要,而且这样做的方式不适用于 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()
    

    【讨论】:

      【解决方案3】:

      内部类在 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...
      

      此外,它尝试复制 Java 行为,即使用 getattr/setattr 在内部类上提供外部类变量是非常狡猾的,而且实际上是不必要的(因为更 Pythonic 的方式是显式调用 i.__outer__.attr )。

      【讨论】:

        【解决方案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
        

        【讨论】:

          【解决方案5】:

          如果不自己设置,我不相信有什么方法可以判断类是否嵌套。无论如何,Python 类不能用作命名空间(或至少不容易),我想说最好的办法是简单地使用不同的文件。

          【讨论】:

            【解决方案6】:

            AFAIK,给定一个类而没有其他信息,你无法判断它是否是一个嵌套类。但是,see here 了解如何使用装饰器来确定这一点。

            问题在于嵌套类只是一个普通类,它是其外部类的一个属性。您可能期望工作的其他解决方案可能不会 - 例如,inspect.getmro 只为您提供基类,而不是外部类。

            此外,很少需要嵌套类。我会强烈地重新考虑这是否是在您想使用它的每个特定情况下的好方法。

            【讨论】:

            • 谢谢,接受你的回答:关键是嵌套类是外部的属性。 P.S:我确信嵌套类总是有替代品,但我不明白为什么它们也不应该是一个坏主意。
            猜你喜欢
            • 1970-01-01
            • 2010-09-28
            • 2012-02-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-05-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多