Having both a method and a function which do the same thing? - python

Is there a convention on how to have both a method and a function that do the same thing (or whether to do this at all)?
Consider, for example,
from random import choice
from collections import Counter
class MyDie:
def __init__(self, smallest, largest, how_many_rolls):
self.min = smallest
self.max = largest
self.number_of_rolls = how_many_rolls
def __call__(self):
return choice( range(self.min, self.max+1) )
def count_values(self):
return Counter([self() for n in range(self.number_of_rolls)])
def count_values(randoms_func, number_of_values):
return Counter([randoms_func() for n in range(number_of_values)])
where count_values is both a method and a function.
I think it's nice to have the method because the result "belongs to" the MyDie object. Also, the method can pull attributes from the MyDie object without having to pass them to count_values. On the other hand, it's nice to have the function in order to operate on functions other than MyDie, like
count_values(lambda: choice([3,5]) + choice([7,9]), 7)
Is it best to do this as above (where the code is repeated; assume the function is a longer piece of code, not just one line) or replace the count_values method with
def count_values(self):
return count_values(self, number_of_rolls)
or just get rid of the method all together and just have a function? Or maybe something else?

Here is an alternative that still allows you to encapsulate the logic in MyDie. Create a class method in MyDie
#staticmethod
def count_specified_values(random_func, number_of_values):
return Counter([randoms_func() for n in range(number_of_values)])
You also could add additional formal parameters to the constructor with default values that you could override to achieve the same functionality.

Related

Instance variable as function of other instance variables

Is it possible to define an instance variable in a class as a function of another? I haven't gotten it to work unless you redefine the "function instance variable" all the time.
Basically you could have a scenario where you have one instance variable that is a list of integers, and want to have the sum of these as an instance variable, that automatically redefines every time the list is updated.
Is this possible?
class Example:
list_variable = []
sum_variable = sum(list_variable)
def __init__(self, list_variable):
self.list_variable = list_variable
return
This will result in sum_variable = 0 unless you change it.
I understand that this is far from a major issue, you could either define sum_variable as a method or redefine it every time you change list_variable, I'm just wondering if it's possible to skip those things/steps.
Python offers the property decorator for a syntatically identical use of your example:
class Example:
list_variable = []
def __init__(self, list_variable):
self.list_variable = list_variable
return
#property
def sum_variable(self):
return sum(self.list_variable)
e = Example(list_variable=[10, 20, 30])
e.sum_variable # returns 60

what is the exact difference between return a class and a object

Please guide to an explain of the difference between
object = class()
and
var = class method returning a class:
class Countsome(object):
#classmethod
def get(cls, x, y):
self = cls()
sum = self.add2(x, y)
print sum
return cls
def add2(self, x, y):
sum = x+y
return sum
xyz = Countsome.get(5, 9)
==========================================
class CountSome(object):
def __init__(self):
pass
def add2(self, x, y):
sum = x+y
print sum
xyz = CountSome()
xyz.add2(5, 9)
Looking to understand where I should use one, I am just printing the sum so not returning, so please assume I am asking this question for these kind of tasks(where returning results like sum is not important).
And looking for answers like, which one would be efficient, when.
What are the benefits of each and scenarios best suited for each. Guide to a source if possible
You kinda get it wrong. classmethod should be use when you need to perform action that doesn't need an instance but does need the cls object:
A class method receives the class as implicit first argument, just like an instance method receives the instance.
For example, if you have a COUNTER object in your class which counts how many instances were instantiated.
The second code is actually using staticmethod; that is a method defined in a class but don't need access to any class / instance attributes. staticmethod can be defined outside of a class but resides in it for convenience

Keep changes to an object temporary during method chaining

