Decide baseclass at runtime - python

I want to do something like this:
class A:
def methodA(self):
return 5
class B:
def methodB(self):
return 10
class X(...):
def __init__(self, baseclass):
if baseclass =='A' : derive X from A
elif baseclass == 'B' : derive X from B
else: raise Exception("Not supported baseclass %s!" % (baseclass))
def methodX(self):
return 42
X('A').methodA() # returns 5
X('A').methodX() # returns 42
X('A').methodB() # methodB not defined
X('B').methodB() # returns 10
X('B').methodX() # returns 42
X('A').methodA() # methodA not defined
How can I implement this?

If you want to add methodX to the existing classes, you could consider multiple inheritance:
class A:
def methodA(self):
return 5
class B:
def methodB(self):
return 10
class X():
#classmethod
def new(cls, baseclass):
if baseclass == A:
return AX()
elif baseclass == B:
return BX()
else: raise Exception("Not supported baseclass %s!" % str(baseclass))
def methodX(self):
return 42
class AX(A, X):
pass
class BX(B, X):
pass
You can add args and kwargs to X.new and pass them on to the specific constructors. Here are the outputs of your tests (I corrected the last on in your question):
>>> ax = X.new(A)
>>> ax.methodA() # returns 5
5
>>> ax.methodX() # returns 42
42
>>> ax.methodB() # methodB not defined
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: AX instance has no attribute 'methodB'
>>> bx = X.new(B)
>>> bx.methodB() # returns 10
10
>>> bx.new(B).methodX() # returns 42
42
>>> bx.new(B).methodA() # methodA not defined
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: BX instance has no attribute 'methodA'

You should define two classes, X and Y, and a factory-method to instantiate either X or Y, depending on a parameter.
In general, the behavior you try to implement is somewhat confusing. When you create an instance (that is what X(...) does) you should get an instance of X, and instances of a class should have same attributes. That is one of the main reasons why classes exist.
Example:
class A:
def methodA(self):
return 5
class B:
def methodB(self):
return 10
def x(class_name):
name2class = {"A":A, "B":B}
return name2class[class_name]()
for name in ["A","B","C"]:
instance = x(name)
print name, instance
will print
A <__main__.A instance at 0x022C8D50>
B <__main__.B instance at 0x022C8DF0>
Traceback (most recent call last):
File ".../14834949.py", line 21, in <module>
instance = x(name)
File ".../14834949.py", line 18, in x
return name2class[class_name]()
KeyError: 'C'

Related

Accessing attribute from parent class inside child class

When I access an attribute from the parent class via the child class like this all works fine:
class A():
a=1
b=2
class B(A):
c=3
d=B.a+B.b+B.c
print d
But if I try to access an attribute from the parent class inside the child class like this, it doesn't work:
class A():
a=1
b=2
class B(A):
c=3
d=a+b+c
print d
I receive the error: name 'a' is not defined
Let assume that I have many equation like d=a+b+c (but more complicated) and I can't edit them - I have to call in class B "a" as "a", not "self.a" or "something.a". But I can, before equations, do A.a=a. But it is not the smartest way to reload all variables manually. I want to bypass it using inheritance. Is it possible or i should do all manually? Or maybe it is 3th route in this code?
During the class definition, none of the inherited attributes are available:
>>> class Super(object):
class_attribute = None
def instance_method(self):
pass
>>> class Sub(Super):
foo = class_attribute
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
class Sub(Super):
File "<pyshell#7>", line 2, in Sub
foo = class_attribute
NameError: name 'class_attribute' is not defined
>>> class Sub(Super):
foo = instance_method
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
class Sub(Super):
File "<pyshell#9>", line 2, in Sub
foo = instance_method
NameError: name 'instance_method' is not defined
You can't even access them using super, as the name of the subclass isn't defined within the definition block*:
>>> class Sub(Super):
foo = super(Sub).instance_method
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
class Sub(Super):
File "<pyshell#11>", line 2, in Sub
foo = super(Sub).instance_method
NameError: name 'Sub' is not defined
The only way to access the inherited attributes at definition time is to do so explicitly, using the name of the superclass:
>>> class Sub(Super):
foo = Super.class_attribute
>>> Sub.foo is Super.class_attribute
True
Alternatively you can access them within class or instance methods, but then you need to use the appropriate prefix of the class (conventionally cls) or instance (conventionally self) parameter.
* for anyone thinking "ah, but in 3.x you don't need arguments to super":
>>> class Sub(Super):
foo = super().instance_method
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
class Sub(Super):
File "<pyshell#6>", line 2, in Sub
foo = super().instance_method
RuntimeError: super(): no arguments
That's only true inside instance/class methods!
I may be wrong on this, but are you sure you don't want rather this?
class A(object):
def __init__(self):
self.a = 1
self.b = 2
class B(A):
def __init__(self):
super(B, self).__init__()
self.c = 3
#property
def d(self):
return self.a + self.b + self.c
BB = B()
print BB.d
or, as jonrsharpe pointed out:
class A():
a=1
b=2
class B(A):
c=3
d=A.a+A.b+c
print B.d

