Method Overriding? - python

I saw this particular piece of code:
def g(x,y):
return x+y
def g(x,y):
return x*y
x,y=6,7
print (g(x,y))
The output is obviously(but not to me) is 42. Can somebody please explain this behavior? This is method overriding I suppose, but I'm still not getting the flow here.

When you define a function, and you redefine it, it will use the last one you defined, even the parameter is different:
def g(x,y):
return x+y
def g(x,y):
return x*y
x,y=6,7
print (g(x,y))
def hello():
return 'hello'
def hello():
return 'bye'
print hello()
def withone(word):
return word
def withone():
return 1==1
print withone('ok')
Output:
42
bye
TypeError: withone() takes no arguments (1 given)
And function name in Python is more like simple variable:
def hello():
return 'hello'
iamhello = hello # bind to the old one
def hello():
return 'bye'
print hello() # here is the new guy
print iamhello()
OutPut:
bye
hello

The devil is in the order of function definitions.
This is not technically method overriding as that requires class inheritance, instead it's a result of how python declares and references functions.
When declaring a function, python stores a reference to that function in a variable named after the function definition. (e.g. variable would be "foo" for "def foo():")
By declaring the function twice, the value of that variable gets overwritten by the second definition.

A Python script is parsed from top till bottom.
So anytime the same name of a variable or function or class occurs, it overwrites any definitions that where associated with this name before.
def g(x,z):
print('first')
def g():
print('second')
g = 3
print g
print g()
So look at this example which will result in the printout of '3' and then in an Exception: 'TypeError: 'int' object is not callable'
The name g is at first a function with two parameters, then it gets redefined to be a function with no parameters, then it gets redefined to be an int.
Which cannot be called obviously :)

Everything in python is treated as object, whether it be a function name or class name. So, when we define a function using 'def', the memory allocation is done for that method. Then python points the name that we assign to the function, to this allocated memory location. So if we define a method :-
def demo():
print 'hi'
the memory is allocated for the method, and the name 'demo' is pointed to its memory location as follows :-
Now as described by zoosuck in his second example, when you assign the function name to another variable :-
demo2 = demo # bind to the old one
then in that case, the assigned memory location to demo, is assigned to demo2 as well. So both demo and demo2 points to same location 12506.
print id(demo) # will print 12506
print id(demo2) # will print 12506
Now if we modify the above piece of code and in the next line, define a new method with same name demo:-
def demo():
print 'hi'
demo2 = demo # bind to the old one
demo() # Will print hi
def demo():
print "hello"
demo() # Will print hello
demo2() # Will print hi
then a completely new memory location 12534 is allocated for this new method, and now demo will point to this new location 12534 instead of pointing to the old one i.e. to 12506. But demo2 is still pointing to the location 12506.
I hope this will give you a clear idea of what is going on and how the method name is over-written.

Order matters, if names are same,last function you defined is processing. In your case it's;
def g(x,y):
return x*y

g is just a variable. The fact that the object it refers to is a function doesn't make it special in Python, so you can assign and reassign it as you want. In this case, the second assignment (which is what a function definition is) simply replaces the object stored there with a different one.

Functions and methods are normal objects like any others. So in
def g(x, y):
return x + y
def g(x, y):
return x * y
the second object g will override(replace) the first one, just like object a does below:
a = 1
a = 2
The number, type or order of parameters does not make any difference, because Python does not support function/method override and does not allow two functions/methods to have the same name.

If you are familiar with lambda function, also often called anonymous\inline functions, this might clear things up a bit
These two code blocks are essentially equal
def g(x,y):
return x+y
def g(x,y):
return x*y
g = lambda x,y: x+y
g = lambda x,y: x*y

Related

pass return of a function into another

