我有一个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
类本身。
我想知道是否有办法避免在调用Child
时传递第二个method2
参数。
我发现的一种解决方法是在基类中定义一个抽象方法,然后在子类中构建该函数,如下所示:
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)
但是,我希望此方法位于基类中。有什么想法吗?预先感谢!
答案 0 :(得分:0)
方法隐式接收self
作为第一个参数,即使它似乎没有被传递。例如:
class C:
def f(self, x):
print(x)
C.f
带有两个参数,但是通常只用一个参数来调用它:
c = C()
c.f(1)
方法是,当您访问c.f
时,会创建一个“ bound” 方法,该方法隐式地将c
作为第一个参数。
如果您将外部函数分配给类并将其用作方法,则会发生同样的事情。
在子类中实现方法的通常方法是在子类中显式地实现它,而不是在外部函数中实现,所以我要做的不是你所做的:
class Child(Base):
property1 = 'text'
# instead of: property2 = function
def property2(self, val):
return val + 1
如果您真的想在班上有property2 = function
(看不到原因)而在班上有function
,那么您就必须照顾self
:>
class Child(Base):
property1 = 'text'
property2 = function
def function(self, val):
return val + 1
如果您要使用先前的解决方案,但在self
中没有function
:
class Child(Base):
property1 = 'text'
def property2(self, val):
return function(val)
def function(val):
return val + 1
答案 1 :(得分:0)
让您的方法静态:
class Child(Base)
property2 = staticmethod(function)
如zvone所述,bound methods隐式接收self
作为第一个参数。
要创建绑定方法,您不一定需要在类主体中对其进行定义。
这个:
def foo(self):
print("foo")
class Foo:
bar = foo
f = Foo()
print(f.bar)
将输出:
>>> <bound method foo of <__main__.Foo object at 0x014EC790>>
分配给class属性的函数因此将像普通的类方法一样工作,这意味着,如果将其称为f.bar()
,则它将被视为绑定方法,并且self
会作为第一个隐式传递参数。
要控制隐式传递给类方法的是什么和不隐式传递给类方法,因为第一个参数通常由装饰器控制
@classmethod
:该类本身作为第一个参数传递@staticmethod
:不会将任何参数隐式传递给方法因此,您需要staticmethod
的行为,但是由于您只是将已定义的函数分配给类属性,因此不能使用装饰器语法。
但是,由于装饰器只是将函数作为参数并返回包装函数的普通函数,所以:
class Child(Base):
property2 = staticmethod(function)
与此等效(*):
class Child(Base):
@staticmethod
def property2():
function()
我建议对您的Base
类进行一些小的修改:
重命名property2
并将其标记为abstractproperty
(**)而不是abstractstaticmethod
。
这将帮助同事(并最终使您自己)更好地理解子类中期望什么样的实现。
class Base(object):
__metaclass__ = ABCMeta
@abstractstaticmethod
def staticmethod1(self):
pass
(*)或多或少。前者实际上将function
分配给property2
,后者实际上创建了一个新的静态方法,该方法委托给function
。
(**)abstractstaticmethod
自Python 3.3起是deprecated,但由于您也使用abstractproperty
,所以我希望保持一致。