繁体   English   中英

如何在基类中使用子类的函数属性?

[英]How can I use a child class' function attribute in the base class?

概述

我有一个 python 类继承结构,其中大多数方法在基类中定义,而这些方法所依赖的大多数属性在子类中定义。

基类大致如下所示:

class Base(object):

    __metaclass__ = ABCMeta

    @abstractproperty
    def property1(self):
        pass

    @abstractproperty
    def property2(self):
        pass

    def method1(self):
        print(self.property1)

    def method2(self, val):
        return self.property2(val)

而子类看起来像这样:

class Child(Base):
    property1 = 'text'
    property2 = function

其中function是一个如下所示的函数:

def function(val):
    return val + 1

显然上面的代码缺少细节,但结构反映了我真实代码的结构。

问题

当我尝试在基类中使用method1 ,一切都按预期工作:

>>> child = Child()
>>> child.method1()
'text'

但是,对method2尝试相同的方法会引发错误:

>>> child = Child()
>>> child.method2(1)  # expected 2
TypeError: method2() takes exactly 1 argument (2 given)

第二个传递的参数是Child类本身。

我想知道是否有办法避免在调用method2时传递第二个Child参数。

尝试

我发现的一种解决方法是在基类中定义一个抽象方法,然后在子类中构建该函数,如下所示:

class Base(object):

    __metaclass__ = ABCMeta

    @abstractproperty
    def property1(self):
        pass

    @abstractmethod
    def method2(self, val):
        pass

    def method1(self):
        print(self.property1)
class Child(Base):

    property1 = 'text'

    def method2(self, val):
        return function(val)

但是,我更希望这个方法存在于基类中。 有什么想法吗? 提前致谢!

方法隐式地接收self作为第一个参数,即使它似乎没有被传递。 例如:

class C:
    def f(self, x):
        print(x)

Cf有两个参数,但你通常只用一个来调用它:

c = C()
c.f(1)

这样做的方式是,当您访问cf时,会创建一个“绑定”方法,该方法隐式地将c作为第一个参数。

如果您将外部函数分配给类并将其用作方法,也会发生同样的情况,就像您所做的那样。

解决方案1

在子类中实现方法的通常方法是在子类中显式执行,而不是在外部函数中执行,因此我会执行以下操作而不是您所做的:

class Child(Base):
    property1 = 'text'

    # instead of: property2 = function
    def property2(self, val):
        return val + 1

解决方案2

如果你真的想拥有property2 = function的类(不知道为什么)和function了之类的,那么你必须照顾self

class Child(Base):
    property1 = 'text'
    property2 = function

def function(self, val):
    return val + 1

解决方案3

如果你想要以前的解决方案,但没有selffunction

class Child(Base):
    property1 = 'text'

    def property2(self, val):
        return function(val)

def function(val):
    return val + 1

解决方案

使您的方法静态:

class Child(Base)
    property2 = staticmethod(function)

解释

正如 zvone 已经解释的那样, 绑定方法隐式接收self作为第一个参数。
要创建绑定方法,您不一定需要在类主体中定义它。
这个:

def foo(self):
    print("foo")

class Foo:
    bar = foo

f = Foo()
print(f.bar)

将输出:

>>> <bound method foo of <__main__.Foo object at 0x014EC790>>

因此,分配给类属性的函数的行为就像普通的类方法一样,这意味着如果您将其作为f.bar()调用,它将被视为绑定方法,而self作为第一个参数隐式传递。

控制隐式传递给类方法的内容和内容,因为第一个参数通常由装饰器控制

  • @classmethod :类本身作为第一个参数传递
  • @staticmethod :没有参数被隐式传递给方法

所以你想要一个staticmethod的行为,但由于你只是将一个已经定义的函数分配给一个类属性,你不能使用装饰器语法。
但是由于装饰器只是将函数作为参数并返回包装函数的普通函数,因此:

class Child(Base):
    property2 = staticmethod(function)

等价于 (*):

class Child(Base):
    @staticmethod
    def property2():
        function()

进一步改进

我建议对您的Base类进行一些小的额外修改:
重命名property2并将其标记为abstractproperty property2而不是abstractproperty abstractstaticmethod (**)。 这将帮助同事(最终是你自己)更好地理解子类中期望什么样的实现。

class Base(object):

    __metaclass__ = ABCMeta

    @abstractstaticmethod
    def staticmethod1(self):
        pass

(*) 好吧,或多或少。 前者实际上将function分配给property2 ,后者创建了一个新的静态方法,该方法委托给function

(**) abstractstaticmethod自 Python 3.3 起已弃用,但由于您也在使用abstractproperty我希望保持一致。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM