Python deep nesting factory functions - python

Working through "Learning Python" came across factory function. This textbook example works:
def maker(N):
def action(X):
return X ** N
return action
>>> maker(2)
<function action at 0x7f9087f008c0>
>>> o = maker(2)
>>> o(3)
8
>>> maker(2)
<function action at 0x7f9087f00230>
>>> maker(2)(3)
8
However when going deeper another level I have no idea how to call it:
>>> def superfunc(X):
... def func(Y):
... def subfunc(Z):
... return X + Y + Z
... return func
...
>>> superfunc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: superfunc() takes exactly 1 argument (0 given)
>>> superfunc(1)
<function func at 0x7f9087f09500>
>>> superfunc(1)(2)
>>> superfunc(1)(2)(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
>>> superfunc(1)(2)
>>>
Why doesn't superfunc(1)(2)(3) work while maker(2)(3) does?
While this kind of nesting certainly doesn't look like a good, usable code to me, Python still accepts it as valid, so I'm curious as to how this can be called.

You get a TypeError because function func doesn't return anything (thus its return is NoneType). It should return subfunc:
>>> def superfunc(X):
... def func(Y):
... def subfunc(Z):
... return X + Y + Z
... return subfunc
... return func
...

A return is missing somewhere in your superfunc: you have a return for subfunc, but none for func.

superfunc corrected, with a calling example
def superfunc(X):
def func(Y):
def subfunc(Z):
return X + Y + Z
return subfunc
return func
print superfunc(1)(2)(3)

You forgot the return of the second function.
Here is the fixed function
def superfunct(x):
def func(y):
def subfunc(z):
return x + y + z
return subfunc
return func
print superfunct(1)(2)(3)

Related

How do I count the number of calls of a function in Python 3.6?

I want to count the number of calls of the function f inside of inc. How should I modify the function main to do it?
I have this code:
def inc(f):
f()
f()
def main():
a = 0
def f():
a += 1
inc(f)
print(a) # should print 2
main()
But it leads to the error:
Traceback (most recent call last):
File "main.py", line 11, in <module>
main()
File "main.py", line 9, in main
inc(f)
File "main.py", line 2, in inc
f()
File "main.py", line 8, in f
a += 1
UnboundLocalError: local variable 'a' referenced before assignment
The usual way is to create an attribute func.invocations for your function func, like
def func(a):
func.invocations += 1
return a + 1
func.invocations = 0
and use it like
func(1) # 2
func(10) # 11
func.invocations # 2
To make the whole thing more reusable and readable you can also create a decorator counter that allows you to count the number of calls on any function you like:
import functools
def counter(fn):
#functools.wraps(fn)
def helper(*args, **kargs):
helper.invocations += 1
return fn(*args, **kargs)
helper.invocations = 0
return helper
and then use it like
#counter
def func(a):
return a + 1
func(1) # 2
func(10) # 11
func.invocations # 2
def inc(f):
f()
f()
def main():
a = 0
def f():
nonlocal a
a += 1
inc(f)
print(a) # should print 2
main()
Make a nonlocal in f()
If you are looking for a simple solution, a global variable would do the trick.
reps = 0
def f():
global reps
reps += 1
# do your func stuff here
f()
f()
f()
f() # called f() 4 times
print(reps) # -> 4
You try this:
def inc(f):
f()
f()
def main():
a = 0
def f():
f.counter += 1
f.counter =0
inc(f)
print(f.counter)
main()
How functions are objects in python you can create an attribute to count the number of call to that function

call 2 functions in a function [duplicate]

This question already has answers here:
Assign multiple functions to a single variable?
(3 answers)
Closed 6 years ago.
The problem is as follows below:
Write a function compose that takes two functions as argument, we call them Fa and Fb, and returns a function, Fres, that means that outdata from the other function is indata to the first, ex: Fres(x) = Fa(Fb(x)).
run example:
>>> def multiply_five(n):
... return n * 5
...
>>> def add_ten(x):
... return x + 10
...
>>> composition = compose(multiply_five, add_ten)
>>> composition(3)
65
>>> another_composition = compose(add_ten, multiply_five)
>>> another_composition(3)
25
So as I understand this if I send in 3 the function compose will take 3+10 = 13
after that send that result into the multiply function it will do: 13*5 witch is 65.
this is the code I've written so far:
def multiply_five(n):
return n*5
def add_ten(x):
return x+10
def compose(func1, func2):
def comp(arg):
return func2(arg)
return func1(comp(arg))
I get compile error, and I've tried some different approaches:
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
composition = compose(multiply_five, add_ten)
File "C:\Users\Jim\Desktop\tdp002\5h.py", line 10, in compose
return func1(comp(arg))
NameError: name 'arg' is not defined
You don't want to call either func1 or func2 yet; you just want to return a function that will call them both.
def compose(func1, func2):
def _(*args, **kw):
return func1(func2(*args, **kw))
return _
You could also just use a lambda expression to create the composed function.
def compose(func1, func2):
return lambda *args, **kw: func1(func2(*args, **kw))
Try this:
def compose(func1, func2):
def comp(arg):
return func1(func2(arg))
return comp

Argument existence by assert statement in python

Is there any way to check the existence of argument of a function by assert statement?
def fractional(x) :
assert x==None, "argument missing" <---- is it possible here to check?
assert type(x) == int, 'x must be integer'
assert x > 0 , ' x must be positive '
output = 1
for i in range ( 1 , int(x)+1) :
output = output*i
assert output > 0 , 'output must be positive'
return output
y=3
fractional() <----- argument missing
you shouldn't have to assert the existence of the argument explicitly. if the argument isn't given when you call the function, you'll get a TypeError like:
>>> def foo(x):
... pass
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 argument (0 given)
>>>
if you wanted to ensure other properties of the argument (you mentioned only existence), you could test those properties and raise exceptions if they weren't met:
>>> def foo(x):
... if not isinstance(x, str):
... raise ValueError("argument must be a string!")
...
>>> foo(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
ValueError: argument must be a string!
>>>

<method-wrapper '__call__' of functools.partial object at 0x1356e10> is not a Python function

I'm trying to build a function which I can use as a handler for an RxPy stream that I'm mapping over. The function I have needs access to a variable outside the scope where that variable is defined which, to me, means that I need to use a closure of some kind. So I reached for functools.partial to close over the one variable and return a partial function that I can pass to as an observer to my stream.
However, doing so results in the following:
Traceback (most recent call last):
File "retry/example.py", line 46, in <module>
response_stream = message_stream.flat_map(functools.partial(message_handler, context=context))
File "/home/justin/virtualenv/retry/local/lib/python2.7/site-packages/rx/linq/observable/selectmany.py", line 67, in select_many
selector = adapt_call(selector)
File "/home/justin/virtualenv/retry/local/lib/python2.7/site-packages/rx/internal/utils.py", line 37, in adapt_call_1
argnames, varargs, kwargs = getargspec(func)[:3]
File "/usr/lib/python2.7/inspect.py", line 816, in getargspec
raise TypeError('{!r} is not a Python function'.format(func))
TypeError: <method-wrapper '__call__' of functools.partial object at 0x2ce6cb0> is not a Python function
Here is some sample code which reproduces the problem:
from __future__ import absolute_import
from rx import Observable, Observer
from pykafka import KafkaClient
from pykafka.common import OffsetType
import logging
import requests
import functools
logger = logging.basicConfig()
def puts(thing):
print thing
def message_stream(consumer):
def thing(observer):
for message in consumer:
observer.on_next(message)
return Observable.create(thing)
def message_handler(message, context=None):
def req():
return requests.get('http://httpbin.org/get')
return Observable.start(req)
def handle_response(message, response, context=None):
consumer = context['consumer']
producer = context['producer']
t = 'even' if message % 2 == 0 else 'odd'
return str(message) + ': ' + str(response) + ' - ' + t + ' | ' + str(consumer) + ' | ' + producer
consumer = ['pretend', 'these', 'are', 'kafka', 'messages']
producer = 'some producer'
context = {
'consumer': consumer,
'producer': producer
}
message_stream = message_stream(consumer)
response_stream = message_stream.flat_map(functools.partial(message_handler, context=context))
message_response_stream = message_stream.zip(response_stream, functools.partial(handle_response, context=context))
message_stream.subscribe(puts)
The problem seems to be that my partial function returns False when calling inspect.isfunction.
How can I make my partial function pass this check? Is there a way to easily convert a partial function into a "real" function type?
You're asking if it's actually a function, and it's telling you isn't not a function. It's a method-wrapper.
You want to duck-type.
>>> def printargs(*args):
... print args
>>> import inspect
>>> from functools import partial
>>> inspect.isfunction(printargs)
True
>>> f = partial(printargs, 1)
>>> inspect.isfunction(f)
False
# try duck-typing, see if the variable is callable
# check does it work for a method-wrapper?
>>> callable(f)
True
# check an integer, which should be false
>>> callable(1)
False
# ensure it works on an actual function
>>> callable(printargs)
True
This is why you duck-type. You don't care if it's a function. You care if it acts like a function.
EDIT:
You could, if desperate enough, write a class and pass a reference to a function in the class.
class A():
def __init__(self, frozen, *args, **kwds):
self.frozen = frozen
self.args = args
self.kwds = kwds
def call(self):
self.frozen(*self.args, **self.kwds)
Then just use A(f).call as your wrapper.
>>> f_ = A(f)
>>> inspect.ismethod(f_.call)
True
>>> f_.call()
(1,)
This works as long as ismethod works.
If not, you really need a decorator.
Final EDIT:
If you are truly desperate enough and don't want to write a custom decorator, you could use a lambda function with a tuple to pass to make a partial-like function.
Ex.:
>>> import inspect
>>> def printargs(*args):
... print args
>>> a = (1,2,3)
>>> f = lambda x: printargs(*x)
>>> f(a)
(1, 2, 3)
>>> inspect.isfunction(f)
True

How could I import a class from a python script into another python script?

I am trying to write a script contains some classes and save for example as model.py.
import numpy as np
from scipy import integrate
class Cosmology(object):
def __init__(self, omega_m=0.3, omega_lam=0.7):
# no quintessence, no radiation in this universe!
self.omega_m = omega_m
self.omega_lam = omega_lam
self.omega_c = (1. - omega_m - omega_lam)
#self.omega_r = 0
def a(self, z):
return 1./(1+z)
def E(self, a):
return (self.omega_m*a**(-3) + self.omega_c*a**(-2) + self.omega_lam)**0.5
def __angKernel(self, x):
return self.E(x**-1)**-1
def Da(self, z, z_ref=0):
if isinstance(z, np.ndarray):
da = np.zeros_like(z)
for i in range(len(da)):
da[i] = self.Da(z[i], z_ref)
return da
else:
if z < 0:
raise ValueError(" z is negative")
if z < z_ref:
raise ValueError(" z should not not be smaller than the reference redshift")
d = integrate.quad(self.__angKernel, z_ref+1, z+1,epsrel=1.e-6, epsabs=1.e-12)
rk = (abs(self.omega_c))**0.5
if (rk*d > 0.01):
if self.omega_c > 0:
d = sinh(rk*d)/rk
if self.omega_c < 0:
d = sin(rk*d)/rk
return d/(1+z)
Then I want to call Cosmology class into another script, but I get the following error:
>>>from model import Cosmology as cosmo
>>>print cosmo.a(1.)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method a() must be called with Cosmology instance as first argument (got int instance instead)
I don't quite understand what the problem is!! Any tips??
You are trying to call an instance method from a class. In order to use the a() method, you need to create an instance of the Cosmology class:
>>>from model import Cosmology
>>>cosmo = Cosmology()
>>>cosmo.a(1.)
0.5
Or, if you want a() to be a class method, you need to decorate it with the #classmethod decorator - see here for more details.

Categories

Resources