I am writing a program that must solve a task and the task has many points, so I made one function for each point.
In the main function, I am calling the functions (which all return a value) in the following way:
result = funcD(funcC(funcB(funcA(parameter))))
Is this way of setting function calls right and optimal or there is a better way?
First, as everyone else said, your implementation is totally valid, and separate into multiple lines is good idea to improve readability.
However, if there are even more that 4 functions, I have a better way to make your code more simple.
def chain_func(parameter, *functions):
for func in functions:
parameter = func(parameter)
return parameter
This is based on python can pass function as a variable and call it in other function.
To use it, just simple chain_func(parameter, funcA, funcB, funcC, funcD)
There's nothing really wrong with that way. You could improve readability by instead calling them like this:
resultA = funcA(parameter)
resultB = funcB(resultA)
resultC = funcC(resultB)
resultD = funcD(resultC)
But that's really just a matter of personal preference and style.
If what they do and what they return is fixed, then also the dependency between them is fixed. So you have no other way then call them in this order. Otherwise there is no way of telling without knowing what do they do exactly.
Whether you pin a reference to the partial results:
result1 = funcA(parameter)
#...
result = funcD(result3)
or call them as you've presented in your question doesn't make a significant difference.
Related
To implement prettified xml, I have written following code
def prettify_by_response(response, prettify_func):
root = ET.fromstring(response.content)
return prettify_func(root)
def prettify_by_str(xml_str, prettify_func):
root = ET.fromstring(xml_str)
return prettify_func(root)
def make_pretty_xml(root):
rough_string = ET.tostring(root, "utf-8")
reparsed = minidom.parseString(rough_string)
xml = reparsed.toprettyxml(indent="\t")
return xml
def prettify(response):
if isinstance(response, str) or isinstance(response, bytes):
return prettify_by_str(response, make_pretty_xml)
else:
return prettify_by_response(response, make_pretty_xml)
In prettify_by_response and prettify_by_str functions, I pass function make_pretty_xml as an argument
Instead of passing function as an argument, I can simply call that function.e.g
def prettify_by_str(xml_str, prettify_func):
root = ET.fromstring(xml_str)
return make_pretty_xml(root)
One of the advantage that passing function as an argument to these function over calling that function directly is, this function is not tightly couple to make_pretty_xml function.
What would be other advantages or Am I adding additional complexity?
This seem very open to biased answers I'll try to be impartial but I can't make any promise.
First, high order functions are functions that receive, and/or return functions. The advantages are questionable, I'll try to enumerate the usage of HoF and elucidate the goods and bads of each one
Callbacks
Callbacks came as a solution to blocking calls. I need B to happens after A so I call something that blocks on A and then calls B. This naturally leads to questions like, Hmm, my system wastes a lot of time waiting for things to happen. What if instead of waiting I can get what I need to be done passed as an argument. As anything new in technology that wasn't scaled yet seems a good idea until is scaled.
Callbacks are very common on the event system. If you every code in javascript you know what I'm talking about.
Algorithm abstraction
Some designs, mostly the behavioral ones can make use of HoF to choose some algorithm at runtime. You can have a high-level algorithm that receives functions that deal with low-level stuff. This lead to more abstraction code reuse and portable code. Here, portable means that you can write code to deal with new low levels without changing the high-level ones. This is not related to HoF but can make use of them for great help.
Attaching behavior to another function
The idea here is taking a function as an argument and returning a function that does exactly what the argument function does, plus, some attached behavior. And this is where (I think) HoF really shines.
Python decorators are a perfect example. They take a function as an argument and return another function. This function is attached to the same identifier of the first function
#foo
def bar(*args):
...
is the same of
def bar(*args):
...
bar = foo(bar)
Now, reflect on this code
from functools import lru_cache
#lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
fib is just a Fibonacci function. It calculates the Fibonacci number up to n. Now lru_cache attach a new behavior, of caching results for already previously calculated values. The logic inside fib function is not tainted by LRU cache logic. What a beautiful piece of abstraction we have here.
Applicative style programming or point-free programming
The idea here is to remove variables, or points and combining function applications to express algorithms. I'm sure there are lots of people better than me in this subject wandering SO.
As a side note, this is not a very common style in python.
for i in it:
func(i)
from functools import partial
mapped_it = map(func, it)
In the second example, we removed the i variable. This is common in the parsing world. As another side node, map function is lazy in python, so the second example doesn't have effect until if you iterate over mapped_it
Your case
In your case, you are returning the value of the callback call. In fact, you don't need the callback, you can simply line up the calls as you did, and for this case you don't need HoF.
I hope this helps, and that somebody can show better examples of applicative style :)
Regards
I have the following code (simplified):
def send_issue(issue):
message = bot.send_issue(issue)
return message
def send_issues(issues):
return [send_issue(issue) for issue in issues]
As you see, send_issues and send_issue are non-pure functions. Is this considered a good practice (and Pythonic) to call non-pure functions in list comprehensions? The reason I want to do this is that this is convenient. The reason against this is that when you see a list comprehension, you expect that this code just generates the list and nothing more, but that's not the case.
UPD:
I actually want to create and return the list contrary this question.
The question here is - Do you really need to create the list?
If this is so it is okay but not the best design.
It is good practice for a function to do only one thing especially if it has a side effect like I/O.
In your case, the function is creating and sending a message.
To fix this you can create a function that is sending the message and a function which is generating the message.
It is better to write it as.
msgs = [bot.get_message(issue) for issue in issues]
for msg in msgs:
bot.send(msg)
This is clearer and widens the use of API while keeping the side effect isolated.
If you don't want to create another function you can at least use map since it says - "map this function to every element".
map(lambda issue: bot.send_issue(issue), issues) # returns a list
Also, the function send_issue is not needed because it just wraps the bot.send_issue.
Adding such functions is only making the code noisy which is not a good practice.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
So a few days ago we got this exercise where we need to make a function that takes two lists as input and calculates the difference of their averages.
Sounds simple enough, but there are a few catches:
the entire thing needs to be one line long
you can absolutely NOT use ':'
They encouraged us to use 'import', 'help()' and 'dir()'.
The thing is that I know how to make it only one line long, but the no ':' is really annoying.
The way I see it, I first need to define a function (without code) then change it's 'func_code' attr.
Any ideas on how can I do it?
And how do the params fit into this?
Any answer is appreciated!!!
Edit: thanks for all the answers and the creative minds that said char(58) is the solution, it is really creative and I haven't thought of that solution but it's not allowed since you are using ':' even though not directly.
No : means you can't use lambda. That leaves higher-order functions or eval trickery.
eval('lambda a,b{}sum(a)/len(a)-sum(b)/len(b)'.format(chr(58)))
This meets the letter of the law, but violates its spirit.
Unfortunately, without a function composition function, higher-order functions don't work very well. Implementing one without : is tricky.
Here's what should be a fairly self-contained solution, using a pickled code object. I've created it in Python 3.6, and the specific bytestring is very likely to be version specific, but you can create your own version pretty easily using the expanded code below. Anyway, here's the oneliner:
f = __import__('types').FunctionType(__import__('pickle').loads(b'\x80\x03cipykernel.codeutil\ncode_ctor\nq\x00(K\x02K\x00K\x02K\x04KCC t\x00|\x00\x83\x01t\x01|\x00\x83\x01\x1b\x00t\x00|\x01\x83\x01t\x01|\x01\x83\x01\x1b\x00\x18\x00S\x00q\x01N\x85q\x02X\x03\x00\x00\x00sumq\x03X\x03\x00\x00\x00lenq\x04\x86q\x05X\x01\x00\x00\x00aq\x06X\x01\x00\x00\x00bq\x07\x86q\x08X\x1e\x00\x00\x00<ipython-input-1-384cc87bd499>q\tX\x16\x00\x00\x00difference_of_averagesq\nK\x01C\x02\x00\x01q\x0b))tq\x0cRq\r.'), globals())
Here's what I'm doing without the one-line shenanigans:
import types # replace these import statements with calls to __import__ in the oneliner
import pickle
def difference_of_averages(a, b):
return sum(a)/len(a) - sum(b)/len(b)
payload = pickle.dumps(difference_of_averages.__code__) # embed as a literal in the oneliner
f = types.FunctionType(pickle.loads(payload), globals())
Hmm, having tried this on the few different interpreters I have at hand, it looks like my pickle string includes some nonsense from the IPython interpreter I created it in. If you get errors using my string, I'd suggest just building your own (which, if it contains any junk, will at least be junk compatible with your environment).
Not using ':' is tricky because you normally use it to define the function body, like this:
def average(number_list):
return sum(number_list) / len(number_list)
However, I know of one way to define a function that doesn't require require writing a block for its body: You can assign a lambda function (or even an already-defined function) to a function you want to define, simply by using the equal sign (=). For example, if you want to create an average() function, you might write:
average = lambda number_list: sum(number_list) / len(number_list)
average might look like a variable, but you can use it as a function. It simply calls the lambda function that takes a number_list as input and returns the average value of the number_list. You can call it like this:
value = average([10, 11, 12]) # sets value to 11
Now, lambda functions can only have one line. But that's not really a problem for you, since your task requires you to only use one line.
Do you understand what to do now? Your exercise requires you to find the average of two lists, so you might consider using a lambda function that takes two inputs (instead of just one, like in the example I gave above). Also bear in mind that you need to return the difference, and if the difference should always be positive, consider using Python's abs() function somewhere in your code.
Edit: Well, gilch's response made me realize that I can't use lambda because even they use :. So apparently you can't use my advice. It's still good to know about lambda functions, though.
The fact that you are encouraged to use import makes me wonder if it's okay for you to use an already-defined function from some module to define your own function. Kind of like this:
import math; average = math.difference_of_averages
However, that depends on you being able to find a (probably standard) function that does exactly what you want. (I've briefly checked the math and numpy modules, and haven't found anything that matches yet.)
And maybe this means that you can create a module and define it anyway you like. The module is in its own world, so it's not constrained to the rules of your exercise.
Then again, maybe not.
So unless you want to "sneak-in" a : in an eval statement (as gilch suggested), like this:
average = eval('lambda number_list' + chr(58) + ' sum(number_list) / len(number_list)')
there's no way I know of off hand to avoidi using :.
I keep nesting def statements as a way of grouping/organizing code, but after doing some reading I think I'm abusing it..
Is it kosher to do something like this?
def generate_random_info():
def random_name():
return numpy.random.choice(['foo', 'bar'])
def random_value():
return numpy.random.rand()
return {'name':random_name(), 'value':random_value()}
There is nothing wrong with it per se. But you should consider one thing when you use structures like this: random_name and random_value are functions that keep being redefined whenever you call generate_random_info(). Now that might not be a problem for those particular functions, especially when you won’t call it too often but you should consider that this is overhead that can be avoided.
So you should probably move those function definitions outside of the generate_random_info function. Or, since those inner functions don’t do much themselves, and you just call them directly, just inline them:
def generate_random_info():
return {
'name': numpy.random.choice(['foo', 'bar']),
'value': numpy.random.rand()
}
Unless you are planning on reusing the same chunk of code repeatedly throughout a single function and that function only, I would avoid creating those functions just for the sake of doing it. I'm not an expert on how the code is working on the computational level, but I would think that creating a function is more intensive than simply using that line as you have it now, especially if you're only going to use that function once.
In a function, I need to perform some logic that requires me to call a function inside a function. What I did with this, like:
def dfs(problem):
stack.push(bache)
search(root)
while stack.isEmpty() != 0:
def search(vertex):
closed.add(vertex)
for index in sars:
stack.push(index)
return stack
In the function, dfs, I am using search(root), is this is the correct way to do it?
I am getting an error: local variable 'search' referenced before assignment
There are many mysterious bug-looking aspects in your code. The wrong order of definition (assuming you do need the search function to be a nested one) and the syntax error from the empty while loop have already been observed, but there are more...:
def dfs(problem):
stack.push(bache)
search(root)
what's bache, what's stack, what's root? If they're all global variables, then you're overusing globals -- and apparently nowhere ever using the argument problem (?!).
while stack.isEmpty() != 0:
what's this weird-looking method isEmpty? IOW, what type is stack (clearly not a Python list, and that's weird enough, since they do make excellent LIFO stacks;-)...? And what's ever going to make it empty...?
def search(vertex):
closed.add(vertex)
...don't tell me: closed is yet another global? Presumably a set? (I remember from a few of your Qs back that you absolutely wanted to have a closed dict, not set, even though I suggested that as a possibility...
for index in sars:
...and what's sars?!
stack.push(index)
return stack
what a weird "loop" -- one that executes exactly once, altering a global variable, and then immediately returns that global variable (?) without doing any of the other steps through the loop. Even if this is exactly what you mean (push the first item of sars, period) I don't recommend hiding it in a pseudo-loop -- it seriously looks like a mystery bug just waiting to happen;-).
You need to de-indent your search function. The way you have it set up right now you are defining your search function as a part of the completion of your dfs call. Also, encapsulation in a class would help.
Thats the wrong order. Try this:
def dfs(problem):
def search(vertex):
closed.add(vertex)
for index in sars:
stack.push(index)
return stack
stack.push(bache)
search(root)
while stack.isEmpty() != 0:
Either define search before you call it, or define it outside of dfs.
you have to define the function before using it
root doesn't seem to be available in your scope - make sure it's reachable
You don't have body to your for your while loop. That is probably causing problems parsing the code. I would also suggest putting the local function definition before it is used, so it is easier to follow.