Represent a function by a mathematical function - python

Is it possible to output a mathematical function directly from the function implementation ?
class MyFunction:
def __init__(self, func):
self.func = func
def math_representation(self):
# returns a string representation of self.func
f = lambda x: 3*x**2
myFunc = MyFunction(f)
print(myFunc.math_reprentation()) #prints something like 3*x**2
Of course constructing the object with the representation as a parameter is possible, and is a trivial solution. But the idea is to generate this representation.
I could also build the function with objects representing the math operations, but the idea is to do it on a regular (lambda) function.
I really don't see a way for this to happen, but I'm curious.
Thanks for any help and suggestion

As I said, you can use SymPy if you want this to be more complex, but for simple functions (and trusted inputs), you could do something like this:
class MathFunction(object):
def __init__(self, code):
self.code = code
self._func = eval("lambda x: " + code)
def __call__(self, arg):
return self._func(arg)
def __repr__(self):
return "f(x) = " + self.code
You can use it like this:
>>> sq = MathFunction("x**2")
>>> sq
f(x) = x**2
>>> sq(7)
49
This is a bit restricted, of course (only using the variable called "x", and only one parameter), but it can be, of course, expanded.

Related

Ways to define and use partially bound functions

The two ways I'm aware of to have a partially-bound function that can be later called is:
apply_twice = lambda f: lambda x: f(f(x))
square2x = apply_twice(lambda x: x*x)
square2x(2)
# 16
And
def apply_twice(f):
def apply(x):
return f(f(x))
return apply
square_2x=apply_twice(lambda x: x*x)
square_2x(4)
# 256
Are there any other common ways to pass around or use partially-bound functions?
functools.partial can be used to partially apply an ordinary Python function. This is especially useful if you already have a regular function and want to apply only some of the arguments.
from functools import partial
def apply_twice(f, x):
return f(f(x))
square2x = partial(apply_twice, lambda x: x*x)
print(square2x(4))
It's also important to remember that functions are only one type of callable in Python, and we're free to define callables ourselves as ordinary user-defined classes. So if you have some complex operation that you want to behave like a function, you can always write a class, which lets you document in more detail what it is and what the different parts mean.
class MyApplyTwice:
def __init__(self, f):
self.f = f
def __call__(self, x):
return self.f(self.f(x))
square2x = MyApplyTwice(lambda x: x*x)
print(square2x(4))
While overly verbose in this example, it can be helpful to write your function out as a class if it's going to be storing state long-term or might be doing confusing mutable things with its state. It's also useful to keep in mind for learning purposes, as it's a healthy reminder that closures and objects are two sides of the same coin. They're really the same thing, viewed in a different light.
You can also do this with functools.partial():
def apply_twice(f, x):
return f(f(x))
square_2x = functools.partial(apply_twice, lambda x: x*x)
This isn't really partial binding, assuming you mean partial application.
Partial application is when you create a function that does the same thing as another function by fixing some number of its arguments, producing a function of smaller arity (the arity of a function is the number of arugments it takes).
So, for example,
def foo(a, b, c):
return a + b + c
A partially applied version of foo would be something like:
def partial_foo(a, b):
return foo(a, b, 42)
Or, with a lambda expression:
partial_foo = lambda a, b: foo(a, b, 42)
However, note, the above goes against the official style guidelines, in PEP8, you shouldn't assign the result of lambda expressions to a name, if you are going to do that just use a full function defintion.
The module, functools, has a helper for partial application:
import functools
partial_foo = functools.partial(foo, c=42)
Note, you may have heard about "currying", which sometimes gets confused for partial application. Currying is when you decompose a n-arity function into N, 1-arity functions. So, more concretely, for foo:
curried_foo = lambda a: lambda b: lambda c: a + b + c
Or in long form:
def curried_foo(a):
def _curr0(b):
def _curr1(c):
return a + b + c
return _curr1
return _curr0
And the important part, curried_foo(1)(2)(3) == foo(1, 2, 3)

Producing combinations of lambda functions compositions

