can one function be overwritten by calling another? - python

Let's say you have functions a and b. Can you, by calling function a, replace function b with another function?
I know you can do b=a(b), but can you change b with just doing a(b)?

Functions and methods are attributes of modules and classes respectively. So you can modify the required attribute to point to another function.
>>> __name__
'__main__'
>>> def a():
... print 'a'
...
>>> def b():
... print 'b'
...
>>> import sys
>>> sys.modules['__main__'].b = a
>>> b()
a
For a class:
>>> class A(object):
... def a(self):
... print 'a'
... def b(self):
... print 'b'
...
>>> A.b = A.a
>>> x = A()
>>> x.b()
a
And if you have a variable holding the name to replace, then use setattr, for example:
setattr(sys.modules['__main__'],'b',a)
setattr(A,'b',A.a)
Just replace the string ('b') with your variable.
Not sure why you would want to though? It will make for confusing code.

You can replace the code object of b with another function's code:
>>> def b():
... print 'b'
...
>>> def a():
... print 'a'
...
>>> def c(f):
... f.__code__ = a.__code__ # func_code instead of __code__ for py 2.5 and earlier
...
>>> c(b)
>>> b()
a
Although this is almost certainly a sign you're thinking of whatever problem you're trying to solve in the wrong way.

You could use global to accomplish something like this.
>>> def a():
... global b
... def b():
... print "New Function B"
>>> def b():
... print "Function B"
...
...
>>> b()
Function B
>>> a()
>>> b()
New Function B
>>>
If you don't know which method you're replacing, you can use function.func_code to replace one function's code with another.
>>> def change(old_func, new_func):
... old_func.func_code = new_func.func_code
...
>>> def a():
... print "Function A"
...
>>> def b():
... print "Function B"
...
>>> def c():
... print "Function C"
...
>>>
>>> change(a, b)
>>> a()
Function B
>>> change(a, c)
>>> a()
Function C
>>>

You can do it easily like this
def a(func):
globals()[func] = c
def b():
print('b')
def c():
print('c')
a()
b()
>>> c

I'm not sure what you are aiming for, but yes, you can do that:
>>> def a():
... global b
... b = a
... return 'a'
...
>>> def b():
... return 'b'
...
>>> b()
'b'
>>> a()
'a'
>>> b()
'a'
>>> def c(f):
What if I don't know I'm overwriting b beforehand?In other words, if I want to pass b as an argument to a
>>> def c(f):
... global b
... b = f
... return 'c'
...
>>> def d():
... return 'd'
...
>>> b()
'a'
>>> c(d)
'c'
>>> b()
'd'
>>> c(a)
'c'
>>> b()
'a'

Related

Usefulness of def __init__(self)?

I am fairly new to python, and noticed these posts:
Python __init__ and self what do they do? and
Python Classes without using def __init__(self)
After playing around with it, however, I noticed that these two classes give apparently equivalent results-
class A(object):
def __init__(self):
self.x = 'Hello'
def method_a(self, foo):
print self.x + ' ' + foo
(from this question)
and
class B(object):
x = 'Hello'
def method_b(self,foo):
print self.x + ' ' + foo
Is there any real difference between these two? Or, more generally, does __init__ change anything inherently about the attributes of a class? In the documentation it is mentioned that __init__ is called when the instance is created. Does this mean that x in class B is established before instantiation?
Yeah, check this out:
class A(object):
def __init__(self):
self.lst = []
class B(object):
lst = []
and now try:
>>> x = B()
>>> y = B()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1, 2]
>>> x.lst is y.lst
True
and this:
>>> x = A()
>>> y = A()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1]
>>> x.lst is y.lst
False
Does this mean that x in class B is established before instantiation?
Yes, it's a class attribute (it is shared between instances). While in class A it's an instance attribute. It just happens that strings are immutable, thus there is no real difference in your scenario (except that class B uses less memory, because it defines only one string for all instances). But there is a huge one in my example.
In the first exemple you have the variable of the instance of the class. This variable is only accessible through an instance (self required).
class A():
def __init__(self):
self.x = 'hello'
print A.x -> AttributeError
print A().x -> 'hello'
In the second exemple you have a static variable. You can access to this variable thanks to the name of the class A
class A():
x = 'hello'
print A.x -> 'hello'
print A().x -> 'hello'
In fact you can have a static variable and an instance variable with the same name:
class A():
x = 'hello'
def __init__(self):
self.x = 'world'
print A.x -> hello
print A().x -> world
The static value is shared between all the instances
class A():
x = 'hello'
#staticmethod
def talk():
print A.x
a = A()
print a.talk() -> hello
A.x = 'world'
print a.talk() -> world
You have a good article here:
http://linuxwell.com/2011/07/21/static-variables-and-methods-in-python/
As others have stated, it's the difference between a variable on a class and a variable on a class instance. See the following example.
>>> class A:
... a = []
...
>>> class B:
... def __init__(self):
... self.b = []
...
>>> a1 = A()
>>> a1.a.append('hello')
>>> a2 = A()
>>> a2.a
['hello']
>>> b1 = B()
>>> b1.b.append('goodbye')
>>> b2 = B()
>>> b2.b
[]
For immutable objects like tuples, strings, etc. it's harder to notice the difference, but for mutables, it changes everything—the changes applied are shared between ALL instances of that class.
Note also that the same behavior happens for keyword argument defaults!
>>> class A:
... def __init__(self, a=[]):
... a.append('hello')
... print(a)
...
>>> A()
['hello']
>>> A()
['hello', 'hello']
>>> A()
['hello', 'hello', 'hello']
>>> class B:
... def __init__(self, b=None):
... if b is None:
... b = []
... b.append('goodbye')
... print(b)
...
>>> B()
['goodbye']
>>> B()
['goodbye']
>>> B()
['goodbye']
This behavior bites a lot of new Python programmers. Good for you in discovering these distinctions early on!

