简体   繁体   中英

How to "wrap" object to automatically call superclass method instead of overriden ones?

Consider:

class A(object):
    def f(self): print("A")

class B(A):
    def f(self): print("B")

b = B()

I can call Af on b by doing:

A.f(b)

Is there an easy way to "wrap" b such that wrap(b).f() calls Af for any f ?

Here is my solution which copies the methods from the most upper base class:

import types, copy

def get_all_method_names(clazz):
  return [func for func in dir(clazz) if callable(getattr(clazz, func))]

def wrap(obj):
  obj = copy.copy(obj)
  obj_clazz = obj.__class__
  base_clazz = obj_clazz.__bases__[-1] # the one which directly inherits from object
  base_methods = get_all_method_names(base_clazz) # list of all method names in base_clazz
  for base_method_name in base_methods:
    base_method = getattr(base_clazz, base_method_name) # get the method object
    if isinstance(base_method, types.FunctionType): # skip dunder methods like __class__, __init__
      setattr(obj, base_method_name, base_method) # copy it into our object
  return obj

# class declaration from question here

wrapped_b = wrap(b)

wrapped_b.f(wrapped_b) # prints A, unfortunately we have to pass the self parameter explicitly
b.f() # prints B, proof that the original object is untouched

This feels dirty to me, but it also seems to work. I'm not sure I'd rely on this for anything important.

import copy

def upcast(obj, clazz):
    if not isinstance(obj, clazz):  # make sure we're actually "upcasting"
        raise TypeError()
    wrapped = copy.copy(obj)
    wrapped.__class__ = clazz
    return wrapped

This results in

>>> a = A()
>>> a.f()
A
>>> b = B()
>>> b.f()
B
>>> upcast(b, A).f()
A

What I've really done here is essentially monkey-patch a clone of b and lied to it and told it it's actually an A , so when it comes time to resolve which version of f to call, it'll call the one from A .

Object Slicing is not supported in python the way it is done in C++ (The link you are pointing to takes a cpp example). In Python Object Slicing is a rather different thing which means to slice up any object which supports sequence protocol (implements getitem () and len () methods). Example :

    A = [1,2,3,4,5,6,7,8]
    print(A[1:3])

But in C++ Object Slicing is just cutting off the properties added by a base class instance when assigned to a parent class variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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