【问题标题】:Is there a way to make code run when a class is derived from a particular parent class in Python?当一个类派生自 Python 中的特定父类时,有没有办法让代码运行?
【发布时间】:2014-07-29 13:21:15
【问题描述】:

例如,如果我创建类 Foo,然后派生子类 Bar,我希望 Foo 的 myCode() 方法运行。

class Foo(object):
    x = 0
    def __init__(self):
        pass
    def myCode(self):
        if(self.x == 0):
            raise Exception("nope")


class Bar(Foo):    #This is where I want myCode() to execute
    def baz(self):
        pass

这应该在任何类从基类 Foo 派生时发生。是否有可能在 Python 中做到这一点?如果重要的话,我正在使用 Python 3。

注意:在我的真实代码中,Foo实际上是一个抽象基类。

编辑:我还需要访问myCode() 中的派生类成员数据和方法。

【问题讨论】:

  • 查找元类。这需要一些技巧才能让 Foo “告诉”元类在子类化时要调用它。如果您尝试元类解决方案,您可能会更好地提出更具体的问题。
  • 我实际上正在为我的 Foo 类使用“abc”库中的抽象基类,我查看了相关文档,但它似乎对我想要的东西没有帮助虽然做。我不确定抽象类和元类之间的区别是什么,但我会研究一下。
  • 你到底想让myCode做什么?
  • 您希望将什么“self”参数传递给myCode
  • 在此用例中,myCode() 将检查派生类的实现,以确保与应使用父类的派生实例的方式一致。 Tldr:我需要能够访问myCode() 中的派生类成员数据,例如。 self.x。我不确定如何用灰色衬衫的回答来做到这一点。

标签: python class oop python-3.x


【解决方案1】:

使用metaclass

class MetaClass:
    def __init__(cls, name, bases, dictionary):
        if name is not 'Parent':
            print('Subclass created with name: %s' % name)
        super().__init__(name, bases, dictionary)

class Parent(metaclass=MetaClass):
    pass

class Subclass(Parent):
    pass

输出:

Subclass created with name: Subclass

元类控制类本身的创建方式。子类从父类继承其元类,因此代码在定义时就会运行。

编辑:至于您使用抽象基类的用例,我想您只需要将元类定义为 ABCMeta 的子类,但我没有对此进行测试。

【讨论】:

  • 我收到了NameError: global name 'self' is not definedself.validate_subclass(subclass) 行。
  • 你是对的;我删除了该代码,因为它没有任何好处。道歉;请参考我上面的评论。
  • 虽然我自己解决了这个问题,但我还是选择了这个作为使用元类的建议的答案。
  • 谢谢!我很好奇你想出了什么,简而言之。
  • 我把它作为这个问题的答案发布了。
【解决方案2】:

希望这段代码可以帮助你:

class Foo:
    def myCode(self):
        print('myCode within Foo')
    def __init__(self):
        if type(self) != Foo:
            self.myCode()

class Bar(Foo):
    def __init__(self):
        super(Bar, self).__init__()
    def baz(self):
        pass

测试:

>>> 
>>> f = Foo()
>>> b = Bar()
myCode within Foo
>>> 

【讨论】:

  • 当一个类派生自我的基类Foo 时,我需要运行代码,而不是在实例化Foo 的派生类时运行。
【解决方案3】:

这行得通:

class MyMeta(type):
    def __new__(cls, name, parents, dct):
        if name is not 'Foo':
            if 'x' not in dct:
                raise Exception("Nein!")
            elif 'x' in dct and dct['x'] == 0:
                raise Exception("Nope!")
        return super(MyMeta, cls).__new__(cls, name, parents, dct)

输出:

class Bar(Foo):
    x = 0
> Exception: Nope!

如果有人想评论这是否合适,这是我的具体用例:

class MagmaMeta(type):
    def __new__(cls, name, parents, dct):
        # Check that Magma instances are valid.
        if name is not 'Magma':
            if 'CAYLEY_TABLE' not in dct:
                raise Exception("Cannot create Magma instance without CAYLEY_TABLE")
            else:
                # Check for square CAYLEY_TABLE
                for row in CAYLEY_TABLE:
                    if not len(row) == len(dct['CAYLEY_TABLE']):
                        raise Exception("CAYLEY_TABLE must be a square array")
                # Create SET and ORDER from CAYLEY_TABLE
                dct['SET'] = set([])
                for rows in CAYLEY_TABLE:
                    for x in rows:
                        dct['SET'].add(x)
                dct['ORDER'] = len(dct['SET'])
        return super(MyMeta, cls).__new__(cls, name, parents, dct)

【讨论】:

    猜你喜欢
    • 2010-11-22
    • 1970-01-01
    • 2022-08-24
    • 2021-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    相关资源
    最近更新 更多