Calling Python functions/methods with zero arguments - python

According to Clean Code, a function should take zero arguments when at all possible.
If we take a trivial example in Python with a function that does nothing more than add 2 to whatever is passed to it:
def add_two(x):
return x + 2
>add_two(1)
3
The only way I can see that such a function can have zero arguments passed to it is by incorporating it into a class:
class Number(object):
def __init__(self, x):
self.x = x
def add_two(self):
return self.x + 2
>n = Number(1)
>n.add_two()
3
It hardly seems worth the effort. Is there another way of achieving the no-argument function in this example?

If we take a trivial example in Python with a function that does
nothing more than add 2 to whatever is passed to it:
...
Is there another way of achieving the no-argument function in this
example?
In a word, no.
In several words: by definition, your function takes an argument. There's no way to take an argument without taking an argument.

In General
That is truly bad general advice, no argument methods are great for objects that modify the object in a way that requires no external data, or for functions that only interact with globals (you should really have minimal need to do this). In your case, you need to modify a given object with external data, and both objects are a builtin type (int).
In this case, just use a function with two arguments.
Too Many Arguments
Now, here is where the advice gets good. Say I need to do a complicated task, with numerous arguments.
def complicatedfunction(arg1, arg2, arg3, arg4, arg5, arg6):
'''This requires 6 pieces of info'''
return ((arg1 + arg2) / (arg3 * arg4)) ** (arg5 + arg6)
In this case, you are making unreadable code, and you should reduce the number of arguments to 5 or less.
Reducing Argument Counts
In this case, you could pass a namedtuple:
from collections import namedtuple
Numbers = namedtuple("Numbers", "numerator denominator exponent")
mynumber = Numbers(1+2, 3+4, 5+6)
def complicatedfunction(number):
return (number.numerator / number.denominator) ** (number.exponent)
This has the added benefit of then making your code easy to modify in the future. Say I need to add another argument: I can just add that as a value into the namedtuple.
from collections import namedtuple
Numbers = namedtuple("Numbers", "numerator denominator exponent add")
mynumber = Numbers(1+2, 3+4, 5+6, 2)
def complicatedfunction(number):
value = (number.numerator / number.denominator) ** (number.exponent)
return value + number.add
Object-Oriented Design
Or, if I want to use that specific namedtuple for a lot of different tasks, I can subclass it and then get a 0-argument method for a specific goal. I can add as many methods as I want, which allows me to use the object in a versatile manner, as follows:
from collections import namedtuple
class Numbers(namedtuple("Numbers", "numerator denominator exponent add")):
def process(self):
value = (self.numerator / self.denominator) ** (self.exponent)
return value + self.add
mynumber = Numbers(1+2, 3+4, 5+6, 2)

Why don't you use default argument method
def add_two(x=0):
return x + 2
>>> add_two(1)
3
>>> add_two()
2
>>>

Related

How to set a class of mathematical functions in Python?

I would like to create a math-visualisation class in Python where I can visualise optimisation algorithms. This is what I have so far:
class function_visualisation:
def objective1n1(x):
return x**5.0 - 2*x**4 - 0.5*x**3 + 4*x**2 - x
def objective2n1(x,y):
return x**5.0 - 2*y**4 - 15*x**3 + 4*y**2 - x
def __init__(self, input = 0):
self.fct_1 = self.objective1n1(x)
self.fct_2 = self.objective2n1(x,y)
Where right now I have 2 polynomials; the first taking one and the second two inputs.
Eventually I would like the class to have several adjustable function types and plotting methods. The problem is that when trying to instanciate Python says
self.fct_1 = self.objective1n1(x)
NameError: name 'x' is not defined
which I can understand.
In various posts I saw people use an intuitive technique to define functions with numpy; e.g. :
x = np.linspace(−4*np.pi,4*np.pi,50)
y = np.linspace(−4*np.pi,4*np.pi,50)
z = x**2 + y**2
Is there a good way to get something similar such that I don't have to give the function arguments in advance?
Edit:
Thanks to both of you.
but as I commented, when I initialise and insert a concrete value
fcts = function_visualisation()
print(fcts.fct_1(5))
I get
print(fcts.fct_1(5))
TypeError: objective1n1() takes 1 positional argument but 2 were given
The reason I do want a class like this is to package different plotting methods for different dimensions together and make it easy to change the function one contemplates. So how could I fix that?
When you have a function, such as
def objective1n1(x):
return x**5.0 - 2*x**4 - 0.5*x**3 + 4*x**2 - x
Calling objective1n1(x) will calculate this function at the input x, thus x has to be defined in advance (just like in your example with np.linspace).
If you simply want to assign a function object to another variable, use:
self.fct_1 = self.objective1n1
After that, you can call self.fct_1(x) for any x later in your code.
self.objective1n1(x) is the call of the function self.objective1n1. If you simply want to change which function is behind self.fct_1, you need
self.fct_1 = self.objective1n1
If you don't need the self-reference, you can use the #staticmethod decorator. However, you might want to think about not using a class for this in the first place.
To combine the answers of Martin Thoma, Mikhail Genkin and the comment of kindall:
Calling objective1n1(x) will calculate this function at the input x, thus x has to be defined in advance (just like in the example with np.linspace).
If one simply wants to assign a function object to another variable, use:
self.fct_1 = self.objective1n1
To be able to call the function like this
fcts = function_visualisation()
print(fcts.fct_1(5))
one has to define it either with a #staticmethod decorator
#staticmethod
def objective1n1(x):
return x**5.0 - 2*x**4 - 0.5*x**3 + 4*x**2 - x
or with a self reference
def objective1n1(self,x):
return x**5.0 - 2*x**4 - 0.5*x**3 + 4*x**2 - x

