Cast base class to derived class python (or more pythonic way of extending classes)
If you are just adding behavior, and not depending on additional instance values, you can assign to the object's __class__
:
from math import pi
class Circle(object):
def __init__(self, radius):
self.radius = radius
def area(self):
return pi * self.radius**2
class CirclePlus(Circle):
def diameter(self):
return self.radius*2
def circumference(self):
return self.radius*2*pi
c = Circle(10)
print c.radius
print c.area()
print repr(c)
c.__class__ = CirclePlus
print c.diameter()
print c.circumference()
print repr(c)
Prints:
10
314.159265359
<__main__.Circle object at 0x00A0E270>
20
62.8318530718
<__main__.CirclePlus object at 0x00A0E270>
This is as close to a "cast" as you can get in Python, and like casting in C, it is not to be done without giving the matter some thought. I've posted a fairly limited example, but if you can stay within the constraints (just add behavior, no new instance vars), then this might help address your problem.
What's the pythonic way to add behavior to objects returned by an external module?
You can rewrite this in a more dynamic manner:
from other_module import Foo, FooTypeA, FooTypeB
bases = [Foo, FooTypeA, FooTypeB]
class MyMixin(object):
pass
def factory(bases, mixins, name='MyClass'):
return type(name, bases + mixins, {})
new_classes = [factory((c,), (MyMixin,)) for c in bases]
Copying values from the object of base class in Python
That is not how to do inheritance. You're passing an instance of the base class to the __init__
of the derived class, which is completely unrelated to inheriting its attributes. Instead, do:
class Base():
def __init__(self):
self.a = 10
class Derived(Base):
def __init__(self):
super(Derived, self).__init__() # calls Base.__init__
self.b = 'abc'
def main():
base = Base()
derived = Derived()
How to cast object in Python
There is no casting as the other answers already explained. You can make subclasses or make modified new types with the extra functionality using decorators.
Here's a complete example (credit to How to make a chain of function decorators?). You do not need to modify your original classes. In my example the original class is called Working.
# decorator for logging
def logging(func):
def wrapper(*args, **kwargs):
print func.__name__, args, kwargs
res = func(*args, **kwargs)
return res
return wrapper
# this is some example class you do not want to/can not modify
class Working:
def Do(c):
print("I am working")
def pr(c,printit): # other example method
print(printit)
def bla(c): # other example method
c.pr("saybla")
# this is how to make a new class with some methods logged:
class MutantWorking(Working):
pr=logging(Working.pr)
bla=logging(Working.bla)
Do=logging(Working.Do)
h=MutantWorking()
h.bla()
h.pr("Working")
h.Do()
this will print
h.bla()
bla (<__main__.MutantWorking instance at 0xb776b78c>,) {}
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'saybla') {}
saybla
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'Working') {}
Working
Do (<__main__.MutantWorking instance at 0xb776b78c>,) {}
I am working
In addition, I would like to understand why you can not modify a class. Did you try? Because, as an alternative to making a subclass, if you feel dynamic you can almost always modify an old class in place:
Working.Do=logging(Working.Do)
ReturnStatement.Act=logging(ReturnStatement.Act)
Update: Apply logging to all methods of a class
As you now specifically asked for this. You can loop over all members and apply logging to them all. But you need to define a rule for what kind of members to modify. The example below excludes any method with __ in its name .
import types
def hasmethod(obj, name):
return hasattr(obj, name) and type(getattr(obj, name)) == types.MethodType
def loggify(theclass):
for x in filter(lambda x:"__" not in x, dir(theclass)):
if hasmethod(theclass,x):
print(x)
setattr(theclass,x,logging(getattr(theclass,x)))
return theclass
With this all you have to do to make a new logged version of a class is:
@loggify
class loggedWorker(Working): pass
Or modify an existing class in place:
loggify(Working)
Universally create Derived class from Base in python
You can use inheritance:
class FileProxyGetter(ProxyGetter):
...
def MakeProxy(self, *args, **kwargs):
return Proxy.fromstring(*args, **kwargs)
def Get(self):
...
proxies.append(self.MakeProxy(l[:-1]))
...
...
class FileSecureProxyGetter(FileProxyGetter):
def MakeProxy(self, *args, **kwargs):
return SecureProxy.fromstring(*args, **kwargs)
but it's probably more useful in this case to use composition.
class FileProxyGetter(ProxyGetter):
def __init__(self, proxyclass, fname = "d:\\proxies.txt"):
self.proxyClass = proxyclass
self.fileName = fname
...
def Get(self):
...
proxies.append(self.proxyclass.fromstring(l[:-1]))
...
...
# use this as such
FileProxyGetter(Proxy, "proxies.txt")
FileProxyGetter(SecureProxy, "secure_proxies.txt")
EDIT: A dirty trick in python to switch the type of an object:
>>> class A(object):
... def foo(self):
... print 'hello A'
...
>>> class B(object):
... def foo(self):
... print 'hello B'
...
>>> a = A()
>>> a.foo()
hello A
>>> a.__class__
<class '__main__.A'>
>>> a.__class__ = B
>>> a.foo()
hello B
Another dirty trick for two objects of different types to share the same state:
>>> class B(object):
... def rename(self, name):
... self.name = name
...
>>> class A(object):
... def say(self):
... print 'Hello', self.name
...
>>> a, b = A(), B()
>>> a.__dict__ = b.__dict__
>>> b.rename('john')
>>> a.say()
Hello john
>>> a.rename('mary')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'rename'
>>> b.say()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute 'say'
However, these tricks, while possible in Python, I would not call them pythonic nor a good OO design.
Another possibility in Python 3.x and up, which had removed "unbound method" in place of using regular function:
>>> class A(object):
... def say(self):
... print('Hello', self.name)
...
>>> class B(object):
... def rename(self, name):
... self.name = name + name
...
>>> a = A()
>>> B.rename(a, 'josh')
>>> a.say()
Hello joshjosh
Related Topics
How to Implement the Softmax Function in Python
How to Dynamically Add/Remove Periodic Tasks to Celery (Celerybeat)
Matplotlib Log Scale Tick Label Number Formatting
How to Remove an Element in Lxml
Why Not Generate the Secret Key Every Time Flask Starts
How to Detect the Python Version at Runtime
Right Way to Reverse a Pandas Dataframe
Is There a Generator Version of 'String.Split()' in Python
How to Open a Website in My Web Browser Using Python
Ssl Insecureplatform Error When Using Requests Package
How to Write a File or Data to an S3 Object Using Boto3
Algorithm to Find Which Number in a List Sum Up to a Certain Number
Error: 'Int' Object Is Not Subscriptable - Python
Changing Iteration Variable Inside for Loop in Python