3

(How) Is it possible in Python to treat an instance of class B exactly as an instance of class A, where A is a parent of B (like up-casting in compiled languages)?

Say we have the following:

class A:
    def __init__(self, prop=None):
        self.prop = prop

    def f(self):
        return 'A.f'

    def g(self):
        return 'A.g', self.f()


class B(A):
    def f(self):
        return 'B.f'

    def g(self):
        return 'B.g', self.f()

Calling A().g() produces ('A.g', 'A.f'), whereas B().g() produces ('B.g', 'B.f'). Calling super(B, B()).g() produces ('A.g', 'B.f'), which is different from compiled languages, so I cannot use super. Instead, I need a function that changes the type from which an instance's methods are resolved, but preserves (a reference to) the original state. In short, I'm looking for a way to do this:

b = B(object())
a = upcast(b, A)
a.prop = object()

assert isinstance(a, A)
assert a.g() == ('A.g', 'A.f')
assert a.prop is b.prop

The closest I could get is

a = copy.copy(b)
a.__class__ = A
a.__dict__ = b.__dict__

(assuming A/B are "nice" "heap" classes), but this makes unnecessary copies of all objects in the __dict__ before I discard them. Is there a better way to do this?

  • 1
    First off, change `super(type(B), B()).g()` to `super(B, B()).g()` because second argument of super should be an instance of(or subtype of) the first agrument. – S.B May 20 '21 at 14:44
  • @SorousHBakhtiary, you're right, it was a typo (I had b=B() and I messed up the copying) – kosiokarchev May 20 '21 at 21:42
  • I'd question whether you really need to do this. Instance attributes don't belong to one class or another; there's no `A.prop` and `B.prop`, just a single instance attribute that happens to be initialized by `A.__init__`. (As a result, `a.prop is b.prop` is always true as long as `a is b` is true.) – chepner May 20 '21 at 21:49
  • @chepner, however, I won't have `a is b` just as a pointer to A is not technically the same as a pointer to B, even if they reference the same location. And the idea of casting is that you don't change any of the memory, you just interpret what you find there, that's why I think it's nice to have the casted object point to the same objects as the original. – kosiokarchev May 20 '21 at 23:18
  • 1
    Python's semantics don't work that way. Objects aren't just random bits to be interpreted; they are distinct objects that have a type as an intrinsic attribute. – chepner May 21 '21 at 01:19

0 Answers0