I am designing an object-oriented data structure that shall be simple to handle from the user's perspective, e.g., by method chaining (aka Fluent interface). However, each change should only act temporarily on the object: within that chain, but not beyond that chain.
Here is a simplified example that does not work as intended:
class C:
def __init__(self, num):
self.sum = num
def add(self, num=0):
self.sum += num
return self
number = C(23)
number.add(7).add(12).sum
# 42
number.sum
# 42 (but I expect: 23)
In this case, .add() makes permanent changes to number. However, permanent changes should only be possible like this:
# This is the only way how a user should make permanent changes:
number = number.add(4).add(12)
In the temporary scope, I am looking for a way to get back to the old version of number after the chain is terminated. On the edge of despair, I can think of ugly solutions like "instance replication":
class C2:
def __init__(self, num):
self.sum = num
def add(self, num=0):
self2 = C2(self.sum) # or equivalently: self2 = copy.deepcopy(self)
self2.sum += num
return self2
number = C2(23)
number.add(7).add(12).sum
# 42
number.sum
# 23
However, the actuall classes and objects with which I am working contain a huge amount of data, attributes, methods, and even subclasses. So we should avoid copying the instance in every single method, besides the fact that it involves ugly code.
Are there ways to solve this problem, e.g. by (silently) creating a single copy only once at the first element of the chain? Or by destroying any changes made at the end of the chain? (Note that real-world "changes" involve many different, commutable methods other than just adding numbers)
An accepted solution should perform the necessary operations internally, i.e., without bothering the user interface:
# These are NOT accepted solutions:
number.copy().add(4).add(12)
number.add(4).add(12).undo()
If there no direct solution other than self-replication, the question would be: What is the most elegant way to do it that sustains code-readability and keeps memory usage low? E.g., decorating every class method by self-replicating function?
Instead of modyfing the object on which you call the method, return a modified copy:
class C:
def __init__(self, num):
self.sum = num
def add(self, num=0):
return C(self.sum + num)
number = C(23)
assert number.add(7).add(12).sum == 42
assert number.sum == 23
For details on memory handling in this solution, see comments of this posts. This solution is standard way of solving your problem.

Can I implement a function or better a decorator that makes func(a1)(a2)(a3)...(an) == func(a1, a2, a3,...,an)? [duplicate]

On Codewars.com I encountered the following task:
Create a function add that adds numbers together when called in succession. So add(1) should return 1, add(1)(2) should return 1+2, ...
While I'm familiar with the basics of Python, I've never encountered a function that is able to be called in such succession, i.e. a function f(x) that can be called as f(x)(y)(z).... Thus far, I'm not even sure how to interpret this notation.
As a mathematician, I'd suspect that f(x)(y) is a function that assigns to every x a function g_{x} and then returns g_{x}(y) and likewise for f(x)(y)(z).
Should this interpretation be correct, Python would allow me to dynamically create functions which seems very interesting to me. I've searched the web for the past hour, but wasn't able to find a lead in the right direction. Since I don't know how this programming concept is called, however, this may not be too surprising.
How do you call this concept and where can I read more about it?
I don't know whether this is function chaining as much as it's callable chaining, but, since functions are callables I guess there's no harm done. Either way, there's two ways I can think of doing this:
Sub-classing int and defining __call__:
The first way would be with a custom int subclass that defines __call__ which returns a new instance of itself with the updated value:
class CustomInt(int):
def __call__(self, v):
return CustomInt(self + v)
Function add can now be defined to return a CustomInt instance, which, as a callable that returns an updated value of itself, can be called in succession:
>>> def add(v):
... return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44) # and so on..
50
In addition, as an int subclass, the returned value retains the __repr__ and __str__ behavior of ints. For more complex operations though, you should define other dunders appropriately.
As #Caridorc noted in a comment, add could also be simply written as:
add = CustomInt
Renaming the class to add instead of CustomInt also works similarly.
Define a closure, requires extra call to yield value:
The only other way I can think of involves a nested function that requires an extra empty argument call in order to return the result. I'm not using nonlocal and opt for attaching attributes to the function objects to make it portable between Pythons:
def add(v):
def _inner_adder(val=None):
"""
if val is None we return _inner_adder.v
else we increment and return ourselves
"""
if val is None:
return _inner_adder.v
_inner_adder.v += val
return _inner_adder
_inner_adder.v = v # save value
return _inner_adder
This continuously returns itself (_inner_adder) which, if a val is supplied, increments it (_inner_adder += val) and if not, returns the value as it is. Like I mentioned, it requires an extra () call in order to return the incremented value:
>>> add(1)(2)()
3
>>> add(1)(2)(3)() # and so on..
6
You can hate me, but here is a one-liner :)
add = lambda v: type("", (int,), {"__call__": lambda self, v: self.__class__(self + v)})(v)
Edit: Ok, how this works? The code is identical to answer of #Jim, but everything happens on a single line.
type can be used to construct new types: type(name, bases, dict) -> a new type. For name we provide empty string, as name is not really needed in this case. For bases (tuple) we provide an (int,), which is identical to inheriting int. dict are the class attributes, where we attach the __call__ lambda.
self.__class__(self + v) is identical to return CustomInt(self + v)
The new type is constructed and returned within the outer lambda.
If you want to define a function to be called multiple times, first you need to return a callable object each time (for example a function) otherwise you have to create your own object by defining a __call__ attribute, in order for it to be callable.
The next point is that you need to preserve all the arguments, which in this case means you might want to use Coroutines or a recursive function. But note that Coroutines are much more optimized/flexible than recursive functions, specially for such tasks.
Here is a sample function using Coroutines, that preserves the latest state of itself. Note that it can't be called multiple times since the return value is an integer which is not callable, but you might think about turning this into your expected object ;-).
def add():
current = yield
while True:
value = yield current
current = value + current
it = add()
next(it)
print(it.send(10))
print(it.send(2))
print(it.send(4))
10
12
16
Simply:
class add(int):
def __call__(self, n):
return add(self + n)
If you are willing to accept an additional () in order to retrieve the result you can use functools.partial:
from functools import partial
def add(*args, result=0):
return partial(add, result=sum(args)+result) if args else result
For example:
>>> add(1)
functools.partial(<function add at 0x7ffbcf3ff430>, result=1)
>>> add(1)(2)
functools.partial(<function add at 0x7ffbcf3ff430>, result=3)
>>> add(1)(2)()
3
This also allows specifying multiple numbers at once:
>>> add(1, 2, 3)(4, 5)(6)()
21
If you want to restrict it to a single number you can do the following:
def add(x=None, *, result=0):
return partial(add, result=x+result) if x is not None else result
If you want add(x)(y)(z) to readily return the result and be further callable then sub-classing int is the way to go.
The pythonic way to do this would be to use dynamic arguments:
def add(*args):
return sum(args)
This is not the answer you're looking for, and you may know this, but I thought I would give it anyway because if someone was wondering about doing this not out of curiosity but for work. They should probably have the "right thing to do" answer.