I am facing a challenging issue in order to make my Python3 code more elegant.
Suppose I have a number function with variable number of different inputs, for example something like this:
def fun1(a,b):
return a+b
def fun2(c,d,e):
return c*d + e
def fun3(x):
return x*x
These functions needs to be agglomerated in a single function that needs to be used as the optimization function of a numerical solver.
However I need to create different combinations of various operations with these functions, like for example multiplying the output of the first two functions and summing by the third.
The manual solution is to create a specific lambda function:
fun = lambda x : fun1(x[0],x[1])*fun2(x[2],x[3],x[4]) + fun3(x[4])
but the number of functions I have is large and I need to produce all the possibile combinations of them.
I would like to systematically be able to compose these functions and always knowing the mapping from the arguments of higher level function fun to the lower level arguments of each single function.
In this case I manually specified that x[0] corresponds to the argument a of fun1, x[1] corresponds to argument b of fun1 etcetera.
Any idea?
It sounds like you are trying to do what is known as symbolic regression. This problem is often solved via some variation on genetic algorithms which encode the functional relationships in the genes and then optimise based on a fitness function which includes the prediction error as well as a term which penalises more complicated relationships.
Here are two libraries which solve this problem for you:
GPLearn
dcgpy
The following classes provide a rudimentary way of composing functions and keeping track of the number of arguments each one requires, which appears to be the main problem you have:
class Wrapper:
def __init__(self, f):
self.f = f
self.n = f.__code__.co_argcount
def __call__(self, x):
return self.f(*x)
def __add__(self, other):
return Add(self, other)
def __mul__(self, other):
return Mul(self, other)
class Operator:
def __init__(self, left, right):
self.left = left
self.right = right
self.n = left.n + right.n
class Mul(Operator):
def __call__(self, x):
return self.left(x[:self.left.n]) * self.right(x[self.left.n:])
class Add(Operator):
def __call__(self, x):
return self.left(x[:self.left.n]) + self.right(x[self.left.n:])
To use them, you first create wrappers for each of your functions:
w1 = Wrapper(fun1)
w2 = Wrapper(fun2)
w3 = Wrapper(fun3)
Then you can add and multiply the wrappers to get a new function-like object:
(w1 + w2*w3)([1, 2, 3, 4, 5, 6])
This could be a solution:
def fun1(a,b):
return a+b
def fun2(c,d,e):
return c+d+e
def compose(f1,f2):
n1 = len(f1.__code__.co_varnames)
n2 = len(f2.__code__.co_varnames)
F1 = lambda x : f1(*[x[i] for i in range(0,n1)])*f2(*[x[i] for i in range(n1,n1+n2)])
return F1
print(compose(fun1,fun2)([1,2,3,4,5]))

From Haskell to Python: how to do currying?

