Extending builtin classes in python
Solution 1
Just subclass the type
>>> class X(str):
... def my_method(self):
... return int(self)
...
>>> s = X("Hi Mom")
>>> s.lower()
'hi mom'
>>> s.my_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in my_method
ValueError: invalid literal for int() with base 10: 'Hi Mom'
>>> z = X("271828")
>>> z.lower()
'271828'
>>> z.my_method()
271828
Solution 2
One way could be to use the "class reopening" concept (natively existing in Ruby) that can be implemented in Python using a class decorator. An exemple is given in this page: http://www.ianbicking.org/blog/2007/08/opening-python-classes.html
I quote:
I think with class decorators you could do this:
@extend(SomeClassThatAlreadyExists)
class SomeClassThatAlreadyExists:
def some_method(self, blahblahblah):
stuff
Implemented like this:
def extend(class_to_extend):
def decorator(extending_class):
class_to_extend.__dict__.update(extending_class.__dict__)
return class_to_extend
return decorator
Solution 3
Assuming that you can not change builtin classes.
To simulate a "class reopening" like Ruby in Python3 where __dict__
is an mappingproxy object and not dict object :
def open(cls):
def update(extension):
for k,v in extension.__dict__.items():
if k != '__dict__':
setattr(cls,k,v)
return cls
return update
class A(object):
def hello(self):
print('Hello!')
A().hello() #=> Hello!
#reopen class A
@open(A)
class A(object):
def hello(self):
print('New hello!')
def bye(self):
print('Bye bye')
A().hello() #=> New hello!
A().bye() #=> Bye bye
In Python2 I could also write a decorator function 'open' as well:
def open(cls):
def update(extension):
namespace = dict(cls.__dict__)
namespace.update(dict(extension.__dict__))
return type(cls.__name__,cls.__bases__,namespace)
return update
UnkwnTech
The desire to attempt the impossible is a key trait of most great programmers.
Updated on January 22, 2021Comments
-
UnkwnTech over 3 years
How can I extend a builtin class in python? I would like to add a method to the str class.
I've done some searching but all I'm finding is older posts, I'm hoping someone knows of something newer. -
UnkwnTech over 15 yearsI was hoping that I wouldn't have to subclass but after some more research I have come to the conclusion that it is not possible any other way, so I'll accept this answer.
-
user1066101 over 15 years@Unkwntech: Can't imagine a better way than subclassing. Seriously. Whatever you had in mind (monkeypatching?) never seems to work out as well as a clear, precise, obvious subclass.
-
orip over 15 years@S.Lott - Ruby's open classes and C#'s extension methods come to mind.
-
user1066101 over 15 years@orip: Aware of these. Find monkeypatching in all forms to be a management nightmare -- they effectively prevent reuse by injecting features in obscure ways.
-
dagfr almost 4 yearsIn this sample type(z.lower()) is str an not X. How to keep it an X ?
-
GalacticRaph over 3 years@dagfr by overriding the .lower() method in the X class and returning a new X object
-
caram over 3 yearsPython 3.9,
__dict__
is no longer adict
but amappingproxy
, you have to use @MVP's solution instead. -
caram over 3 yearsAt last I can do this like in Ruby. Works like a charm. I prefer the second definition.