Accessing variable and functions in object oriented python - python

How to I declare a default value in a python object?
Without a python object it looks fine:
def obj(x={123:'a',456:'b'}):
return x
fb = obj()
print fb
With a python object I get the following error:
def foobar():
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self,field):
return x[field]
fb = foobar()
print fb.x
Traceback (most recent call last):
File "testclass.py", line 9, in <module>
print fb.x
AttributeError: 'NoneType' object has no attribute 'x'
How do I get the object to return the value of a variable in the object?
With a python object, I got an error:
def foobar():
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self,field):
return x[field]
fb2 = foobar({678:'c'})
print fb2.getStuff(678)
Traceback (most recent call last):
File "testclass.py", line 8, in <module>
fb2 = foobar({678:'c'})
TypeError: foobar() takes no arguments (1 given)
You didn't define a class, you defined a function with nested functions.
def foobar():
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self,field):
return x[field]
Use class to define a class instead:
class foobar:
def __init__(self,x={123:'a',456:'b'}):
self.x = x
def getStuff(self, field):
return self.x[field]
Note that you need to refer to self.x in getStuff().
Demo:
>>> class foobar:
... def __init__(self,x={123:'a',456:'b'}):
... self.x = x
... def getStuff(self, field):
... return self.x[field]
...
>>> fb = foobar()
>>> print fb.x
{456: 'b', 123: 'a'}
Do note that using a mutable value for a function keyword argument default is generally not a good idea. Function arguments are defined once, and can lead to unexpected errors, as now all your classes share the same dictionary.
See "Least Astonishment" and the Mutable Default Argument.
to define a class in python you have to use
class classname(parentclass):
def __init__():
<insert code>
With your code you're declaring a method not a class
Use
class foobar:
instead of
def foobar():

What is the difference between __init__ and __call__?

