I have a class object with a method function. Inside this method function "animal", I have an inner function that I want to call. But it appears that my inner function isn't being called because the correct result should return "hit here" instead of "sample text".
Here is my class code:
class PandaClass(object):
def __init__(self, max_figure):
self.tree = {}
self.max_figure = max_figure
def animal(self, list_sample, figure):
def inner_function():
if len(list_sample) == 0:
return "hit here"
inner_function()
return "sample text"
I instantiate the class and call the animal function with code below:
panda = PandaClass(max_figure=7)
panda.animal(list_sample=[], figure=0)
I want the code to return "hit here" which would mean the inner function got run but instead I got "sample text". Please let me know how I can correct this.
return always gives its result to the code that called it. In this case, the outer function called the inner function, so the inner function is returning it's value to the outer function.
If you want the outer function to return the result that the inner function returns, you need to do something like this:
def animal(self, list_sample, figure):
def inner_function():
if len(list_sample) == 0:
return "hit here"
inner_func_result = inner_function()
if inner_func_result:
return inner_func_result
else:
return "sample text"
Related
I didn't find a solution in "similar" questions. I like to call a function in a function in a loop. the solution will not be to set "parameters" in front of the function (def inner) I try to call. I like to call the "def inner" in the end of the loop. Thanks!
def meta1():
def inner():
print("hello inner2")
parameters = {"Name": "XYZ","max_time": 35}
return parameters
def meta2():
def inner():
print("hello inner2")
parameters = {"Name": "XXX","max_time": 25}
return parameters
the loop over the functions
for func in [meta1, meta2]:
x = func()
print(x['Name'])
print("here is some other code between. The solution is not to change the functions!")
print(func(inner())) #here i need some help, thanks
Not clear why you want/need to do this but if each meta also returns its inner function then it is easy.
def meta1():
def printer():
print("hello xyz")
parameters = {"Name": "XYZ","max_time": 35}
return parameters,printer
def meta2():
def printer():
print("hello xxx")
parameters = {"Name": "XXX","max_time": 25}
return parameters,printer
for func in [meta1, meta2]:
x,inner = func()
print(x['Name'])
print("here is some other code between. The solution is not to change the functions!")
print(inner())
While it is not clear what you want to do, this code may help
You can copy and paste it into an Idle window, and run it.
The point of my answer is to introduce you to classes, which in Python may be the best fit for the level of abstraction you want. Classes are a major feature of Python, and when you learn about them you will also discover static members and so on. But for now ...
def meta1():
def inner():
print("hello inner2")
parameters = {"Name": "XYZ","max_time": 35}
return parameters
class Meta1ClassExample:
def inner(self):
print("hello inner2")
parameters = {"Name": "XYZ","max_time": 35}
return parameters
if __name__ == '__main__':
try:
meta1.inner() #AttributeError: 'function' object has no attribute 'inner'
except AttributeError:
print("As expected, looking for the inner function is an error")
metaclass = Meta1ClassExample()
p = metaclass.inner()
print (p)
If your goal is to use the inner functions outside meta1 and meta2, respectively, you can try something like this:
def meta1():
def printer():
print("hello xyz")
parameters = {"Name": "XYZ","max_time": 35}
return printer, parameters
def meta2():
def printer():
print("hello xxx")
parameters = {"Name": "XXX","max_time": 25}
return printer, parameters
for func in [meta1, meta2]:
printer_fct, x = func()
print(x['Name'])
print("here is some other code between. The solution is not to change the functions!")
print(printer_fct()) #here i need some help, thanks
Edit: In the last line, you would probably want a simple call to the function printer_fct(), since the application of print only outputs None because printer_fct() does not return anything.
def display():
""" i am testing to see doc string """
pass
display_1=display()
print(display.__doc__)
output-:i am testing to see doc string
print(display_1.__doc__)
output-:None
display_1 is not a function. It is None as you have taken the return value of the function display()
What you want to do is this:
display_1 = display
Do not add the () at the end as that will call the function and store the return value in display_1
You arr calling to the function display, which has no return. In python, if a function returns nothing explicitly, it returns None.
So, when you are executing display_1=display(), display_1 is None, so it has not the attribute doc
If you want to get the docstring, call display.__doc__
Look at this: Getting the docstring from a function
for example you can do like this also:
class DoubleMap(object):
def __init__(self):
self.url = "https://someurl"
def Method(self):
"""rejgnjknkjnklerg"""
return self.url
mapInstance = DoubleMap.Method.__doc__
print(mapInstance)
in your code display() is no returning any value thats why you are getting none you can do like this if you want
def display():
""" i am testing to see doc string """
return display.__doc__
display_1=display()
print(display.__doc__)
print(display_1)
Basically I want to do something like this:
How can I hook a function in a python module?
but I want to call the old function after my own code.
like
import whatever
oldfunc = whatever.this_is_a_function
def this_is_a_function(parameter):
#my own code here
# and call original function back
oldfunc(parameter)
whatever.this_is_a_function = this_is_a_function
Is this possible?
I tried copy.copy, copy.deepcopy original function but it didn't work.
Something like this? It avoids using globals, which is generally a good thing.
import whatever
import functools
def prefix_function(function, prefunction):
#functools.wraps(function)
def run(*args, **kwargs):
prefunction(*args, **kwargs)
return function(*args, **kwargs)
return run
def this_is_a_function(parameter):
pass # Your own code here that will be run before
whatever.this_is_a_function = prefix_function(
whatever.this_is_a_function, this_is_a_function)
prefix_function is a function that takes two functions: function and prefunction. It returns a function that takes any parameters, and calls prefunction followed by function with the same parameters. The prefix_function function works for any callable, so you only need to program the prefixing code once for any other hooking you might need to do.
#functools.wraps makes it so that the docstring and name of the returned wrapper function is the same.
If you need this_is_a_function to call the old whatever.this_is_a_function with arguments different than what was passed to it, you could do something like this:
import whatever
import functools
def wrap_function(oldfunction, newfunction):
#functools.wraps(function)
def run(*args, **kwargs):
return newfunction(oldfunction, *args, **kwargs)
return run
def this_is_a_function(oldfunc, parameter):
# Do some processing or something to customize the parameters to pass
newparams = parameter * 2 # Example of a change to newparams
return oldfunc(newparams)
whatever.this_is_a_function = wrap_function(
whatever.this_is_a_function, this_is_a_function)
There is a problem that if whatever is a pure C module, it's typically impossible (or very difficult) to change its internals in the first place.
So, here's an example of monkey-patching the time function from the time module.
import time
old_time = time.time
def time():
print('It is today... but more specifically the time is:')
return old_time()
time.time = time
print time.time()
# Output:
# It is today... but more specifically the time is:
# 1456954003.2
However, if you are trying to do this to C code, you will most likely get an error like cannot overwrite attribute. In that case, you probably want to subclass the C module.
You may want to take a look at this question.
This is the perfect time to tout my super-simplistic Hooker
def hook(hookfunc, oldfunc):
def foo(*args, **kwargs):
hookfunc(*args, **kwargs)
return oldfunc(*args, **kwargs)
return foo
Incredibly simple. It will return a function that first runs the desired hook function (with the same parameters, mind you) and will then run the original function that you are hooking and return that original value. This also works to overwrite a class method. Say we have static method in a class.
class Foo:
#staticmethod
def bar(data):
for datum in data:
print(datum, end="") # assuming python3 for this
print()
But we want to print the length of the data before we print out its elements
def myNewFunction(data):
print("The length is {}.".format(len(data)))
And now we simple hook the function
Foo.bar(["a", "b", "c"])
# => a b c
Foo.bar = hook(Foo.bar, myNewFunction)
Foo.bar(["x", "y", "z"])
# => The length is 3.
# => x y z
Actually, you can replace the target function's func_code. The example below
# a normal function
def old_func():
print "i am old"
# a class method
class A(object):
def old_method(self):
print "i am old_method"
# a closure function
def make_closure(freevar1, freevar2):
def wrapper():
print "i am old_clofunc, freevars:", freevar1, freevar2
return wrapper
old_clofunc = make_closure('fv1', 'fv2')
# ===============================================
# the new function
def new_func(*args):
print "i am new, args:", args
# the new closure function
def make_closure2(freevar1, freevar2):
def wrapper():
print "i am new_clofunc, freevars:", freevar1, freevar2
return wrapper
new_clofunc = make_closure2('fv1', 'fv2')
# ===============================================
# hook normal function
old_func.func_code = new_func.func_code
# hook class method
A.old_method.im_func.func_code = new_func.func_code
# hook closure function
# Note: the closure function's `co_freevars` count should be equal
old_clofunc.func_code = new_clofunc.func_code
# ===============================================
# call the old
old_func()
A().old_method()
old_clofunc()
output:
i am new, args: ()
i am new, args: (<__main__.A object at 0x0000000004A5AC50>,)
i am new_clofunc, freevars: fv1 fv2
I want to build a view_functions dictionary by call my decorate!
view_functions = {}
def route(rule):
def _route(function_name):
def __route(function_arg):
view_functions[rule] = function_name
return __route
return _route
if __name__ == '__main__':
#route('hey')
def hello(arg):
print 'hello ',arg
#hello('ap') if you have no call the function directly,you will got view_function have no key 'hey' ...That's my question!
view_functions['hey']('pp')
How can I just simple put the decorate above view_function (just like Flask) and then my view_functions dictionary will fill itself?
Your dict assignment is at the wrong level. It needs to be at the outer one, which is called at definition time. In this instance, the inner function doesn't actually need to do anything (apart from calling the decorated function, of course).
view_functions = {}
def route(rule):
def _route(function_name):
view_functions[rule] = function_name
def __route(function_arg):
function_name(function_arg)
return __route
return _route
Also note your definition of hello shouldn't be inside the if __name__ block.
Why can two functions with the same id value have differing attributes like __doc__ or __name__?
Here's a toy example:
some_dict = {}
for i in range(2):
def fun(self, *args):
print i
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
some_dict["function_{}".format(i)] = fun
my_type = type("my_type", (object,), some_dict)
m = my_type()
print id(m.function_0)
print id(m.function_1)
print m.function_0.__doc__
print m.function_1.__doc__
print m.function_0.__name__
print m.function_1.__name__
print m.function_0()
print m.function_1()
Which prints:
57386560
57386560
I am function 0
I am function 1
function_0
function_1
1 # <--- Why is it bound to the most recent value of that variable?
1
I've tried mixing in a call to copy.deepcopy (not sure if the recursive copy is needed for functions or it is overkill) but this doesn't change anything.
You are comparing methods, and method objects are created anew each time you access one on an instance or class (via the descriptor protocol).
Once you tested their id() you discard the method again (there are no references to it), so Python is free to reuse the id when you create another method. You want to test the actual functions here, by using m.function_0.__func__ and m.function_1.__func__:
>>> id(m.function_0.__func__)
4321897240
>>> id(m.function_1.__func__)
4321906032
Method objects inherit the __doc__ and __name__ attributes from the function that they wrap. The actual underlying functions are really still different objects.
As for the two functions returning 1; both functions use i as a closure; the value for i is looked up when you call the method, not when you created the function. See Local variables in Python nested functions.
The easiest work-around is to add another scope with a factory function:
some_dict = {}
for i in range(2):
def create_fun(i):
def fun(self, *args):
print i
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
return fun
some_dict["function_{}".format(i)] = create_fun(i)
Per your comment on ndpu's answer, here is one way you can create the functions without needing to have an optional argument:
for i in range(2):
def funGenerator(i):
def fun1(self, *args):
print i
return fun1
fun = funGenerator(i)
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
some_dict["function_{}".format(i)] = fun
#Martjin Pieters is perfectly correct. To illustrate, try this modification
some_dict = {}
for i in range(2):
def fun(self, *args):
print i
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
some_dict["function_{}".format(i)] = fun
print "id",id(fun)
my_type = type("my_type", (object,), some_dict)
m = my_type()
print id(m.function_0)
print id(m.function_1)
print m.function_0.__doc__
print m.function_1.__doc__
print m.function_0.__name__
print m.function_1.__name__
print m.function_0()
print m.function_1()
c = my_type()
print c
print id(c.function_0)
You see that the fun get's a different id each time, and is different from the final one. It's the method creation logic that send's it pointing to the same location, as that's where the class's code is stored. Also, if you use the my_type as a sort of class, instances created with it have the same memory address for that function
This code gives:
id 4299601152
id 4299601272
4299376112
4299376112
I am function 0
I am function 1
function_0
function_1
1
None
1
None
<main.my_type object at 0x10047c350>
4299376112
You should save current i to make this:
1 # <--- Why is it bound to the most recent value of that variable?
1
work, for example by setting default value to function argument:
for i in range(2):
def fun(self, i=i, *args):
print i
# ...
or create a closure:
for i in range(2):
def f(i):
def fun(self, *args):
print i
return fun
fun = f(i)
# ...