I recently started coding in Python and I was wondering if it's possible to return a function that specializes another function.
For example, in Haskell you can create a function that adds 5 to any given number like this:
sumFive = (+5)
Is it somehow possible in Python?
I think the other answers are misunderstanding the question. I believe the OP is asking about partial application of a function, in his example the function is (+).
If the goal isn't partial application, the solution is as simple as:
def sumFive(x): return x + 5
For partial application in Python, we can use this function: https://docs.python.org/2/library/functools.html#functools.partial
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
Then, we must turn the + operator into a function (I don't believe there's a lightweight syntax to do so like in Haskell):
def plus(x, y): return x + y
Finally:
sumFive = partial(plus, 5)
Not nearly as nice as in Haskell, but it works:
>>> sumFive(7)
12
Python's design does not naturally support the evaluation of a multi-variable function into a sequence of single-variable functions (currying). As other answers point out, the related (but distinct) concept of partial application is more straightforward to do using partial from the functools module.
However, the PyMonad library supplies you with the tools to make currying possible in Python, providing a "collection of classes for programming with functors, applicative functors and monads."
Use the curry decorator to decorate a function that accepts any number of arguments:
from pymonad import curry
#curry
def add(x, y):
return x + y
It is then very easy to curry add. The syntax is not too dissimilar to Haskell's:
>>> add5 = add(5)
>>> add5(12)
17
Note that here the add and add5 functions are instances of PyMonad's Reader monad class, not a normal Python function object:
>>> add
<pymonad.Reader.Reader at 0x7f7024ccf908>
This allows, for example, the possibility of using simpler syntax to compose functions (easy to do in Haskell, normally much less so in Python).
Finally, it's worth noting that the infix operator + is not a Python function: + calls into the left-hand operand's __add__ method, or the right-hand operand's __radd__ method and returns the result. You'll need to decorate these class methods for the objects you're working with if you want to curry using + (disclaimer: I've not tried to do this yet).
Yup. Python supports lambda expressions:
sumFive = lambda x: x + 5
for i in range(5):
print sumFive(i),
#OUTPUT 5,6,7,8,9
Python functions can return functions, allowing you to create higher-order functions. For example, here is a higher-order function which can specialize a function of two variables:
def specialize(f,a,i):
def g(x):
if i == 0:
return f(a,x)
else:
return f(x,a)
return g
Used like this:
>>> def subtract(x,y): return x - y
>>> f = specialize(subtract,5,0)
>>> g = specialize(subtract,5,1)
>>> f(7)
-2
>>> g(7)
2
But -- there is really no need to reinvent the wheel, the module functools has a number of useful higher-order functions that any Haskell programmer would find useful, including partial for partial function application, which is what you are asking about.
As it was pointed out, python does have lambda functions, so the following does solve the problem:
# Haskell: sumFive = (+5)
sumFive = lambda x : x + 5
I think this is more useful with the fact that python has first class functions (1,2)
def summation(n, term):
total, k = 0, 1
while k <= n:
total, k = total + term(k), k + 1
return total
def identity(x):
return x
def sum_naturals(n):
return summation(n, identity)
sum_naturals(10) # Returns 55
# Now for something a bit more complex
def pi_term(x):
return 8 / ((4*x-3) * (4*x-1))
def pi_sum(n):
return summation(n, pi_term)
pi_sum(1e6) # returns: 3.141592153589902
You can find more on functional programming and python here
For the most generic Haskell style currying, look at partial from the functools module.

product of two functions

I have two functions, f and g. Both have the same signature: (x). I want to create a new function, z, with the same signature:
def z(x):
return f(x) * g(x)
except that I'd like to be able to write
z = f * g instead of the above code. Is it possible?
Something close is possible:
z = lambda x: f(x) * g(x)
Personally, I find this way more intuitive than z = f * g, because mathematically, multiplying functions doesn't mean anything. Depending on the interpretation of the * operator, it may mean composition so z(x) = f(g(x)), but definitely not multiplication of the results of invocation. On the other hand, the lambda above is very explicit, and frankly requires just a bit more characters to write.
Update: Kudos to JBernardo for hacking it together. I was imagining it would be much more hacky than in turned out. Still, I would advise against using this in real code.
The funny thing is that it is quite possible. I made a project some days ago to do things like that.
Here it is: FuncBuilder
By now you can only define variables, but you can use my metaclass with the help of some other functions to build a class to what you want.
Problems:
It's slow
It's really slow
You think you want that but describing functions the way they meant to be described is the right way.
You should use your first code.
Just as a proof of concept:
from funcbuilder import OperatorMachinery
class FuncOperations(metaclass=OperatorMachinery):
def __init__(self, function):
self.func = function
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def func(self, *n, oper=None):
if not n:
return type(self)(lambda x: oper(self.func(x)))
return type(self)(lambda x: oper(self.func(x), n[0](x)))
FuncOperations.apply_operators([func, func])
Now you can code like that:
#FuncOperations
def f(x):
return x + 1
#FuncOperations
def g(x):
return x + 2
And the desired behavior is:
>>> z = f * g
>>> z(3)
20
I added a better version of it on the FuncBuilder project. It works with any operation between a FuncOperation object and another callable. Also works on unary operations. :D
You can play with it to make functions like:
z = -f + g * h
I can be done with the exact syntax you intended (though using lambda might be better), by using a decorator. As stated, functions don't have operators defined for them, but objects can be made to be callable just like functions in Python --
So the decorator bellow just wraps the function in an object for which the multiplication for another function is defined:
class multipliable(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kw):
return self.func(*args, **kw)
def __mul__(self, other):
#multipliable
def new_func(*args, **kw):
return self.func(*args, **kw) * other(*args, **kw)
return new_func
#multipliable
def x():
return 2
(tested in Python 2 and Python 3)
def y():
return 3
z = x * y
z()

