【问题标题】:Is there any way to remove a nested class in Python?有什么方法可以删除 Python 中的嵌套类?
【发布时间】:2020-01-29 03:13:15
【问题描述】:

下面的脚本尝试从Outer 类中删除Inner1 嵌套类。我收到明确的错误“TypeError:无法删除 __class__ 属性”。死胡同?

def Loader(cls):
    for key in dir(cls):
        value = getattr(cls, key)
        if isinstance(value, type):
            delattr(cls, key)
    return cls

@Loader
class Outer:
    class Inner1:
        X = 1

print(Outer.Inner1.X)

【问题讨论】:

  • 记住__dir__会返回各种各样的东西。
  • 将其减少到 delattr(Outer, 'Inner1') 将按预期工作 - 发生的情况是 dir(cls) 生成了 __class__ 属性,由于生成的代码 delattr(Outer, '__class__') 无法从任何类中删除该属性
  • Loader 试图删除的不仅仅是Inner1,它还试图删除cls 中的任何内容,即type 的一个实例。错误实际上很清楚 - 您的代码试图删除 __class__ 属性,但它不能。

标签: python metaprogramming


【解决方案1】:

问题在于以下行:

if isinstance(value, type):

匹配从type 继承的所有内容。如果您只想删除在装饰类中明确定义的内部类,您可以使用以下内容:

from inspect import isclass

def Loader(cls):
    # vars returns the __dict__ attributes, so only names that are explicitely defined in cls.
    for key, value in vars(cls).copy().items():

        # If it is a class, delete it
        if isclass(value):
            delattr(cls, key)

    return cls

@Loader
class Outer:
    class Inner1:
        X = 1

print(Outer.Inner1.X) # AttributeError: type object 'Outer' has no attribute 'Inner1'

另一种方法是将您的装饰器设为一个类,并明确告诉它您要删除的名称。例如

class Loader:
    def __init__(self, *args):
        # Store the given names to delete
        self.names = args

    def __call__(self, cls):
        for name in self.names:
            try:
                delattr(cls, name)
            except AttributeError:
                pass

        return cls

@Loader('Inner1', 'Inner2', 'etc')
class Outer:
    class Inner1:
        X = 1

print(Outer.Inner1.X) # AttributeError: type object 'Outer' has no attribute 'Inner1'

也就是说,我不确定您为什么要装饰一个类并定义您将动态删除的内部类...为什么不...根本不定义它们? :D

【讨论】:

  • “我不知道你为什么要装饰一个类并定义你将动态删除的内部类......为什么不......根本不定义它们?” i> 好问题。如果出于某种教学原因我想禁止使用特定功能(如嵌套类),我能想象的唯一原因是对学生的作业进行自动评分。在那种情况下,我想知道使用了嵌套类,而不是删除它,但在其他类似的模糊用例中,删除嵌套类可能是正确的做法。
猜你喜欢
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 2015-11-13
相关资源
最近更新 更多