Reputation: 136
Here is the code:
class A: pass
class B: pass
class Example(A, B): pass
...a lot of method
# new class B called BPlus
class BPlus: pass
# want a new class Example that base on (A, BPlus) but not copy old Example's method.
class Example(A, BPlus)
...here do not copy method
# try change __base__ but got 'readonly attribute' error
Example.__bases__ = (A, BPlus)
How to change base class without copy duplicate code.
Why I want this?
I am using pymysql, and need to intercept each operation to record some info. I define a class base on pymysql.cursors.Cursor
and overwrite __getattribute__
method in the class to intercept execute
method.
from pymysql.cursors import Cursors as RawCurors
class Cursor(RawCursor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __getattribute__(self, item):
"""Here I intercept `execute` method OK""
pass
Now, it work well when I set pymysql.Connection's param cursorclass=Cursor. Some time I need to use DictCursor. It is defined very sample in pymysql's source code. I can still copy to implement.
from pymysql.cursors import DictCursorMixin
# note that Cursor is the new I defined above
class DictCursor(DictCursorMixin, Cursor):
pass
But it is not easy to define SSDictCursor. It is base on SSCursor and DictCursorMixin, and SSCursor has many methods. SSCursor is based on Cursor. I want to replace SSCursor baseclass from RawCurors to Cursor and define the new SSDictCursor.
# the old class
class SSCursor(RawCurors):
# here has many methods
pass
class SSDictCursor(DictCursorMixin, SSCursor):
pass
And if there is way to replace SSCursor's base to Cursor without define new class?
Upvotes: 0
Views: 79
Reputation: 110516
Your question is not easy to read in the current form, but it does have a short answer:
You can change the __bases__
attribute of a Python defined class as long as none of the old or new bases have a "different layout" - meaning that their definition at built-in level does not have different fields, and they don't use __slots__
.
So, using your naming, but actually with a syntactically valid snippet:
class A:
...
class B:
...
class BPlus(B):
def test(self):
print(42)
...
class Example(A, B):
...
print(Example.__bases__)
# (A, B)
A.__bases__ = A, BPlus
print(Example.__bases__)
# (A, BPlus)
Example().test()
# 42
However keep in mind that beyond learning and playing around purposes this would HARDLY have any application in any kind of "real world" code. Even extremely dynamic code (say, code which would create new classes based on externally obtained data, at run time), would be better creating new classes dynamically, not modifying existing ones. (Which will change the behavior of existing objects "mid flight".
To create a new, Example2
class, at run time, with the new bases, you can use the type
call:
Example2 = type('Example2', (A, BPlus), {})
Upvotes: 2