how to make my own mapping type in python

I have created a class MyClassthat contains a lot of simulation data. The class groups simulation results for different simulations that have a similar structure. The results can be retreived with a MyClass.get(foo) method. It returns a dictionary with simulationID/array pairs, array being the value of foo for each simulation.
Now I want to implement a method in my class to apply any function to all the arrays for foo. It should return a dictionary with simulationID/function(foo) pairs.
For a function that does not need additional arguments, I found the following solution very satisfying (comments always welcome :-) ):
def apply(self, function, variable):
result={}
for k,v in self.get(variable).items():
result[k] = function(v)
return result
However, for a function requiring additional arguments I don't see how to do it in an elegant way. A typical operation would be the integration of foo with bar as x-values like np.trapz(foo, x=bar), where both foo and bar can be retreived with MyClass.get(...)
I was thinking in this direction:
def apply(self, function_call):
"""
function_call should be a string with the complete expression to evaluate
eg: MyClass.apply('np.trapz(QHeat, time)')
"""
result={}
for SID in self.simulations:
result[SID] = eval(function_call, locals=...)
return result
The problem is that I don't know how to pass the locals mapping object. Or maybe I'm looking in a wrong direction. Thanks on beforehand for your help.
Roel
You have two ways. The first is to use functools.partial:
foo = self.get('foo')
bar = self.get('bar')
callable = functools.partial(func, foo, x=bar)
self.apply(callable, variable)
while the second approach is to use the same technique used by partial, you can define a function that accept arbitrary argument list:
def apply(self, function, variable, *args, **kwds):
result={}
for k,v in self.get(variable).items():
result[k] = function(v, *args, **kwds)
return result
Note that in both case the function signature remains unchanged. I don't know which one I'll choose, maybe the first case but I don't know the context on you are working on.
I tried to recreate (the relevant part of) the class structure the way I am guessing it is set up on your side (it's always handy if you can provide a simplified code example for people to play/test).
What I think you are trying to do is translate variable names to variables that are obtained from within the class and then use those variables in a function that was passed in as well. In addition to that since each variable is actually a dictionary of values with a key (SID), you want the result to be a dictionary of results with the function applied to each of the arguments.
class test:
def get(self, name):
if name == "valA":
return {"1":"valA1", "2":"valA2", "3":"valA3"}
elif name == "valB":
return {"1":"valB1", "2":"valB2", "3":"valB3"}
def apply(self, function, **kwargs):
arg_dict = {fun_arg: self.get(sim_args) for fun_arg, sim_args in kwargs.items()}
result = {}
for SID in arg_dict[kwargs.keys()[0]]:
fun_kwargs = {fun_arg: sim_dict[SID] for fun_arg, sim_dict in arg_dict.items()}
result[SID] = function(**fun_kwargs)
return result
def joinstrings(string_a, string_b):
return string_a+string_b
my_test = test()
result = my_test.apply(joinstrings, string_a="valA", string_b="valB")
print result
So the apply method gets an argument dictionary, gets the class specific data for each of the arguments and creates a new argument dictionary with those (arg_dict).
The SID keys are obtained from this arg_dict and for each of those, a function result is calculated and added to the result dictionary.
The result is:
{'1': 'valA1valB1', '3': 'valA3valB3', '2': 'valA2valB2'}
The code can be altered in many ways, but I thought this would be the most readable. It is of course possible to join the dictionaries instead of using the SID's from the first element etc.

Categories

Resources