如何在Python中重写实例级的实例方法而不替换它? 描述
我的问题与提出的问题非常相似,但有一个区别:我不想直接编辑或替换原始类实例中的任何内容 所以,基本上,假设我们有一个定义为如何在Python中重写实例级的实例方法而不替换它? 描述,python,methods,overriding,instance,Python,Methods,Overriding,Instance,我的问题与提出的问题非常相似,但有一个区别:我不想直接编辑或替换原始类实例中的任何内容 所以,基本上,假设我们有一个定义为 class Class1(object): """ This is Class1. """ def __init__(self, name): self.name = name def a(self): "Method a" return("This is the Class1 a
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()
-方法被替换为
def b(self):
return('This is the new Class1 b()-method!')
此对象的其他所有内容必须与提供的实例中的内容完全相同,以便新对象可以在旧对象可以使用的任何位置使用。
基本上就好像Class1
(或任何使用过的子类)的定义已经使用了b()
的这个定义
尝试
所以,我已经尝试了一些方法,但每一种方法都至少有一个我不喜欢的问题。
请注意,我省略了任何检查,以查看提供的对象是否确实是Class1
类或任何派生子类的实例,因为它不会向我的描述中添加任何内容
我尝试使用给出的解决方案,得到以下结果:
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\u obj
中的b()
-方法。
因此,一旦调用了get_new_Class1_obj()
-函数,原始的Class1_obj
就不能再在其原始状态下使用。
这是一个问题,对于我拥有的应用程序,我实际上要求原始的b()
-方法仍然可用(在本例中,我只是没有使用这样的方法来保持它的简单性)
我尝试的另一种方法是使用类工厂(我已经尝试了几种不同的版本,下面可能是最接近我想要的): 这也非常接近我想要的(尽管不断更新
override\u attrs
列表很烦人),如果我想要的话,我现在可以在新的\u class1\u obj
中使用原始的class1\u obj
。
然而,这里的问题是new_class1_obj
的bb()
-方法不能正常工作,因为它将使用class1_obj的b()
-方法,而不是new_class1_obj
的方法。
据我所知,如果不知道方法bb()
以这样的形式存在,就无法强制执行此操作。
由于可能有人将Class1
子类化,并引入调用b()
的c()
-方法,因此此解决方案将无法正常工作(而第一个解决方案可以正常工作)
在这里不子类化Class1
可以消除一些麻烦,但这也意味着像isinstance
这样的函数不再正常工作,而不能用bb()
-方法解决问题
解决方案
因此,我目前无法找到解决方案(我已经尝试了几天)。
我正在考虑使用我的第一次尝试解决方案,但我没有立即替换b()
-方法,而是首先将b()
分配给\u old\u b()
或\u 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>
我不是很确定你想要什么,但是下面这个合适吗?(文件test.py在python 3.7.3中测试正常)
此代码将返回:
$ python test.py
are insts same? 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!')
这是你想要的吗
我回顾了我的答案,在我看来,这一次接近你上面的例子。您对此有何看法?我不知道这是否是您想要的,但下面的代码具有与您的示例相同的输出:
import copy
class ComplexObject: # Equivalent of old Class1, but with no methods
def __init__(self, name):
self.name = name
self.other_member = 'other, but could be intracomm'
class Class1(object):
def __init__(self, fwd):
self.fwd = fwd # All the interesting data is in this instance
def get_name(self):
return self.fwd.name # Need to go through fwd to get at data
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 function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
def b(self):
# Return both old and new b() output
return(class1_obj.b(), "This is the new Class1 b()-method!")
new_instance = copy.copy(class1_obj)
def b_wrapper():
return b(new_instance)
new_instance.b = b_wrapper
return new_instance
complex=ComplexObject('TEST')
class1_obj = Class1(complex)
new_class1_obj = get_new_Class1_obj(class1_obj)
print("are insts same? ",class1_obj is new_class1_obj)
print("class1_obj.name",class1_obj.get_name())
print("class1_obj.a():",class1_obj.a())
print("class1_obj.b():",class1_obj.b())
print("class1_obj.bb():",class1_obj.bb())
print("new_class1_obj.name",new_class1_obj.get_name())
print("new_class1_obj.a():",new_class1_obj.a())
print("new_class1_obj.b():",new_class1_obj.b())
print("new_class1_obj.bb():",new_class1_obj.bb())
#Change some of the interesting data
class1_obj.fwd.name='FOO'
print("class1_obj.name",class1_obj.get_name())
print("new_class1_obj.name",new_class1_obj.get_name())
输出:
are insts same? 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 FOO
new_class1_obj.name FOO
您可以看到,有趣数据中的更改会影响这两个类。可能的解决方案
在查看了由给出的答案后,我提出了一个可能的解决方案,但我希望得到一些反馈:
from types import MethodType
# 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 function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
# Obtain list of all properties that class1_obj has that are not methods
props = [prop for prop in dir(class1_obj)
if not isinstance(getattr(class1_obj, prop), MethodType)]
# Make a subclass of the class used for class1_obj
class new_Class1(class1_obj.__class__, object):
# Empty __init__ as no initialization is required
def __init__(self):
pass
# If requested attribute is not a method, use class1_obj for that
def __getattribute__(self, name):
if name in props:
return(getattr(class1_obj, name))
else:
return(super().__getattribute__(name))
# If requested attribute is not a method, use class1_obj for that
def __setattr__(self, name, value):
if name in props:
setattr(class1_obj, name, value)
else:
super().__setattr__(name, value)
# Use the __dir__ of class1_obj
def __dir__(self):
return(dir(class1_obj))
# 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!")
# Initialize new_Class1
new_class1_obj = new_Class1()
# Return it
return(new_class1_obj)
这里的所有输出都是我想要的输出。
我仍然不确定是否希望new_class1_obj
中的非方法更改影响class1_obj
,但我可以通过简单地不重写\uuuu setattr_uu()
轻松地删除它。
上述操作还确保向new_class1_obj
添加新属性不会影响class1_obj
。
如果我真的想让相反的方法发挥作用,我可以在\uuuu getattribute\uuuuuuuu
中添加确定的道具(在class1\u obj
中添加一个新属性会影响new\u class1\u obj
)。在什么情况下/如何调用class1\u obj
的原始b()
函数?也许这会让我们对如何proceed@CodelessBugging例如,如果用户希望同时使用class1\u obj
和new\u class1\u obj
。但是,我还要求可以从new\u class1\u obj
调用原始的b()
-方法。编辑:我添加了一个示例。您的问题似乎源于bb()
方法,它仍然需要在原始实例或新实例中调用旧的b()
方法,但新实例上的任何外部调用程序都将重定向到新的b()
。似乎您应该直接在类中对此进行建模。@quamrana不,我希望bb()
-m
import copy
class ComplexObject: # Equivalent of old Class1, but with no methods
def __init__(self, name):
self.name = name
self.other_member = 'other, but could be intracomm'
class Class1(object):
def __init__(self, fwd):
self.fwd = fwd # All the interesting data is in this instance
def get_name(self):
return self.fwd.name # Need to go through fwd to get at data
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 function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
def b(self):
# Return both old and new b() output
return(class1_obj.b(), "This is the new Class1 b()-method!")
new_instance = copy.copy(class1_obj)
def b_wrapper():
return b(new_instance)
new_instance.b = b_wrapper
return new_instance
complex=ComplexObject('TEST')
class1_obj = Class1(complex)
new_class1_obj = get_new_Class1_obj(class1_obj)
print("are insts same? ",class1_obj is new_class1_obj)
print("class1_obj.name",class1_obj.get_name())
print("class1_obj.a():",class1_obj.a())
print("class1_obj.b():",class1_obj.b())
print("class1_obj.bb():",class1_obj.bb())
print("new_class1_obj.name",new_class1_obj.get_name())
print("new_class1_obj.a():",new_class1_obj.a())
print("new_class1_obj.b():",new_class1_obj.b())
print("new_class1_obj.bb():",new_class1_obj.bb())
#Change some of the interesting data
class1_obj.fwd.name='FOO'
print("class1_obj.name",class1_obj.get_name())
print("new_class1_obj.name",new_class1_obj.get_name())
are insts same? 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 FOO
new_class1_obj.name FOO
from types import MethodType
# 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 function that returns new Class1 object
def get_new_Class1_obj(class1_obj):
# Obtain list of all properties that class1_obj has that are not methods
props = [prop for prop in dir(class1_obj)
if not isinstance(getattr(class1_obj, prop), MethodType)]
# Make a subclass of the class used for class1_obj
class new_Class1(class1_obj.__class__, object):
# Empty __init__ as no initialization is required
def __init__(self):
pass
# If requested attribute is not a method, use class1_obj for that
def __getattribute__(self, name):
if name in props:
return(getattr(class1_obj, name))
else:
return(super().__getattribute__(name))
# If requested attribute is not a method, use class1_obj for that
def __setattr__(self, name, value):
if name in props:
setattr(class1_obj, name, value)
else:
super().__setattr__(name, value)
# Use the __dir__ of class1_obj
def __dir__(self):
return(dir(class1_obj))
# 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!")
# Initialize new_Class1
new_class1_obj = new_Class1()
# Return it
return(new_class1_obj)
# Do testing
if __name__ == '__main__':
# Initialize instances
class1_obj = Class1('TEST')
new_class1_obj = get_new_Class1_obj(class1_obj)
# Check that instances are not the same
print(class1_obj is new_class1_obj)
# Check outputs of class1_obj
print(class1_obj.name)
print(class1_obj.a())
print(class1_obj.b())
print(class1_obj.bb())
# Check outputs of new_class1_obj
print(new_class1_obj.name)
print(new_class1_obj.a())
print(new_class1_obj.b())
print(new_class1_obj.bb())
# Check that non-method changes in class1_obj affect new_class1_obj
class1_obj.name = 'TEST2'
print(class1_obj.name)
print(new_class1_obj.name)
# Check that non-method changes in new_class1_obj affect class1_obj
new_class1_obj.name = 'TEST3'
print(class1_obj.name)
print(new_class1_obj.name)