What does the "at" (#) symbol do in Python?

What does the # symbol do in Python?
An # symbol at the beginning of a line is used for class and function decorators:
PEP 318: Decorators
Python Decorators
The most common Python decorators are:
#property
#classmethod
#staticmethod
An # in the middle of a line is probably matrix multiplication:
# as a binary operator.
Example
class Pizza(object):
def __init__(self):
self.toppings = []
def __call__(self, topping):
# When using '#instance_of_pizza' before a function definition
# the function gets passed onto 'topping'.
self.toppings.append(topping())
def __repr__(self):
return str(self.toppings)
pizza = Pizza()
#pizza
def cheese():
return 'cheese'
#pizza
def sauce():
return 'sauce'
print pizza
# ['cheese', 'sauce']
This shows that the function/method/class you're defining after a decorator is just basically passed on as an argument to the function/method immediately after the # sign.
First sighting
The microframework Flask introduces decorators from the very beginning in the following format:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
This in turn translates to:
rule = "/"
view_func = hello
# They go as arguments here in 'flask/app.py'
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
pass
Realizing this finally allowed me to feel at peace with Flask.
In Python 3.5 you can overload # as an operator. It is named as __matmul__, because it is designed to do matrix multiplication, but it can be anything you want. See PEP465 for details.
This is a simple implementation of matrix multiplication.
class Mat(list):
def __matmul__(self, B):
A = self
return Mat([[sum(A[i][k]*B[k][j] for k in range(len(B)))
for j in range(len(B[0])) ] for i in range(len(A))])
A = Mat([[1,3],[7,5]])
B = Mat([[6,8],[4,2]])
print(A # B)
This code yields:
[[18, 14], [62, 66]]
This code snippet:
def decorator(func):
return func
#decorator
def some_func():
pass
Is equivalent to this code:
def decorator(func):
return func
def some_func():
pass
some_func = decorator(some_func)
In the definition of a decorator you can add some modified things that wouldn't be returned by a function normally.
What does the “at” (#) symbol do in Python?
In short, it is used in decorator syntax and for matrix multiplication.
In the context of decorators, this syntax:
#decorator
def decorated_function():
"""this function is decorated"""
is equivalent to this:
def decorated_function():
"""this function is decorated"""
decorated_function = decorator(decorated_function)
In the context of matrix multiplication, a # b invokes a.__matmul__(b) - making this syntax:
a # b
equivalent to
dot(a, b)
and
a #= b
equivalent to
a = dot(a, b)
where dot is, for example, the numpy matrix multiplication function and a and b are matrices.
How could you discover this on your own?
I also do not know what to search for as searching Python docs or Google does not return relevant results when the # symbol is included.
If you want to have a rather complete view of what a particular piece of python syntax does, look directly at the grammar file. For the Python 3 branch:
~$ grep -C 1 "#" cpython/Grammar/Grammar
decorator: '#' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
--
testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
augassign: ('+=' | '-=' | '*=' | '#=' | '/=' | '%=' | '&=' | '|=' | '^=' |
'<<=' | '>>=' | '**=' | '//=')
--
arith_expr: term (('+'|'-') term)*
term: factor (('*'|'#'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power
We can see here that # is used in three contexts:
decorators
an operator between factors
an augmented assignment operator
Decorator Syntax:
A google search for "decorator python docs" gives as one of the top results, the "Compound Statements" section of the "Python Language Reference." Scrolling down to the section on function definitions, which we can find by searching for the word, "decorator", we see that... there's a lot to read. But the word, "decorator" is a link to the glossary, which tells us:
decorator
A function returning another function, usually applied as a function transformation using the #wrapper syntax. Common
examples for decorators are classmethod() and staticmethod().
The decorator syntax is merely syntactic sugar, the following two
function definitions are semantically equivalent:
def f(...):
...
f = staticmethod(f)
#staticmethod
def f(...):
...
The same concept exists for classes, but is less commonly used there.
See the documentation for function definitions and class definitions
for more about decorators.
So, we see that
#foo
def bar():
pass
is semantically the same as:
def bar():
pass
bar = foo(bar)
They are not exactly the same because Python evaluates the foo expression (which could be a dotted lookup and a function call) before bar with the decorator (#) syntax, but evaluates the foo expression after bar in the other case.
(If this difference makes a difference in the meaning of your code, you should reconsider what you're doing with your life, because that would be pathological.)
Stacked Decorators
If we go back to the function definition syntax documentation, we see:
#f1(arg)
#f2
def func(): pass
is roughly equivalent to
def func(): pass
func = f1(arg)(f2(func))
This is a demonstration that we can call a function that's a decorator first, as well as stack decorators. Functions, in Python, are first class objects - which means you can pass a function as an argument to another function, and return functions. Decorators do both of these things.
If we stack decorators, the function, as defined, gets passed first to the decorator immediately above it, then the next, and so on.
That about sums up the usage for # in the context of decorators.
The Operator, #
In the lexical analysis section of the language reference, we have a section on operators, which includes #, which makes it also an operator:
The following tokens are operators:
+ - * ** / // % #
<< >> & | ^ ~
< > <= >= == !=
and in the next page, the Data Model, we have the section Emulating Numeric Types,
object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__matmul__(self, other)
object.__truediv__(self, other)
object.__floordiv__(self, other)
[...]
These methods are called to implement the binary arithmetic operations (+, -, *, #, /, //, [...]
And we see that __matmul__ corresponds to #. If we search the documentation for "matmul" we get a link to What's new in Python 3.5 with "matmul" under a heading "PEP 465 - A dedicated infix operator for matrix multiplication".
it can be implemented by defining __matmul__(), __rmatmul__(), and
__imatmul__() for regular, reflected, and in-place matrix multiplication.
(So now we learn that #= is the in-place version). It further explains:
Matrix multiplication is a notably common operation in many fields of
mathematics, science, engineering, and the addition of # allows
writing cleaner code:
S = (H # beta - r).T # inv(H # V # H.T) # (H # beta - r)
instead of:
S = dot((dot(H, beta) - r).T,
dot(inv(dot(dot(H, V), H.T)), dot(H, beta) - r))
While this operator can be overloaded to do almost anything, in numpy, for example, we would use this syntax to calculate the inner and outer product of arrays and matrices:
>>> from numpy import array, matrix
>>> array([[1,2,3]]).T # array([[1,2,3]])
array([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
>>> array([[1,2,3]]) # array([[1,2,3]]).T
array([[14]])
>>> matrix([1,2,3]).T # matrix([1,2,3])
matrix([[1, 2, 3],
[2, 4, 6],
[3, 6, 9]])
>>> matrix([1,2,3]) # matrix([1,2,3]).T
matrix([[14]])
Inplace matrix multiplication: #=
While researching the prior usage, we learn that there is also the inplace matrix multiplication. If we attempt to use it, we may find it is not yet implemented for numpy:
>>> m = matrix([1,2,3])
>>> m #= m.T
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: In-place matrix multiplication is not (yet) supported. Use 'a = a # b' instead of 'a #= b'.
When it is implemented, I would expect the result to look like this:
>>> m = matrix([1,2,3])
>>> m #= m.T
>>> m
matrix([[14]])
What does the “at” (#) symbol do in Python?
# symbol is a syntactic sugar python provides to utilize decorator,
to paraphrase the question, It's exactly about what does decorator do in Python?
Put it simple decorator allow you to modify a given function's definition without touch its innermost (it's closure).
It's the most case when you import wonderful package from third party. You can visualize it, you can use it, but you cannot touch its innermost and its heart.
Here is a quick example,
suppose I define a read_a_book function on Ipython
In [9]: def read_a_book():
...: return "I am reading the book: "
...:
In [10]: read_a_book()
Out[10]: 'I am reading the book: '
You see, I forgot to add a name to it.
How to solve such a problem? Of course, I could re-define the function as:
def read_a_book():
return "I am reading the book: 'Python Cookbook'"
Nevertheless, what if I'm not allowed to manipulate the original function, or if there are thousands of such function to be handled.
Solve the problem by thinking different and define a new_function
def add_a_book(func):
def wrapper():
return func() + "Python Cookbook"
return wrapper
Then employ it.
In [14]: read_a_book = add_a_book(read_a_book)
In [15]: read_a_book()
Out[15]: 'I am reading the book: Python Cookbook'
Tada, you see, I amended read_a_book without touching it inner closure. Nothing stops me equipped with decorator.
What's about #
#add_a_book
def read_a_book():
return "I am reading the book: "
In [17]: read_a_book()
Out[17]: 'I am reading the book: Python Cookbook'
#add_a_book is a fancy and handy way to say read_a_book = add_a_book(read_a_book), it's a syntactic sugar, there's nothing more fancier about it.
If you are referring to some code in a python notebook which is using Numpy library, then # operator means Matrix Multiplication. For example:
import numpy as np
def forward(xi, W1, b1, W2, b2):
z1 = W1 # xi + b1
a1 = sigma(z1)
z2 = W2 # a1 + b2
return z2, a1
Decorators were added in Python to make function and method wrapping (a function that receives a function and returns an enhanced one) easier to read and understand. The original use case was to be able to define the methods as class methods or static methods on the head of their definition. Without the decorator syntax, it would require a rather sparse and repetitive definition:
class WithoutDecorators:
def some_static_method():
print("this is static method")
some_static_method = staticmethod(some_static_method)
def some_class_method(cls):
print("this is class method")
some_class_method = classmethod(some_class_method)
If the decorator syntax is used for the same purpose, the code is shorter and easier to understand:
class WithDecorators:
#staticmethod
def some_static_method():
print("this is static method")
#classmethod
def some_class_method(cls):
print("this is class method")
General syntax and possible implementations
The decorator is generally a named object ( lambda expressions are not allowed) that accepts a single argument when called (it will be the decorated function) and returns another callable object. "Callable" is used here instead of "function" with premeditation. While decorators are often discussed in the scope of methods and functions, they are not limited to them. In fact, anything that is callable (any object that implements the _call__ method is considered callable), can be used as a decorator and often objects returned by them are not simple functions but more instances of more complex classes implementing their own __call_ method.
The decorator syntax is simply only a syntactic sugar. Consider the following decorator usage:
#some_decorator
def decorated_function():
pass
This can always be replaced by an explicit decorator call and function reassignment:
def decorated_function():
pass
decorated_function = some_decorator(decorated_function)
However, the latter is less readable and also very hard to understand if multiple decorators are used on a single function.
Decorators can be used in multiple different ways as shown below:
As a function
There are many ways to write custom decorators, but the simplest way is to write a function that returns a subfunction that wraps the original function call.
The generic patterns is as follows:
def mydecorator(function):
def wrapped(*args, **kwargs):
# do some stuff before the original
# function gets called
result = function(*args, **kwargs)
# do some stuff after function call and
# return the result
return result
# return wrapper as a decorated function
return wrapped
As a class
While decorators almost always can be implemented using functions, there are some situations when using user-defined classes is a better option. This is often true when the decorator needs complex parametrization or it depends on a specific state.
The generic pattern for a nonparametrized decorator as a class is as follows:
class DecoratorAsClass:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
# do some stuff before the original
# function gets called
result = self.function(*args, **kwargs)
# do some stuff after function call and
# return the result
return result
Parametrizing decorators
In real code, there is often a need to use decorators that can be parametrized. When the function is used as a decorator, then the solution is simple—a second level of wrapping has to be used. Here is a simple example of the decorator that repeats the execution of a decorated function the specified number of times every time it is called:
def repeat(number=3):
"""Cause decorated function to be repeated a number of times.
Last value of original function call is returned as a result
:param number: number of repetitions, 3 if not specified
"""
def actual_decorator(function):
def wrapper(*args, **kwargs):
result = None
for _ in range(number):
result = function(*args, **kwargs)
return result
return wrapper
return actual_decorator
The decorator defined this way can accept parameters:
>>> #repeat(2)
... def foo():
... print("foo")
...
>>> foo()
foo
foo
Note that even if the parametrized decorator has default values for its arguments, the parentheses after its name is required. The correct way to use the preceding decorator with default arguments is as follows:
>>> #repeat()
... def bar():
... print("bar")
...
>>> bar()
bar
bar
bar
Finally lets see decorators with Properties.
Properties
The properties provide a built-in descriptor type that knows how to link an attribute to a set of methods. A property takes four optional arguments: fget , fset , fdel , and doc . The last one can be provided to define a docstring that is linked to the attribute as if it were a method. Here is an example of a Rectangle class that can be controlled either by direct access to attributes that store two corner points or by using the width , and height properties:
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
def _width_get(self):
return self.x2 - self.x1
def _width_set(self, value):
self.x2 = self.x1 + value
def _height_get(self):
return self.y2 - self.y1
def _height_set(self, value):
self.y2 = self.y1 + value
width = property(
_width_get, _width_set,
doc="rectangle width measured from left"
)
height = property(
_height_get, _height_set,
doc="rectangle height measured from top"
)
def __repr__(self):
return "{}({}, {}, {}, {})".format(
self.__class__.__name__,
self.x1, self.y1, self.x2, self.y2
)
The best syntax for creating properties is using property as a decorator. This will reduce the number of method signatures inside of the class
and make code more readable and maintainable. With decorators the above class becomes:
class Rectangle:
def __init__(self, x1, y1, x2, y2):
self.x1, self.y1 = x1, y1
self.x2, self.y2 = x2, y2
#property
def width(self):
"""rectangle height measured from top"""
return self.x2 - self.x1
#width.setter
def width(self, value):
self.x2 = self.x1 + value
#property
def height(self):
"""rectangle height measured from top"""
return self.y2 - self.y1
#height.setter
def height(self, value):
self.y2 = self.y1 + value
Starting with Python 3.5, the '#' is used as a dedicated infix symbol for MATRIX MULTIPLICATION (PEP 0465 -- see https://www.python.org/dev/peps/pep-0465/)
# can be a math operator or a DECORATOR but what you mean is a decorator.
This code:
def func(f):
return f
func(lambda :"HelloWorld")()
using decorators can be written like:
def func(f):
return f
#func
def name():
return "Hello World"
name()
Decorators can have arguments.
You can see this GeeksforGeeks post: https://www.geeksforgeeks.org/decorators-in-python/
It indicates that you are using a decorator. Here is Bruce Eckel's example from 2008.
Python decorator is like a wrapper of a function or a class. It’s still too conceptual.
def function_decorator(func):
def wrapped_func():
# Do something before the function is executed
func()
# Do something after the function has been executed
return wrapped_func
The above code is a definition of a decorator that decorates a function.
function_decorator is the name of the decorator.
wrapped_func is the name of the inner function, which is actually only used in this decorator definition. func is the function that is being decorated.
In the inner function wrapped_func, we can do whatever before and after the func is called. After the decorator is defined, we simply use it as follows.
#function_decorator
def func():
pass
Then, whenever we call the function func, the behaviours we’ve defined in the decorator will also be executed.
EXAMPLE :
from functools import wraps
def mydecorator(f):
#wraps(f)
def wrapped(*args, **kwargs):
print "Before decorated function"
r = f(*args, **kwargs)
print "After decorated function"
return r
return wrapped
#mydecorator
def myfunc(myarg):
print "my function", myarg
return "return value"
r = myfunc('asdf')
print r
Output :
Before decorated function
my function asdf
After decorated function
return value
To say what others have in a different way: yes, it is a decorator.
In Python, it's like:
Creating a function (follows under the # call)
Calling another function to operate on your created function. This returns a new function. The function that you call is the argument of the #.
Replacing the function defined with the new function returned.
This can be used for all kinds of useful things, made possible because functions are objects and just necessary just instructions.
# symbol is also used to access variables inside a plydata / pandas dataframe query, pandas.DataFrame.query.
Example:
df = pandas.DataFrame({'foo': [1,2,15,17]})
y = 10
df >> query('foo > #y') # plydata
df.query('foo > #y') # pandas

Categories

Resources