How can I convert object attributes in mutable in Python? [duplicate]

How can I pass an integer by reference in Python?
I want to modify the value of a variable that I am passing to the function. I have read that everything in Python is pass by value, but there has to be an easy trick. For example, in Java you could pass the reference types of Integer, Long, etc.
How can I pass an integer into a function by reference?
What are the best practices?
It doesn't quite work that way in Python. Python passes references to objects. Inside your function you have an object -- You're free to mutate that object (if possible). However, integers are immutable. One workaround is to pass the integer in a container which can be mutated:
def change(x):
x[0] = 3
x = [1]
change(x)
print x
This is ugly/clumsy at best, but you're not going to do any better in Python. The reason is because in Python, assignment (=) takes whatever object is the result of the right hand side and binds it to whatever is on the left hand side *(or passes it to the appropriate function).
Understanding this, we can see why there is no way to change the value of an immutable object inside a function -- you can't change any of its attributes because it's immutable, and you can't just assign the "variable" a new value because then you're actually creating a new object (which is distinct from the old one) and giving it the name that the old object had in the local namespace.
Usually the workaround is to simply return the object that you want:
def multiply_by_2(x):
return 2*x
x = 1
x = multiply_by_2(x)
*In the first example case above, 3 actually gets passed to x.__setitem__.
Most cases where you would need to pass by reference are where you need to return more than one value back to the caller. A "best practice" is to use multiple return values, which is much easier to do in Python than in languages like Java.
Here's a simple example:
def RectToPolar(x, y):
r = (x ** 2 + y ** 2) ** 0.5
theta = math.atan2(y, x)
return r, theta # return 2 things at once
r, theta = RectToPolar(3, 4) # assign 2 things at once
Not exactly passing a value directly, but using it as if it was passed.
x = 7
def my_method():
nonlocal x
x += 1
my_method()
print(x) # 8
Caveats:
nonlocal was introduced in python 3
If the enclosing scope is the global one, use global instead of nonlocal.
Maybe it's not pythonic way, but you can do this
import ctypes
def incr(a):
a += 1
x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
Really, the best practice is to step back and ask whether you really need to do this. Why do you want to modify the value of a variable that you're passing in to the function?
If you need to do it for a quick hack, the quickest way is to pass a list holding the integer, and stick a [0] around every use of it, as mgilson's answer demonstrates.
If you need to do it for something more significant, write a class that has an int as an attribute, so you can just set it. Of course this forces you to come up with a good name for the class, and for the attribute—if you can't think of anything, go back and read the sentence again a few times, and then use the list.
More generally, if you're trying to port some Java idiom directly to Python, you're doing it wrong. Even when there is something directly corresponding (as with static/#staticmethod), you still don't want to use it in most Python programs just because you'd use it in Java.
Maybe slightly more self-documenting than the list-of-length-1 trick is the old empty type trick:
def inc_i(v):
v.i += 1
x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
A numpy single-element array is mutable and yet for most purposes, it can be evaluated as if it was a numerical python variable. Therefore, it's a more convenient by-reference number container than a single-element list.
import numpy as np
def triple_var_by_ref(x):
x[0]=x[0]*3
a=np.array([2])
triple_var_by_ref(a)
print(a+1)
output:
7
The correct answer, is to use a class and put the value inside the class, this lets you pass by reference exactly as you desire.
class Thing:
def __init__(self,a):
self.a = a
def dosomething(ref)
ref.a += 1
t = Thing(3)
dosomething(t)
print("T is now",t.a)
In Python, every value is a reference (a pointer to an object), just like non-primitives in Java. Also, like Java, Python only has pass by value. So, semantically, they are pretty much the same.
Since you mention Java in your question, I would like to see how you achieve what you want in Java. If you can show it in Java, I can show you how to do it exactly equivalently in Python.
class PassByReference:
def Change(self, var):
self.a = var
print(self.a)
s=PassByReference()
s.Change(5)
class Obj:
def __init__(self,a):
self.value = a
def sum(self, a):
self.value += a
a = Obj(1)
b = a
a.sum(1)
print(a.value, b.value)// 2 2
In Python, everything is passed by value, but if you want to modify some state, you can change the value of an integer inside a list or object that's passed to a method.
integers are immutable in python and once they are created we cannot change their value by using assignment operator to a variable we are making it to point to some other address not the previous address.
In python a function can return multiple values we can make use of it:
def swap(a,b):
return b,a
a,b=22,55
a,b=swap(a,b)
print(a,b)
To change the reference a variable is pointing to we can wrap immutable data types(int, long, float, complex, str, bytes, truple, frozenset) inside of mutable data types (bytearray, list, set, dict).
#var is an instance of dictionary type
def change(var,key,new_value):
var[key]=new_value
var =dict()
var['a']=33
change(var,'a',2625)
print(var['a'])

Is there syntactic sugar for a function that accepts a tuple?

Suppose I have a function that takes two arguments and performs some calculation on them:
def add(a, b):
return a + b
I want to call this function through a multiprocessing library which can only handle functions with a single argument. So, I change the function to take its argument as a single tuple instead:
def add2(ab):
a, b = ab
return a + b
However, this seems clunky to me. The variables essentially need to be defined (and documented) twice. If I were using a lambda function, I could just write the following and it will accept the tuple properly:
add3 = lambda (a, b): a + b
Unfortunately, my function is not trivial enough to implement as a lambda function. Is there any sort of syntactic sugar feature in python that would allow me to write a named function that accepts a tuple but treats each component of that tuple as a separate named argument? My attempts to search for solutions to this have mostly turned up references to the *args operator, but that does not apply here because I do not control the site where the function is called.
Here is an example of how the function is being called. Note that it is called via the multiprocessing library so I cannot pass more than one argument:
import multiprocessing
pool = multiprocessing.Pool(processes=4)
for result in pool.imap_unordered(add, [(1,2),(3,4)]):
print(result)
Answers for either python 2.7 or 3.x are welcome.
It's best not to alter the original function interface, making it less Pythonic.
In Python 2, write a wrapper function to use with multiprocessing.
def _add(args):
return add(*args)
In Python 3, just use Pool.starmap instead:
>>> def add(a, b):
... return a + b
...
>>> p = Pool()
>>> list(p.starmap(add, [(1, 2), ('hello', ' world')]))
[3, 'hello world']
If you are worried about repeating yourself (a and b appear too many times), simply give the incoming tuple a non-descriptive name.
def add(t):
a, b = t
return a + b
Or, in your specific case, you can avoid a and b altogether by indexing the tuple:
def add(addends):
return addends[0] + addends[1]
As an alternative, you could wrap your function so the source code has the familiar argument format, but the function in use has the tuple argument:
def tupleize(func):
def wrapper(tup):
return func(*tup)
return wrapper
#tupleize
def add(a, b):
return a+b
t = 1, 2
assert(add(t) == 3)
As I was writing this question, I found the way to do it in Python 2.7:
def add4((a, b)):
return a + b
However apparently this no longer works in Python 3, so additional answers regarding Python 3 would still be helpful.
You could use a decorator to extend the multiprocessing library function to take multiple arguments, do whatever you want to them, and then call it with a single argument.
For example, a simple decorator that takes any number of arguments, sums them together, then calls the original function with the total as a single argument:
import 3rdpartylib
def sum_args(func):
def inner(*args):
return func(sum(args))
return inner
# Replace imported function with decorated version
3rdpartylib = sum_args(3rdpartylib)
# Decorate your own libraries
#sum_args
def my_own_lib(number):
print("A:", number)
3rdpartylib(1,2,3,4)
my_own_lib(5,10,15)
The main advantage is that you can decorate/replace any number of methods with this same decorator function to achieve the same effect.

Python Exercise involving functions, recursion and classes

I'm doing an exercise where I'm to create a class representing functions (written as lambda expressions) and several methods involving them.
The ones I've written so far are:
class Func():
def __init__(self, func, domain):
self.func = func
self.domain = domain
def __call__(self, x):
if self.domain(x):
return self.func(x)
return None
def compose(self, other):
comp_func= lambda x: self.func(other(x))
comp_dom= lambda x: other.domain(x) and self.domain(other(x))
return Func(comp_func, comp_dom)
def exp(self, k):
exp_func= self
for i in range(k-1):
exp_func = Func.compose(exp_func, self)
return exp_func
As you can see above, the function exp composes a function with itself k-1 times. Now I'm to write a recursive version of said function, taking the same arguments "self" and "k".
However I'm having difficulty figuring out how it would work. In the original exp I wrote I had access to the original function "self" throughout all iterations, however when making a recursive function I lose access to the original function and with each iteration only have access to the most recent composed function. So for example, if I try composing self with self a certain number of times I will get:
f= x+3
f^2= x+6
(f^2)^2= x+12
So we skipped the function x+9.
How do I get around this? Is there a way to still retain access to the original function?
Update:
def exp_rec(self, k):
if k==1:
return self
return Func.compose(Func.exp_rec(self, k-1), self)
This is an exercise, so I won't provide the answer.
In recursion, you want to do two things:
Determine and check a "guard condition" that tells you when to stop; and
Determine and compute the "recurrence relation" that tells you the next value.
Consider a simple factorial function:
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
In this example, the guard condition is fairly obvious- it's the only conditional statement! And the recurrence relation is in the return statement.
For your exercise, things are slightly less obvious, since the intent is to define a function composition, rather than a straight integer computation. But consider:
f = Func(lambda x: x + 3)
(This is your example.) You want f.exp(1) to be the same as f, and f.exp(2) to be f(f(x)). That right there tells you the guard condition and the recurrence relation:
The guard condition is that exp() only works for positive numbers. This is because exp(0) might have to return different things for different input types (what does exp(0) return when f = Func(lambda s: s + '!') ?).
So test for exp(1), and let that condition be the original lambda.
Then, when recursively defining exp(n+1), let that be the composition of your original lambda with exp(n).
You have several things to consider: First, your class instance has data associated with it. That data will "travel along" with you in your recursion, so you don't have to pass so many parameters recursively. Second, you need to decide whether Func.exp() should create a new Func(), or whether it should modify the existing Func object. Finally, consider how you would write a hard-coded function, Func.exp2() that just constructed what we would call Func.exp(2). That should give you an idea of your recurrence relation.
Update
Based on some comments, I feel like I should show this code. If you are going to have your recursive function modify the self object, instead of returning a new object, then you will need to "cache" the values from self before they get modified, like so:
func = self.func
domain = self.domain
... recursive function modifies self.func and self.domain

Why have a function with an_arg_name and *args as parameters instead of just *args

Why have a function as my_fun(an_arg, *arg) or even this a_func(dict=None, **args) why do people prefer to do this instead of saying just my_func(*args)? Are we not just repeating ourselves by using the former?
There's difference between my_fun(an_arg, *arg) and my_func(*args).
my_fun(an_arg, *arg)
Pass at least 1 argument or more arguments.
my_func(*args)
Pass any number of arguments, even 0.
Demo:
>>> def my_fun(an_arg, *arg):
pass
...
>>> def my_fun1(*arg):
pass
...
>>> my_fun()
...
TypeError: my_fun() missing 1 required positional argument: 'an_arg'
>>> my_fun1(1) #works fine
It's to help give your function a bit more meaning. Let's say that I'm trying to take in a function that increments a list of numbers by some parameter. Here's a silly example to illustrate:
def increase(increment, *nums):
return [num + increment for num in nums]
In this case, it's very clear what the first argument does, and what it's used for. In contrast, if we did this:
def increase(*args):
return [num + args[0] for num in args[1:]]
...then it's less clear what we're doing, and what all the arguments do.
In addition, it's also useful if we want to take in data, transform it, and pass in the rest of my arguments to another function.
Here's another contrived example:
def log(message, func, *args):
print message
func(*args)
Once again, if we just used only *args, our meaning is less clear:
def log(*args):
print args[0]
args[1](args[2:])
This would be much more error-prone, and hard to modify. It would also cause the function to fail if there weren't enough arguments -- by doing it the first way, you essentially make the first two elements mandatory and the rest optional.
They aren't equivalent forms. The other "repeat" forms bind arguments to discreet parameters and, more importantly, indicate that some parameters are required. Try to call def my_fun(an_arg, *arg): pass with 0 arguments.
While discreet (known) parameters work in many cases, *args allows for "sequence-variadic" functions and **kwargs allows "parameter-variadic" functions.

Categories