I want to know the difference between __init__ and __call__ methods.
For example:
class test:
def __init__(self):
self.a = 10
def __call__(self):
b = 20
The first is used to initialise newly created object, and receives arguments used to do that:
class Foo:
def __init__(self, a, b, c):
# ...
x = Foo(1, 2, 3) # __init__
The second implements function call operator.
class Foo:
def __call__(self, a, b, c):
# ...
x = Foo()
x(1, 2, 3) # __call__
Defining a custom __call__() method allows the class's instance to be called as a function, not always modifying the instance itself.
In [1]: class A:
...: def __init__(self):
...: print "init"
...:
...: def __call__(self):
...: print "call"
...:
...:
In [2]: a = A()
init
In [3]: a()
call
In Python, functions are first-class objects, this means: function references can be passed in inputs to other functions and/or methods, and executed from inside them.
Instances of Classes (aka Objects), can be treated as if they were functions: pass them to other methods/functions and call them. In order to achieve this, the __call__ class function has to be specialized.
def __call__(self, [args ...])
It takes as an input a variable number of arguments. Assuming x being an instance of the Class X, x.__call__(1, 2) is analogous to calling x(1,2) or the instance itself as a function.
In Python, __init__() is properly defined as Class Constructor (as well as __del__() is the Class Destructor). Therefore, there is a net distinction between __init__() and __call__(): the first builds an instance of Class up, the second makes such instance callable as a function would be without impacting the lifecycle of the object itself (i.e. __call__ does not impact the construction/destruction lifecycle) but it can modify its internal state (as shown below).
Example.
class Stuff(object):
def __init__(self, x, y, range):
super(Stuff, self).__init__()
self.x = x
self.y = y
self.range = range
def __call__(self, x, y):
self.x = x
self.y = y
print '__call__ with (%d,%d)' % (self.x, self.y)
def __del__(self):
del self.x
del self.y
del self.range
>>> s = Stuff(1, 2, 3)
>>> s.x
1
>>> s(7, 8)
__call__ with (7,8)
>>> s.x
7
>>> class A:
... def __init__(self):
... print "From init ... "
...
>>> a = A()
From init ...
>>> a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
>>>
>>> class B:
... def __init__(self):
... print "From init ... "
... def __call__(self):
... print "From call ... "
...
>>> b = B()
From init ...
>>> b()
From call ...
>>>
__call__ makes the instance of a class callable.
Why would it be required?
Technically __init__ is called once by __new__ when object is created, so that it can be initialized.
But there are many scenarios where you might want to redefine your object, say you are done with your object, and may find a need for a new object. With __call__ you can redefine the same object as if it were new.
This is just one case, there can be many more.
__init__ would be treated as Constructor where as __call__ methods can be called with objects any number of times. Both __init__ and __call__ functions do take default arguments.
I will try to explain this using an example, suppose you wanted to print a fixed number of terms from fibonacci series. Remember that the first 2 terms of fibonacci series are 1s. Eg: 1, 1, 2, 3, 5, 8, 13....
You want the list containing the fibonacci numbers to be initialized only once and after that it should update. Now we can use the __call__ functionality. Read #mudit verma's answer. It's like you want the object to be callable as a function but not re-initialized every time you call it.
Eg:
class Recorder:
def __init__(self):
self._weights = []
for i in range(0, 2):
self._weights.append(1)
print self._weights[-1]
print self._weights[-2]
print "no. above is from __init__"
def __call__(self, t):
self._weights = [self._weights[-1], self._weights[-1] + self._weights[-2]]
print self._weights[-1]
print "no. above is from __call__"
weight_recorder = Recorder()
for i in range(0, 10):
weight_recorder(i)
The output is:
1
1
no. above is from __init__
2
no. above is from __call__
3
no. above is from __call__
5
no. above is from __call__
8
no. above is from __call__
13
no. above is from __call__
21
no. above is from __call__
34
no. above is from __call__
55
no. above is from __call__
89
no. above is from __call__
144
no. above is from __call__
If you observe the output __init__ was called only one time that's when the class was instantiated for the first time, later on the object was being called without re-initializing.
__call__ allows to return arbitrary values, while __init__ being an constructor returns the instance of class implicitly. As other answers properly pointed out, __init__ is called just once, while it's possible to call __call__ multiple times, in case the initialized instance is assigned to intermediate variable.
>>> class Test:
... def __init__(self):
... return 'Hello'
...
>>> Test()
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>> class Test2:
... def __call__(self):
... return 'Hello'
...
>>> Test2()()
'Hello'
>>>
>>> Test2()()
'Hello'
>>>
So, __init__ is called when you are creating an instance of any class and initializing the instance variable also.
Example:
class User:
def __init__(self,first_n,last_n,age):
self.first_n = first_n
self.last_n = last_n
self.age = age
user1 = User("Jhone","Wrick","40")
And __call__ is called when you call the object like any other function.
Example:
class USER:
def __call__(self,arg):
"todo here"
print(f"I am in __call__ with arg : {arg} ")
user1=USER()
user1("One") #calling the object user1 and that's gonna call __call__ dunder functions
You can also use __call__ method in favor of implementing decorators.
This example taken from Python 3 Patterns, Recipes and Idioms
class decorator_without_arguments(object):
def __init__(self, f):
"""
If there are no decorator arguments, the function
to be decorated is passed to the constructor.
"""
print("Inside __init__()")
self.f = f
def __call__(self, *args):
"""
The __call__ method is not called until the
decorated function is called.
"""
print("Inside __call__()")
self.f(*args)
print("After self.f( * args)")
#decorator_without_arguments
def sayHello(a1, a2, a3, a4):
print('sayHello arguments:', a1, a2, a3, a4)
print("After decoration")
print("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print("After first sayHello() call")
sayHello("a", "different", "set of", "arguments")
print("After second sayHello() call")
Output:
Case 1:
class Example:
def __init__(self, a, b, c):
self.a=a
self.b=b
self.c=c
print("init", self.a, self.b, self.c)
Run:
Example(1,2,3)(7,8,9)
Result:
- init 1 2 3
- TypeError: 'Example' object is not callable
Case 2:
class Example:
def __init__(self, a, b, c):
self.a=a
self.b=b
self.c=c
print("init", self.a, self.b, self.c)
def __call__(self, x, y, z):
self.x=x
self.y=y
self.z=z
print("call", self.x, self.y, self.z)
Run:
Example(1,2,3)(7,8,9)
Result:
- init 1 2 3
- call 7 8 9
Short and sweet answers are already provided above. I wanna provide some practical implementation as compared with Java.
class test(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __call__(self, a, b, c):
self.a = a
self.b = b
self.c = c
instance1 = test(1, 2, 3)
print(instance1.a) #prints 1
#scenario 1
#creating new instance instance1
#instance1 = test(13, 3, 4)
#print(instance1.a) #prints 13
#scenario 2
#modifying the already created instance **instance1**
instance1(13,3,4)
print(instance1.a)#prints 13
Note: scenario 1 and scenario 2 seems same in terms of result output.
But in scenario1, we again create another new instance instance1. In scenario2,
we simply modify already created instance1. __call__ is beneficial here as the system doesn't need to create new instance.
Equivalent in Java
public class Test {
public static void main(String[] args) {
Test.TestInnerClass testInnerClass = new Test(). new TestInnerClass(1, 2, 3);
System.out.println(testInnerClass.a);
//creating new instance **testInnerClass**
testInnerClass = new Test().new TestInnerClass(13, 3, 4);
System.out.println(testInnerClass.a);
//modifying already created instance **testInnerClass**
testInnerClass.a = 5;
testInnerClass.b = 14;
testInnerClass.c = 23;
//in python, above three lines is done by testInnerClass(5, 14, 23). For this, we must define __call__ method
}
class TestInnerClass /* non-static inner class */{
private int a, b,c;
TestInnerClass(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
}
__init__ is a special method in Python classes, it is the constructor method for a class. It is called whenever an object of the class is constructed or we can say it initialises a new object.
Example:
In [4]: class A:
...: def __init__(self, a):
...: print(a)
...:
...: a = A(10) # An argument is necessary
10
If we use A(), it will give an error
TypeError: __init__() missing 1 required positional argument: 'a' as it requires 1 argument a because of __init__ .
........
__call__ when implemented in the Class helps us invoke the Class instance as a function call.
Example:
In [6]: class B:
...: def __call__(self,b):
...: print(b)
...:
...: b = B() # Note we didn't pass any arguments here
...: b(20) # Argument passed when the object is called
...:
20
Here if we use B(), it runs just fine because it doesn't have an __init__ function here.
We can use call method to use other class methods as static methods.
class _Callable:
def __init__(self, anycallable):
self.__call__ = anycallable
class Model:
def get_instance(conn, table_name):
""" do something"""
get_instance = _Callable(get_instance)
provs_fac = Model.get_instance(connection, "users")
I want to bring to the table some short cuts and syntax sugar, as well as few techniques that can be used, but I haven't see them in the current answers.
Instantiate the class and call it immediately
In many cases, for example when need to make a APi request, and the logic is encapsulated inside a class and what we really need is just give the data to that class and run it immediatelly as a separate entity, the instantiate class may not been needed. That is the
instance = MyClass() # instanciation
instance() # run the instance.__call__()
# now instance is not needed
Instead we can do something like that.
class HTTPApi:
def __init__(self, val1, val2):
self.val1 = val1
self.val2 = val2
def __call__(self, *args, **kwargs):
return self.run(args, kwargs)
def run(self, *args, **kwargs):
print("hello", self.val1, self.val2, args, kwargs)
if __name__ == '__main__':
# Create a class, and call it
(HTTPApi("Value1", "Value2"))("world", 12, 213, 324, k1="one", k2="two")
Give to call another existing method
We can declare a method to the __call__ as well, without creating an actual __call__ method.
class MyClass:
def __init__(self, val1, val2):
self.val1 = val1
self.val2 = val2
def run(self, *args, **kwargs):
print("hello", self.val1, self.val2, args, kwargs)
__call__ = run
if __name__ == '__main__':
(MyClass("Value1", "Value"))("world", 12, 213, 324, k1="one", k2="two")
This allows to declare another global function instead of a method, for whatever reason (there may be some reasons, for example you can't modify that method but you need it to be called by the class).
def run(self, *args, **kwargs):
print("hello",self.val1, self.val2, args, kwargs)
class MyClass:
def __init__(self, val1, val2):
self.val1 = val1
self.val2 = val2
__call__ = run
if __name__ == '__main__':
(MyClass("Value1", "Value2"))("world", 12, 213, 324, k1="one", k2="two")
call method is used to make objects act like functions.
>>> class A:
... def __init__(self):
... print "From init ... "
...
>>> a = A()
From init ...
>>> a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
<*There is no __call__ method so it doesn't act like function and throws error.*>
>>>
>>> class B:
... def __init__(self):
... print "From init ... "
... def __call__(self):
... print "From call it is a function ... "
...
>>> b = B()
From init ...
>>> b()
From call it is a function...
>>>
<* __call__ method made object "b" to act like function *>
We can also pass it to a class variable.
class B:
a = A()
def __init__(self):
print "From init ... "
__init__() can:
initialize the instance of class.
be called many time.
only return None.
__call__() can be freely used like an instance method.
For example, Person class has __init__() and __call__() as shown below:
class Person:
def __init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
print('"__init__()" is called.')
def __call__(self, arg):
return arg + self.f_name + " " + self.l_name
Now, we create and initialize the instance of Person class as shown below:
# Here
obj = Person("John", "Smith")
Then, __init__() is called as shown below:
"__init__()" is called.
Next, we call __call__() in 2 ways as shown below:
obj = Person("John", "Smith")
print(obj("Hello, ")) # Here
print(obj.__call__("Hello, ")) # Here
Then, __call__() is called as shown below:
"__init__()" is called.
Hello, John Smith # Here
Hello, John Smith # Here
And, __init__() can be called many times as shown below:
obj = Person("John", "Smith")
print(obj.__init__("Tom", "Brown")) # Here
print(obj("Hello, "))
print(obj.__call__("Hello, "))
Then, __init__() is called and the instance of Person class is reinitialized and None is returned from __init__() as shown below:
"__init__()" is called.
"__init__()" is called. # Here
None # Here
Hello, Tom Brown
Hello, Tom Brown
And, if __init__() doesn't return None and we call __init__() as shown below:
class Person:
def __init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
print('"__init__()" is called.')
return "Hello" # Here
# ...
obj = Person("John", "Smith") # Here
The error below occurs:
TypeError: __init__() should return None, not 'str'
And, if __call__ is not defined in Person class:
class Person:
def __init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
print('"__init__()" is called.')
# def __call__(self, arg):
# return arg + self.f_name + " " + self.l_name
Then, we call obj("Hello, ") as shown below:
obj = Person("John", "Smith")
obj("Hello, ") # Here
The error below occurs:
TypeError: 'Person' object is not callable
Then again, we call obj.__call__("Hello, ") as shown below:
obj = Person("John", "Smith")
obj.__call__("Hello, ") # Here
The error below occurs:
AttributeError: 'Person' object has no attribute '__call__'

Python, a function in a method

I have a method (__init__) in a class, and I want to use a function from the class in this method.
But when I want to run my program. I get: NameError: global name 'myfunction' is not defined
Someone, who knows what I have to do? :)
Thank you. But I have still a problem, because def myFunc(self, a): is a method and I wanted a function.
class Myclass(object):
def __init__(self, a):
self.a = self.myFunc(a)
def myFunc(self, a):
return a+1
Then you don't have a function call in the method, but you have a method call in it.
When creating a class you must specify the object when calling its methods:
>>> class A(object):
... def __init__(self, val):
... self.val = self._process(val)
... def _process(self, val):
... return val % 7
... process = _process #if you are outside methods then you don't
... #have to add "self.".
...
>>> a = A(5)
>>> a.process(3)
3
>>> a._process(6) #"a" is passed as the "self" parameter
6
As you can see in a class definition, but outside the methods you must specify the method name only, and not the "self.". Also you can't refer to a method not already defined:
>>> class B(object):
... def __init__(self):pass
... def method1(self):pass
... __call__ = method2 #method2 not defined!
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in B
NameError: name 'method2' is not defined

Python: changing methods and attributes at runtime

I wish to create a class in Python that I can add and remove attributes and methods. How can I acomplish that?
Oh, and please don't ask why.
This example shows the differences between adding a method to a class and to an instance.
>>> class Dog():
... def __init__(self, name):
... self.name = name
...
>>> skip = Dog('Skip')
>>> spot = Dog('Spot')
>>> def talk(self):
... print 'Hi, my name is ' + self.name
...
>>> Dog.talk = talk # add method to class
>>> skip.talk()
Hi, my name is Skip
>>> spot.talk()
Hi, my name is Spot
>>> del Dog.talk # remove method from class
>>> skip.talk() # won't work anymore
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Dog instance has no attribute 'talk'
>>> import types
>>> f = types.MethodType(talk, skip, Dog)
>>> skip.talk = f # add method to specific instance
>>> skip.talk()
Hi, my name is Skip
>>> spot.talk() # won't work, since we only modified skip
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Dog instance has no attribute 'talk'
I wish to create a class in Python that I can add and remove attributes and methods.
import types
class SpecialClass(object):
#classmethod
def removeVariable(cls, name):
return delattr(cls, name)
#classmethod
def addMethod(cls, func):
return setattr(cls, func.__name__, types.MethodType(func, cls))
def hello(self, n):
print n
instance = SpecialClass()
SpecialClass.addMethod(hello)
>>> SpecialClass.hello(5)
5
>>> instance.hello(6)
6
>>> SpecialClass.removeVariable("hello")
>>> instance.hello(7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'SpecialClass' object has no attribute 'hello'
>>> SpecialClass.hello(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'SpecialClass' has no attribute 'hello'
A possibly interesting alternative to using types.MethodType in:
>>> f = types.MethodType(talk, puppy, Dog)
>>> puppy.talk = f # add method to specific instance
would be to exploit the fact that functions are descriptors:
>>> puppy.talk = talk.__get__(puppy, Dog)
I wish to create a class in Python that I can add and remove attributes and methods. How can I acomplish that?
You can add and remove attributes and methods to any class, and they'll be available to all instances of the class:
>>> def method1(self):
pass
>>> def method1(self):
print "method1"
>>> def method2(self):
print "method2"
>>> class C():
pass
>>> c = C()
>>> c.method()
Traceback (most recent call last):
File "<pyshell#62>", line 1, in <module>
c.method()
AttributeError: C instance has no attribute 'method'
>>> C.method = method1
>>> c.method()
method1
>>> C.method = method2
>>> c.method()
method2
>>> del C.method
>>> c.method()
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
c.method()
AttributeError: C instance has no attribute 'method'
>>> C.attribute = "foo"
>>> c.attribute
'foo'
>>> c.attribute = "bar"
>>> c.attribute
'bar'
you can just assign directly to the class (either by accessing the original class name or via __class__ ):
class a : pass
ob=a()
ob.__class__.blah=lambda self,k: (3, self,k)
ob.blah(5)
ob2=a()
ob2.blah(7)
will print
(3, <__main__.a instance at 0x7f18e3c345f0>, 5)
(3, <__main__.a instance at 0x7f18e3c344d0>, 7)
Simply:
f1 = lambda:0 #method for instances
f2 = lambda _:0 #method for class
class C: pass #class
c1,c2 = C(),C() #instances
print dir(c1),dir(c2)
#add to the Instances
c1.func = f1
c1.any = 1.23
print dir(c1),dir(c2)
print c1.func(),c1.any
del c1.func,c1.any
#add to the Class
C.func = f2
C.any = 1.23
print dir(c1),dir(c2)
print c1.func(),c1.any
print c2.func(),c2.any
which results in:
['__doc__', '__module__'] ['__doc__', '__module__']
['__doc__', '__module__', 'any', 'func'] ['__doc__', '__module__']
0 1.23
['__doc__', '__module__', 'any', 'func'] ['__doc__', '__module__', 'any', 'func']
0 1.23
0 1.23
another alternative, if you need to replace the class wholesale is to modify the class attribute:
>>> class A(object):
... def foo(self):
... print 'A'
...
>>> class B(object):
... def foo(self):
... print 'Bar'
...
>>> a = A()
>>> a.foo()
A
>>> a.__class__ = B
>>> a.foo()
Bar
Does the class itself necessarily need to be modified? Or is the goal simply to replace what object.method() does at a particular point during runtime?
I ask because I sidestep the problem of actually modifying the class to monkey patch specific method calls in my framework with getattribute and a Runtime Decorator on my Base inheritance object.
Methods retrieved by a Base object in getattribute are wrapped in a Runtime_Decorator that parses the method calls keyword arguments for decorators/monkey patches to apply.
This enables you to utilize the syntax object.method(monkey_patch="mypatch"), object.method(decorator="mydecorator"), and even object.method(decorators=my_decorator_list).
This works for any individual method call (I leave out magic methods), does so without actually modifying any class/instance attributes, can utilize arbitrary, even foreign methods to patch, and will work transparently on sublcasses that inherit from Base (provided they don't override getattribute of course).
import trace
def monkey_patched(self, *args, **kwargs):
print self, "Tried to call a method, but it was monkey patched instead"
return "and now for something completely different"
class Base(object):
def __init__(self):
super(Base, self).__init__()
def testmethod(self):
print "%s test method" % self
def __getattribute__(self, attribute):
value = super(Base, self).__getattribute__(attribute)
if "__" not in attribute and callable(value):
value = Runtime_Decorator(value)
return value
class Runtime_Decorator(object):
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
if kwargs.has_key("monkey_patch"):
module_name, patch_name = self._resolve_string(kwargs.pop("monkey_patch"))
module = self._get_module(module_name)
monkey_patch = getattr(module, patch_name)
return monkey_patch(self.function.im_self, *args, **kwargs)
if kwargs.has_key('decorator'):
decorator_type = str(kwargs['decorator'])
module_name, decorator_name = self._resolve_string(decorator_type)
decorator = self._get_decorator(decorator_name, module_name)
wrapped_function = decorator(self.function)
del kwargs['decorator']
return wrapped_function(*args, **kwargs)
elif kwargs.has_key('decorators'):
decorators = []
for item in kwargs['decorators']:
module_name, decorator_name = self._resolve_string(item)
decorator = self._get_decorator(decorator_name, module_name)
decorators.append(decorator)
wrapped_function = self.function
for item in reversed(decorators):
wrapped_function = item(wrapped_function)
del kwargs['decorators']
return wrapped_function(*args, **kwargs)
else:
return self.function(*args, **kwargs)
def _resolve_string(self, string):
try: # attempt to split the string into a module and attribute
module_name, decorator_name = string.split(".")
except ValueError: # there was no ".", it's just a single attribute
module_name = "__main__"
decorator_name = string
finally:
return module_name, decorator_name
def _get_module(self, module_name):
try: # attempt to load the module if it exists already
module = modules[module_name]
except KeyError: # import it if it doesn't
module = __import__(module_name)
finally:
return module
def _get_decorator(self, decorator_name, module_name):
module = self._get_module(module_name)
try: # attempt to procure the decorator class
decorator_wrap = getattr(module, decorator_name)
except AttributeError: # decorator not found in module
print("failed to locate decorators %s for function %s." %\
(kwargs["decorator"], self.function))
else:
return decorator_wrap # instantiate the class with self.function
class Tracer(object):
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
tracer = trace.Trace(trace=1)
tracer.runfunc(self.function, *args, **kwargs)
b = Base()
b.testmethod(monkey_patch="monkey_patched")
b.testmethod(decorator="Tracer")
#b.testmethod(monkey_patch="external_module.my_patch")
The downside to this approach is getattribute hooks all access to attributes, so the checking of and potential wrapping of methods occurs even for attributes that are not methods + won't be utilizing the feature for the particular call in question. And using getattribute at all is inherently somewhat complicated.
The actual impact of this overhead in my experience/for my purposes has been negligible, and my machine runs a dual core Celeron. The previous implementation I used introspected methods upon object init and bound the Runtime_Decorator to methods then. Doing things that way eliminated the need to utilize getattribute and reduced the overhead mentioned previously... however, it also breaks pickle (maybe not dill) and is less dynamic then this approach.
The only use cases I have actually come across "in the wild" with this technique were with timing and tracing decorators. However, the possibilities it opens up are extremely wide ranging.
If you have a preexisting class that cannot be made to inherit from a different base (or utilize the technique it's own class definition or in it's base class'), then the whole thing simply does not apply to your issue at all unfortunately.
I don't think setting/removing non-callable attributes on a class at runtime is necessarily so challenging? unless you want classes that inherit from the modified class to automatically reflect the changes in themselves as well... That'd be a whole 'nother can o' worms by the sound of it though.

Categories

Resources