I have a question / problem and I don't know how to solve it. Suppose you have three functions, function 1, function 2 and function 3. In function 1 you do some operations and you give a specific return which will be used as input for the second function. In the second function you do some specific calculation and also finish with return, which you pass in a third function
My problem is that as soon as I pass the return of function 1 into function 2 all the calculation in function 1 is repeated (calculation is here in this case, several plots) The same goes for function two into three, now I get results from function 1 and function 2. I hope you do understand what I mean.
What I want is just the return value of func 1 for func 2 and return value of func 2 for three and not the entire function body.
Here is what my code looks like:
class test:
def __(self)__:
self.attribute1=pd.read_csv(...)
self.attribite2=pd.read_csv(...)
def func1(self):
plt.plot(a,b)
plt.plot(c,d)
return x
def func2(self):
self.data_2=self.func1()
plt.plot(e,f)
plt.plot(g,h)
return y
def func3(self):
self.data_3=self.func2()
plt.plot(i,j)
data_test=test()
print(data_test.func2())
My problem is that (let's focus on func2). If I use the input from func1 and execute my code for func2 I get also the two plots. I dont want to have that. I just want to see the plots(e,f) and plots(g,h) instead of plots(a,b), plots(c,d), plots(e,f) and plots(g,h)
Your class definition do not follow the OOP clean design, for which every method should performa the most atomic task possible.
Your methods func1, func2 and func3, they all do at least 2 tasks: plot something and return something else.
Consider changing your class so every method do one and only one thing, defining public APIS and private methods, for instance:
class test:
def __(self)__:
self.attribute1 = []
self.attribite2 = []
def _func1(self):
return x
def _func2(self):
self.data_2 = self._func1()
return y
def _func3(self):
self.data_3 = self._func2()
def func2(self):
self._func2()
plt.plot(e,f)
plt.plot(g,h)
def func3(self):
self._func3()
plt.plot(e,f)
plt.plot(g,h)
data_test=test()
data_test.func2()
This way func2 and func3 are public apis (aka: intended to be called from outside the class) that will "do the work" (setting stuff in self.data_2 and self.data_3) AND plot; while _func2 and _func3 are private methods (aka, methods that only the class itself is supposed to use) will only do the work.
Now, calling func2 will use methods _func1 and _func2, but only plot what's defined in func2.
You say that you "pass the return of function 1 into function 2", but you never do that.
You're not passing any results anywhere, and none of your functions take any input (except self) - you're calling the functions directly in each one.
In other words, every time you call function2, it calls function1, and every time you call function3, it calls function2, which in turn calls function1.
Code that matches your description would look like this:
class test:
def __(self)__:
self.attribute1=pd.read_csv(...)
self.attribite2=pd.read_csv(...)
def func1(self):
plt.plot(a,b)
plt.plot(c,d)
return x
def func2(self, a):
self.data_2 = a
plt.plot(e,f)
plt.plot(g,h)
return y
def func3(self, x):
self.data_3 = x
plt.plot(i,j)
return z
data_test = test()
print(data_test.func3(data_test.func2(data_test.func1())))

Is there a way to use variable from outer function in the inner function body, in Python?

The pattern of the code that I try to build is:
def OuterFunction():
theVariable = 0
def InnerFunction():
# use theVariable from OuterFunction somehow
# the solution is not to use InnerFunction(theVariable) due to the reasons given in the text
InnerFunction()
My hopes were there is some keyword (like global) or a way to tell the interpreter to use theVariable from the outer method's scope.
Why I need it this way:
A Python script that we run before has to become module now (the collection of methods).
OuterFunction did not exist before and InnerFunction is just an example for a big number of very complex methods that bear an already existing logic.
theVariable is just an example for multiple global variables that were used in the script in all of methods that InnerFunction represents.
I do not want to change signatures of all methods, that are, by the way, nested.
EDIT:
Here is the code that crashes for me in every interpreter, with "local variable 'theVariable' referenced before assignment" error (so I could not just reference the variable):
def OuterFunction():
theVariable = 5
def InnerFunction():
theVariable = theVariable + 1
print(theVariable)
InnerFunction()
OuterFunction()
EDIT2:
Seems trying to change the variable leads to the exception, which gives a wrong description.
If InnerFunction() is changed to contain only print(theVariable) statement it works.
You can just reference the variable directly, as follows;
def outer():
x = 1
def inner():
print(x + 2)
inner()
outer()
Prints: 3
You could simply reference the 'theVariable' inside the nested InnerFunction, if you don't want to pass it's value as a parameter:
def OuterFunction():
# Declare the variable
theVariable = 42
def InnerFunction():
# Just reference the 'theVariable', using it, manipulating it, etc...
print(theVariable)
# Call the InnerFunction inside the OuterFunction
InnerFunction()
# Call the OuterFunction on Main
OuterFunction()
# It will print '42' as result
Would this be okay with you:
def OuterFunction():
theVariable = 0
def InnerFunction(value):
return value + 1
theVariable = InnerFunction(theVariable)
return theVariable
This way you don't have to mess with scopes and your functions are pure.

what is difference between foo=bar(foo) and something=bar(foo) in decorator in python?

I read about we can create reference of any function in python but i also read that while creating a decorator we use a special syntax called "#" : ex: #decorator_function
and this #decorator_function is equal to new_function=decorator_function(new_function)
so my doubt is in my view both :
anything = decorator_function(new_function)
new_function=decorator_function(new_function)
both are playing the role of closure but both result different output. so what is big difference between both of them?
example code :
def deco(fn):
def wrapper(*args):
print('called')
return fn(*args)
return wrapper
def something(x):
if x == 0:
print('first')
something(x+1)
else:
print('hello')
print('new name')
a = deco(something)
a(0)
print('\nreassigning to the same name')
something = deco(something)
something(0)
The original something function you wrote makes a recursive call to something, not a.
If you assign deco(something) to a, then something is still the original function, and the recursive call will call the original function:
new function calls original function
original function looks up something, finds original function
original function calls original function...
If you assign deco(something) to something, then something is now the new function, and the recursive call will call the new function:
new function calls original function
original function looks up something, finds new function
original function calls new function
new function calls original function...
For the first one, a = deco(something)
def deco(fn):
def wrapper(*args):
print('called')
return something(*args) # Notice here
return wrapper
The second one, something = deco(something) is just the same except your original function something now has become the wrapper function that deco returned.
>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
>>> a
<function deco.<locals>.wrapper at 0x7fbae4622ea0>
Both something and a wrap the original something before it was overridden by something = deco(something) assignment. Python internally stored the original something function somewhere in the wrapper functions:
>>> something.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>
>>> a.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>
In the last assignment something has become something different:
>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
Both of your assignments using manual calls to the decorator work. But one of them (the one that rebinds something) replaces the original function so that it can't be reached by its original name any more. It's not any different than using any other assignment. For instance:
def foo(x):
return x + 1
a = 10
a = foo(a)
When you assign the result of foo(a) to a, it replaces the old value of 10 with a new value 11. You can't get the 10 any more.
Decorator syntax does the same thing.
def deco(fn):
def wrapper(*args):
print('called')
return fn(*args)
return wrapper
def func_1(x):
pass
func_1 = deco(func_1) # replace the old func_1 with a decorated version
#deco # the # syntax does the same thing!
def func_2(x):
pass
It's not forbidden to use a decorator to create a differently named function, it's just not normally as useful (and so there's no special syntax for it):
def func_3(x):
pass
func_4 = deco(func_3) # this works, creating a new function name without hiding the old one

How to create variables local to with statement?

I would like to create temporary variables visible in a limited scope.
It seems likely to me that you can do this with a "with" statement, and I would think there is a construct that makes it easy to do, but I cannot seem to find it.
I would like something like the following (but it does not work this way of course):
pronunciation = "E_0 g z #_1 m p l"
# ...
with pronunciation.split() as phonemes:
if len(phonemes) > 2 or phonemes[0].startswith('E'):
condition = 1
elif len(phonemes) < 3 and phonemes[-1] == '9r':
condition = 2
So is there a simple way to make this work, using built-ins?
Thanks!
Python creates local variables with function scope (once a name is used it stays alive until the end of the function).
If you really want to limit scope then "del <var>" when you want it explicitly discarded, or create separate function to act as a container for a more limited scope.
You can create a method
def process_pronunciation(pronunciation):
phonemes = pronunciation.split()
if len(phonemes) > 2 or phonemes[0].startswith('E'):
condition = 1
elif len(phonemes) < 3 and phonemes[-1] == '9r':
condition = 2
return condition
When you call the method, the local variable phonemes won't be available in the global namespace.
pronunciation = "E_0 g z #_1 m p l"
condition = process_phonemes(pronunciation)
You could do it with with, but I don't think it's worth the trouble. Basically (in a python function) you have two scopes - global or local, that's it. If you want a symbol to have a lifespan shorter than the function you'll have to delete it afterwards using del. You could define your own context manager to make this happen:
class TempVar:
def __init__(self, loc, name, val):
self.loc = loc
self.name = name
self.val
def __enter__(self):
if self.name in self.loc:
self.old = self.loc[self.name]
self.loc[self.name] = self.val
def __exit__(self, *exc):
if hasattr(self, "old"):
self.loc[self.name] = self.old
else:
del self.loc[self.name]
then you can use it to get a temporary variable:
with TempVar(locals(), "tempVar", 42):
print(tempVar)
The working is that it modifies the dict containing local variables (which is supplied to the constructor via locals()) on entry and restoring it when leaving. Please note that this relies on that modifying the result returned by locals() actually modifies the local namespace - the specification does NOT guarantee this behaviour.
Another (and safer) alternative that was pointed out is that you could define a separate function which would have it's own scope. Remember it's perfectly legal to nest functions. For example:
def outer():
def inner(tempVar):
# here tempVar is in scope
print(tempVar)
inner(tempVar = 42)
# here tempVar is out of scope
with statement does not have its own scope , it uses the surrounding scope (like if the with statement is directly inside the script , and not within any function, it uses global namespace , if the with statement is used inside a function, it uses the function's namespace(scope)).
If you want the statements inside a with block to run in its own local scope, one possible way would be to move the logic to a function , that way the logic would be running in its own scope (and not the surrounding scope of with.
Example -
def function_for_with(f):
#Do something.
with pronunciation.split() as phonemes:
function_for_with(phonemes)
Please note, the above will not stop phonemes from being defined in the surrounding scope.
If you want that as well (move the phonemes into its own scope), you can move the complete with statement inside a function. Example -
def function_with(pronunciation):
with pronunciation.split() as phonemes:
#do stuff
pronunciation = "E_0 g z #_1 m p l"
function_with(pronunciation)
Expanding on #skyking's answer, here's an even more magical implementation of the same idea that reads almost exactly like you wrote. Introducing: the with var statement!1
class var:
def __init__(self, value):
import inspect
self.scope = inspect.currentframe().f_back.f_locals
self.old_vars = set(self.scope.keys())
self.value = value
def __enter__(self):
return self.value
def __exit__(self, type, value, traceback):
for name in set(self.scope.keys()) - self.old_vars:
del self.scope[name]
### Usage:
line = 'a b c'
with var (line.split()) as words:
# Prints "['a', 'b', 'c']"
print(words)
# Causes a NameError
print(words)
It does all the nasty extracting of local variables and names for you! How swell. If you space it quirkily like I did and hide the definition in a from boring_stuff import * statement, you can even pretend var is a keyword to all of your confused co-workers.
[1] If you actually use this, the ghost of a dead parrot will probably haunt you forever. The other answers provide much saner solutions; this one is more of a joke.

Do you change variables AFTER you run a function in python?

So I wrote this function from a book I am reading, and this is how it starts:
def cheese_and_crackers(cheese_count, boxes_of_crackers):
print "You have %d cheeses!" % cheese_count
print "You have %d boxes of crackers!" % boxes_of_crackers
print "Man that's enough for a party!"
print "Get a blanket.\n"
ok, makes sense. and then, this is when this function is run where I got a little confused and wanted to confirm something:
print "OR, we can use variables from our script:"
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese, amount_of_crackers)
the thing that confused me here is that the amount_of_cheese and amount_of_crackers is changing the variables (verbage? not sure if i am saying the right lingo) from cheese_count and boxes_of_crackers repectively from the first inital variable labels in the function.
so my question is, when you are using a different variable from the one that is used in the initial function you wrote, why would you change the name of the AFTER you wrote out the new variable names? how would the program know what the new variables are if it is shown after it?
i thought python reads programs top to bottom, or does it do it bottom to top?
does that make sense? i'm not sure how to explain it. thank you for any help. :)
(python 2.7)
I think you are just a bit confused on the naming rules for parameter passing.
Consider:
def foo(a, b):
print a
print b
and you can call foo as follows:
x = 1
y = 2
foo(x, y)
and you'll see:
1
2
The variable names of the arguments (a, b) in the function signature (1st line of function definition) do not have to agree with the actual variable names used when you invoke the function.
Think of it as this, when you call:
foo(x, y)
It's saying: "invoke the function foo; pass x in as a, pass y in as b". Furthermore, the arguments here are passed in as copies, so if you were to modify them inside the function, it won't change the values outside of the function, from where it was invoked. Consider the following:
def bar(a, b):
a = a + 1
b = b + 2
print a
x = 0
y = 0
bar(x, y)
print x
print y
and you'll see:
1
2
0
0
The script runs from top to bottom. The function executes when you call it, not when you define it.
I'd suggest trying to understand concepts like variables and function argument passing first.
def change(variable):
print variable
var1 = 1
change(var1)
In the above example, var1 is a variable in the main thread of execution.
When you call a function like change(), the scope changes. Variables you declared outside that function cease to exist so long as you're still in the function's scope. However, if you pass it an argument, such as var1, then you can use that value inside your function, by the name you give it in the function declaration: in this case, variable. But it is entirely separate from var! The value is the same, but it is a different variable!
Your question relates to function parameter transfer.
There are two types of parameter transfer into a function:
By value ------- value changed in function domain but not global domain
By reference ------- value changed in global domain
In python, non-atomic types are transferred by reference; atomic types (like string, integer) is transferred by value.
For example,
Case 1:
x = 20
def foo(x):
x+=10
foo()
print x // 20, rather than 30
Case 2:
d = {}
def foo(x): x['key']=20
foo(d)
print d // {'key': 20}

Categories

Resources