【发布时间】:2019-09-19 21:29:48
【问题描述】:
说明
我的问题与here 提出的问题非常相似,但有一个区别:我不想直接编辑或替换原始类实例中的任何内容。
所以,基本上,假设我们有一个类定义为
class Class1(object):
"""
This is Class1.
"""
def __init__(self, name):
self.name = name
def a(self):
"Method a"
return("This is the Class1 a()-method!")
def b(self):
"Method b"
return("This is the Class1 b()-method!")
def bb(self):
"Method bb"
return(self.b())
现在我想做的是创建一个用户可以调用的函数,它为我提供了Class1(或任何派生子类)的实例。
然后,我返回一个行为与提供的实例完全相同的对象,除了 b()-method 已替换为
def b(self):
return('This is the new Class1 b()-method!')
关于此对象的其他所有内容都必须与提供的实例中的完全相同,以便新对象可以在旧对象可以使用的任何地方使用。
基本上就好像Class1(或任何使用的子类)的定义已经使用了b()的这个定义。
尝试
所以,我已经尝试了几件事,但每一件事都至少有一个我不喜欢的问题。
请注意,我省略了任何检查以查看提供的对象是否确实是 Class1 类或任何派生子类的实例,因为它不会对我的描述添加任何内容。
我尝试使用here 提供的解决方案,结果如下:
from types import MethodType
# Define handy decorator for overriding instance methods
def override_method(instance):
def do_override(method):
setattr(instance, method.__name__, MethodType(method, instance))
return(do_override)
# Define function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
# Override b-method
@override_method(class1_obj)
def b(self):
return('This is the new Class1 b()-method!')
# Return it
return(class1_obj)
这个解决方案基本上可以满足我的所有需求,只是它直接用新定义替换了提供的class1_obj 中的b()-方法。
因此,一旦调用了get_new_Class1_obj()-函数,原来的class1_obj就不能再以其原始状态使用。
这是一个问题,至于我的应用程序,我实际上要求原来的b()-方法仍然可用(我只是在这个例子中没有使用这样的东西来保持它有点简单)。
我尝试这样做的另一种方法是使用类工厂(我已经尝试了几个不同的版本,下面可能是最接近我想要的):
# Define function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
# Define list with all methods that are overridden
override_attrs = ['__init__', '__getattribute__', '__dir__', 'b']
# Make a subclass of the class used for class1_obj
# This is required for functions like 'isinstance'
class new_Class1(class1_obj.__class__, object):
# Empty __init__ as no initialization is required
def __init__(self):
pass
# Make sure only overridden attributes are used from this class
def __getattribute__(self, name):
if name in override_attrs:
return(super().__getattribute__(name))
else:
return(getattr(class1_obj, name))
# Use the __dir__ of class1_obj
def __dir__(self):
return(dir(class1_obj))
# Override b-method
def b(self):
return("This is the new Class1 b()-method!")
# Initialize new_Class1
new_class1_obj = new_Class1()
# Return it
return(new_class1_obj)
这也非常接近我想要的(尽管不断更新override_attrs 列表很烦人),如果我愿意,我现在可以在new_class1_obj 中使用原始class1_obj。
但是,这里的问题是new_class1_obj 的bb() 方法将无法正常工作,因为它将使用class1_obj 的b() 方法而不是new_class1_obj 的方法之一。
据我所知,如果不知道bb() 方法以这样的形式存在,就无法强制执行此操作。
由于可能有人继承了Class1 并引入了一个调用b() 的c() 方法,因此该解决方案将无法正常工作(而第一个解决方案可以正常工作)。
这里不继承Class1 会消除一些烦恼,但这也意味着isinstance 之类的函数不再正常工作,同时不能用bb() 方法解决问题。
解决方案?
所以,我目前无法为此提出解决方案(我已经尝试了几天)。
我正在考虑使用我的第一次尝试解决方案,但不是立即替换b()-方法,而是首先将b() 分配给_old_b() 或_b()(显然确保它不存在)然后替换b()。
我不是很喜欢那个解决方案,因为它仍然让我觉得太老套和肮脏。
那么,有人对此有想法吗? 在我看来,这听起来是一个非常简单的问题:我有一个实例,我想用一个新的实例方法更新它的一个实例方法,而不修改原始实例。 但是,这似乎并没有那么简单。
示例
一个完整的例子是:
# Define original Class1 class
class Class1(object):
"""
This is Class1.
"""
def __init__(self, name):
self.name = name
def a(self):
"Method a"
return("This is the Class1 a()-method!")
def b(self):
"Method b"
return("This is the Class1 b()-method!")
def bb(self):
"Method bb"
return(self.b())
# Define new b()-method
def b(self):
# Return both old and new b() output
return(class1_obj.b(), "This is the new Class1 b()-method!")
# Define function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
<code involving getting new_class1_obj>
# Use with expected outputs
>>> class1_obj = Class1('TEST')
>>> new_class1_obj = get_new_Class1_obj(class1_obj)
>>> class1_obj is new_class1_obj
False
>>> class1_obj.name
'TEST'
>>> class1_obj.a()
"This is the Class1 a()-method!"
>>> class1_obj.b()
"This is the Class1 b()-method!"
>>> class1_obj.bb()
"This is the Class1 b()-method!"
>>> new_class1_obj.name
'TEST'
>>> new_class1_obj.a()
"This is the Class1 a()-method!"
>>> new_class1_obj.b()
("This is the Class1 b()-method!", "This is the new Class1 b()-method!")
>>> new_class1_obj.bb()
("This is the Class1 b()-method!", "This is the new Class1 b()-method!")
>>> class1_obj.name = 'TEST2'
>>> class1_obj.name
'TEST2'
>>> new_class1_obj.name
'TEST2'
【问题讨论】:
-
在什么情况下/如何调用
class1_obj的原始b()函数?也许这会给我们一个关于如何进行的想法 -
@CodelessBugging 好吧,例如,如果用户想同时使用
class1_obj和new_class1_obj。但是,我还要求可以从new_class1_obj调用原始的b()-方法。编辑:我添加了一个例子。 -
您的问题似乎源于
bb()方法,无论是在原始实例还是新实例中,它仍然需要调用旧的b()方法,但新实例上的任何外部调用者都是重定向到新的b()。看来你应该直接在类中建模。 -
@quamrana 不,我希望
new_class1_obj中的bb()方法使用新的b()方法,而不是旧方法。只有new_class1_obj本身定义的方法才允许使用旧的b()-method。 -
我有一个实例,我想用一个新的实例方法更新它的一个实例方法,而不修改原始实例。 存在矛盾。更新实例方法意味着修改实例。
标签: python methods overriding instance