Get name of the bound method from instance of the bound method object in Python

I have :
class A:
def a():
pass
After typing in the python command line:
Aobj = A()
aBoundMeth = getattr(Aobj, 'a')
My goal is to get the name of the method that aBoundMeth object represents. Is it possible to do it?
Thank you in advance.
Assuming that the name of the method is the string 'a' (in this case), You can use the __name__ attribute on the function object.
e.g.
>>> Aobj = A()
>>> aBoundMeth = getattr(Aobj, 'a')
>>> aBoundMeth.__name__
'a'
Note that this is the function name when it was created. You can make more references to the same function, but the name doesn't change. e.g.
>>> class A(object):
... def a(self):
... pass
... b = a
...
>>> Aobj = A()
>>> Aobj.a.__name__
'a'
>>> Aobj.b.__name__
'a'

How to change Method of Object in python

I write a python file like :
class A(object):
def update(self, str):
pass
def say(self, str):
print "I update: " + str
def fun(obj, str):
obj.say(str)
a = A()
import types
setattr(A, "update", types.MethodType(fun, None, A))
a.update("hello")
b = A()
b.update("world?")
It change behave of class, the object b have been changed. but, I want to only change object a.
How to change Method of Object in python?
Here is a way to do it:
a.update = lambda x: fun(a, x)
You are setting the class method, while you want to set only the method bound to some instance.
>>> class MyClass(object):
... def a(self): pass
...
>>> MyClass.a = lambda x: x
>>> MyClass.a
<unbound method MyClass.<lambda>>
>>> a = MyClass()
>>> a.a
<bound method MyClass.<lambda> of <__main__.MyClass object at 0x1d7fed0>>
Changing the a method at class level changes also the a methods of all instances.
>>> class MyClass(object):
... def a(self): pass
...
>>> b = MyClass()
>>> b.a = lambda x: x
>>> MyClass.a
<unbound method MyClass.a>
>>> b.a
<function <lambda> at 0x1d88938>
>>> c = MyClass()
>>> c.a
<bound method MyClass.a of <__main__.MyClass object at 0x1d8d110>>
Changing the a method of an instance does not change the method of the class or other instances.

List of all functions used in python program as string

How can we find all the functions in a python program??? for eg.
Input
def func1:
#doing something
def func2:
#doing something
def func3:
#doing something
Output
{'func1' , 'func2' , 'func3'}
If you want all functions in the global scope, you can use globals() with inspect.isfunction():
>>> def foo():
... pass
...
>>> def bar():
... pass
...
>>> import inspect
>>> [member.__name__ for member in globals().values() \
... if inspect.isfunction(member)]
['bar', 'foo']
Guessing you want only the methods in your current context:
import inspect
d = locals()
funcs = [f for f in d if inspect.isfunction(d[f])]

dir() a __class__ attribute?

class Foo:
pass
>>> f = test.Foo()
Lets look into the class instance ...
>>> dir(f)
['__add__', [__class__] ...]
Oooh! Lets look into the class instance metadata ...
>>> dir(f.__class__)
['__add__', [__class__] ...]
hmm ... was expecting attributes of __class__ ; but returns back attributes of f
Trying a hit and trial ...
>>> dir(f.__class__.__class__)
['__abstractmethods__', '__base__' ...]
hmm ... why twice a charm?
dir(f) and dir(f.__class__) are showing the attributes of two different things. It's just that your empty object has the same attributes as its own class. Try this:
>>> class Foo:
... def __init__(self):
... self.a = 17
...
>>> f = Foo()
>>> 'a' in dir(f)
True
>>> 'a' in dir(f.__class__)
False

Categories