我几乎可以确定我想要做的事情有一个合适的术语,但由于我不熟悉它,我将尝试明确地描述整个想法。所以我拥有的是一组所有都继承自一个基类的类。所有类几乎完全由不同的方法组成,这些方法仅在每个类中相关。但是,有几种方法具有相似的名称,一般功能和一些逻辑,但它们的实现仍然大多不同。所以我想知道的是,是否可以在基类中创建一个方法,该方法将执行一些类似于所有方法的逻辑,但仍然继续在特定于类的方法中执行。希望这是有道理的,但我会尝试给出我想要的基本例子。
因此,请考虑一个类似的基类:
class App(object):
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
def access(self):
LOGIC_SHARED
派生类:
的示例class App1(App):
def __init__(self, testName):
. . .
super(App1, self).__init__(testName)
def access(self):
LOGIC_SPECIFIC
所以我想要实现的是在调用任何的LOGIC_SHARED
方法时要执行的基类access
方法中的access
部分{}之前执行App
部分之前的LOGIC_SPECIFIC
类,这是(如其所说)特定于所有派生类的每个access
方法的部分。
如果这有任何区别,LOGIC_SHARED
主要包括日志记录和维护任务。
希望这很清楚,这个想法是有道理的。
注1 :
LOGIC_SHARED
部分中使用了特定于类的参数。
注意2 : 仅使用Python内置函数和模块来实现该行为非常重要。
注3 :
LOGIC_SHARED
部分看起来像这样:
try:
self.localLog.info("Checking the actual link for %s", self.application)
self.link = self.checkLink(self.application)
self.localLog.info("Actual link found!: %s", self.link)
except:
self.localLog.info("No links found. Going to use the default link: %s", self.link)
因此,我使用了很多特定的类实例属性,我不确定如何使用基类中的这些属性。
答案 0 :(得分:11)
当然,只需将特定逻辑放在自己的“私有”函数中,该函数可以被派生类覆盖,并将access
保留在Base中。
class Base(object):
def access(self):
# Shared logic 1
self._specific_logic()
# Shared logic 2
def _specific_logic(self):
# Nothing special to do in the base class
pass
# Or you could even raise an exception
raise Exception('Called access on Base class instance')
class DerivedA(Base):
# overrides Base implementation
def _specific_logic(self):
# DerivedA specific logic
class DerivedB(Base):
# overrides Base implementation
def _specific_logic(self):
# DerivedB specific logic
def test():
x = Base()
x.access() # Shared logic 1
# Shared logic 2
a = DerivedA()
a.access() # Shared logic 1
# Derived A specific logic
# Shared logic 2
b = DerivedB()
b.access() # Shared logic 1
# Derived B specific logic
# Shared logic 2
答案 1 :(得分:4)
执行所需操作的最简单方法是在子级access
方法中调用父级的access
方法。
class App(object):
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
def access(self):
LOGIC_SHARED
class App1(App):
def __init__(self, testName):
super(App1, self).__init__(testName)
def access(self):
App.access(self)
# or use super
super(App1, self).access()
但是,您的共享功能主要是日志记录和维护。除非有一个迫切的理由将它放在父类中,否则您可能要考虑将共享功能重构为装饰器函数。如果您想为类中的一系列方法重用类似的日志记录和维护功能,这将非常有用。
您可以在此处阅读有关函数修饰器的更多信息:http://www.artima.com/weblogs/viewpost.jsp?thread=240808,或者在Stack Overflow上阅读:How to make a chain of function decorators?。
def decorated(method):
def decorated_method(self, *args, **kwargs):
LOGIC_SHARED
method(self, *args, **kwargs)
return decorated_method
请记住,在python中,函数是第一类对象。这意味着您可以获取一个函数并将其作为参数传递给另一个函数。装饰器功能利用这一点。装饰器函数将另一个函数作为参数(此处称为方法),然后创建一个新函数(此处称为decorated_method),取代原始函数。
您的App1课程将如下所示:
class App1(App):
@logged
def access(self):
LOGIC_SPECIFIC
这确实是这方面的简写:
class App1(App):
def access(self):
LOGIC_SPECIFIC
decorated_access = logged(App.access)
App.access = decorated_access
我会发现这比向超类添加方法以捕获共享功能更优雅。
答案 2 :(得分:1)
如果我理解这个通知(How to execute BaseClass method before it gets overridden by DerivedClass method in Python)你希望传递给派生类中使用的父类的其他参数
你可以这样做
class Base(object):
def access(self,
param1 ,param2, #first common parameters
*args, #second positional parameters
**kwargs #third keyword arguments
):
# Shared logic 1
self._specific_logic(param1, param2, *args, **kwargs)
# Shared logic 2
def _specific_logic(self, param1, param2, *args, **kwargs):
# Nothing special to do in the base class
pass
# Or you could even raise an exception
raise Exception('Called access on Base class instance')
class DerivedA(Base):
# overrides Base implementation
def _specific_logic(self, param1, param2, param3):
# DerivedA specific logic
class DerivedB(Base):
# overrides Base implementation
def _specific_logic(self, param1, param2, param4):
# DerivedB specific logic
def test():
x = Base()
a = DerivedA()
a.access("param1", "param2", "param3") # Shared logic 1
# Derived A specific logic
# Shared logic 2
b = DerivedB()
b.access("param1", "param2", param4="param4") # Shared logic 1
# Derived B specific logic
# Shared logic 2
答案 3 :(得分:1)
我个人更喜欢Jonathon Reinhart的回答,但看到你似乎想要更多的选择,这里还有两个。我可能从不使用元类,虽然很酷,但我可能会考虑使用装饰器的第二个。
此方法使用基类的元类,它将强制首先调用基类的访问方法,而不需要单独的私有函数,也不必显式调用super
或类似的东西那。最终结果:没有额外的工作/代码进入继承类。
另外,它的作用类似于 maaaagiiiiic </spongebob>
以下是执行此操作的代码。在这里http://dbgr.cc/W,您可以直接浏览代码,看看它是如何工作的:
#!/usr/bin/env python
class ForceBaseClassFirst(type):
def __new__(cls, name, bases, attrs):
"""
"""
print("Creating class '%s'" % name)
def wrap_function(fn_name, base_fn, other_fn):
def new_fn(*args, **kwargs):
print("calling base '%s' function" % fn_name)
base_fn(*args, **kwargs)
print("calling other '%s' function" % fn_name)
other_fn(*args, **kwargs)
new_fn.__name__ = "wrapped_%s" % fn_name
return new_fn
if name != "BaseClass":
print("setting attrs['access'] to wrapped function")
attrs["access"] = wrap_function(
"access",
getattr(bases[0], "access", lambda: None),
attrs.setdefault("access", lambda: None)
)
return type.__new__(cls, name, bases, attrs)
class BaseClass(object):
__metaclass__ = ForceBaseClassFirst
def access(self):
print("in BaseClass access function")
class OtherClass(BaseClass):
def access(self):
print("in OtherClass access function")
print("OtherClass attributes:")
for k,v in OtherClass.__dict__.iteritems():
print("%15s: %r" % (k, v))
o = OtherClass()
print("Calling access on OtherClass instance")
print("-------------------------------------")
o.access()
这使用元类替换OtherClass
的访问功能,其功能包含对BaseClass
访问功能的调用以及对OtherClass
的调用的访问功能。请在此处查看元类的最佳解释https://stackoverflow.com/a/6581949。
单步执行代码应该可以帮助您理解事物的顺序。
此功能也可以轻松放入装饰器中,如下所示。同样,可以在此处找到以下代码的可执行/可调试/可运行版本http://dbgr.cc/0
#!/usr/bin/env python
def superfy(some_func):
def wrapped(self, *args, **kwargs):
# NOTE might need to be changed when dealing with
# multiple inheritance
base_fn = getattr(self.__class__.__bases__[0], some_func.__name__, lambda *args, **kwargs: None)
# bind the parent class' function and call it
base_fn.__get__(self, self.__class__)(*args, **kwargs)
# call the child class' function
some_func(self, *args, **kwargs)
wrapped.__name__ = "superfy(%s)" % some_func.__name__
return wrapped
class BaseClass(object):
def access(self):
print("in BaseClass access function")
class OtherClass(BaseClass):
@superfy
def access(self):
print("in OtherClass access function")
print("OtherClass attributes")
print("----------------------")
for k,v in OtherClass.__dict__.iteritems():
print("%15s: %r" % (k, v))
print("")
o = OtherClass()
print("Calling access on OtherClass instance")
print("-------------------------------------")
o.access()
上面的装饰者检索BaseClass
&#39;相同名称的功能,并在调用OtherClass
之前先调用&#39;功能
答案 4 :(得分:1)
这种简单的方法可以提供帮助。
class App:
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
self.application = None
self.link = None
def access(self):
print('There is something BaseClass must do')
print('The application is ', self.application)
print('The link is ', self.link)
class App1(App):
def __init__(self, testName):
# ...
super(App1, self).__init__(testName)
def access(self):
self.application = 'Application created by App1'
self.link = 'Link created by App1'
super(App1, self).access()
print('There is something App1 must do')
class App2(App):
def __init__(self, testName):
# ...
super(App2, self).__init__(testName)
def access(self):
self.application = 'Application created by App2'
self.link = 'Link created by App2'
super(App2, self).access()
print('There is something App2 must do')
和测试结果:
>>>
>>> app = App('Baseclass')
>>> app.access()
There is something BaseClass must do
The application is None
The link is None
>>> app1 = App1('App1 test')
>>> app1.access()
There is something BaseClass must do
The application is Application created by App1
The link is Link created by App1
There is something App1 must do
>>> app2 = App2('App2 text')
>>> app2.access()
There is something BaseClass must do
The application is Application created by App2
The link is Link created by App2
There is something App2 must do
>>>
答案 5 :(得分:0)
添加一个组合功能,我们可以组合两个功能并一个接一个地执行它们,如下所示
def combine(*fun):
def new(*s):
for i in fun:
i(*s)
return new
class base():
def x(self,i):
print 'i',i
class derived(base):
def x(self,i):
print 'i*i',i*i
x=combine(base.x,x)
new_obj=derived():
new_obj.x(3)
输出Bellow
i 3
i*i 9
它不必是单级层次结构,它可以具有任意数量的级别或嵌套