anything wrong with retuning more than one thing? - from python function - python

As a follow up from this post:
How to return more than one value from a function in Python?
A separate question:
As a beginner programmer, I was taught to only return one thing from a function.
a. Is there any hidden problem with returning more than one thing?
b. If so, and I want to return 2 lists from a long function (ie not call 2 separate similar functions), is there anything wrong with making a tuple out of the lists?
Thanks

If returning two things makes sense, yes... return two things.
For example, if you want to split a string based on some criteria, like find key/value pairs, you might call split_string_to_get_key_pair() you would expect it to return a tuple of (key, value).
The question is, is returning a tuple (which is how multiple return values often work) returning one thing or two? An argument can be made either way, but as long as what is returned is consistent and documented, then you can return what ever makes sense for your program.

Python encourages returning multiple values if that makes sense. Go for it.

If you put the two lists into one tuple, you're essentially returning one thing. =D

This question is not really specific to Python and is perhaps better suited for Programmers.SE.
Anyway, regarding your questions:
a. Not if these things you are returning are actually a single thing in disguise, and they will be used together most of the time. For example, if you request the color of something, you rarely need only the value of the red channel. So if the returned value is simple enough, or if the wrapping class would not make much sense, you just return a tuple.
b. There isn't, it's a common practice in Python as #Amber has noted.

Related

Alternative to return multiple values from function in python in a structured way?

I'm working on mortgage calculations and many functions calculate multiple different values that I need to return.
For example:
def calculate_something(incomes, debts):
...
return {'value':150000, 'extra':{'dsti_gross':450, 'dsti_supergross':480}}
has many intermediate calculations that are useful in other calculations. These functions are not divisible into smaller functions as it would make the code slower.
I don't want to return tuples as the code might change in the future and I'd need to check all the function calls.
Dictionary is now a way to go but dictionary value calls aren't statically analyzed (most IDEs) so you always need to check the function if you access the correct keys.
Is there another way to work with such returns? Considering classes/objects but every function returns different keys.
To expand on the suggestion to use classes and subclasses, you can take advantage of python dataclasses, which are pretty much designed for such a problem.

Why map,filter,reduce takes the function parameter as first argument meanwhile function like sorted expects it as second parameter

How map defined in python is
map(function, iterable, ...)
as can be seen function is the first parameter the same goes for filter,reduce
but when I am checking functions like sorted they are defined
sorted(iterable, key=None, reverse=False)
key being the function that can be used while sorting. I don't know Python well to say if there are other examples like sorted. But for starters, this seems a little a bit unorganized. Since I am coming from C++/D background in which I can almost all the time tell where the function parameter will go in the standard library it is a bit unorthodox for me.
Is there any historical or hierarchical reason why the function parameter is expected in different orders?
The actual signature of map is:
map(function, iterable, ...)
It can take more than one iterable, so making the function the first argument is the most sensible design.
You can argue about filter, there's no one "correct" way to design it, but making it the same order as map rather makes sense.
sorted doesn't require a key function, so it makes no sense to put it first.
Anyone can contribute a module into the python ecosystem. The lineage of any particular module is fairly unique (though I'm sure there are general families that share common lineages). While there will be attempts to standardise and agree on common conventions, there is a limit to what is possible.
As a result, some modules will have a set of paradigms that will differ vastly from other modules - they will have different focuses, and you just can't standardise down to the level you're looking for.
That being said, if you wanted to make that a priority, there's nothing stopping you from recasting all the non-standard things you find into a new suite of open source libraries and encouraging people to adopt them as the standard.
The map() function design is different, the purpose of the design will surely determine the parameters that you pass into the function. The map() function executes a specified function for each item in an iterable, which is very different for the purpose of the sorted() function.

Is it possible to use a loop to assign multiple variables to different values in python

I have seen duplicates of this, but the original question was never answered: is it possible to assign values to multiple variables using a loop or some other method that would be more efficient that writing out all the variables in hard code.
NOTE: I do not want to use dictionaries or list, I want to use variables. My question is whether it is possible to assign multiple variables at once using a loop or other method, not using dictionaries.
If this is not possible just say so, but I really don't want to see another answer describing how to use lists or dictionaries.
Duplicates:
Python: assigning multiple variables at once
Assign Many Variables at Once, Python
DISCLAIMER: The global()[] function that I talk about here may have more uses/parameters/arguments, but I am just telling you what I know. You can experiment with it on your own
Ok, now that I have found the answer, I'll post it here for future members to view. Note that, as mentioned above, this technique is seldom used, but it's great to know for those corner cases.
The crucial function here is the global()[] function in which you input a string and it turns it into a variable name. You leave the () completely empty, and enter the string into the []. Now, this may seem useless, but one thing you can do is,
for i in range(100):
global()["Var"+str(i)] = i
Now you have 100 variables of the form Var# where # is the number, and, in this case, the value of the variable. This is a very, very simple case, and because of this extra flexibility, there are several things you can do with this.
Again, you will probably use this very few times while programming in python, since using extra lists of strings and values and then using this to create variables is unnecessary and inefficient, but, in the right places, this can save you a lot of time. Just comment if you have any questions since I am not that good at explaining things.

Writing reusable code

I find myself constantly having to change and adapt old code back and forth repeatedly for different purposes, but occasionally to implement the same purpose it had two versions ago.
One example of this is a function which deals with prime numbers. Sometimes what I need from it is a list of n primes. Sometimes what I need is the nth prime. Maybe I'll come across a third need from the function down the road.
Any way I do it though I have to do the same processes but just return different values. I thought there must be a better way to do this than just constantly changing the same code. The possible alternatives I have come up with are:
Return a tuple or a list, but this seems kind of messy since there will be all kinds of data types within including lists of thousands of items.
Use input statements to direct the code, though I would rather just have it do everything for me when I click run.
Figure out how to utilize class features to return class properties and access them where I need them. This seems to be the cleanest solution to me, but I am not sure since I am still new to this.
Just make five versions of every reusable function.
I don't want to be a bad programmer, so which choice is the correct choice? Or maybe there is something I could do which I have not thought of.
Modular, reusable code
Your question is indeed important. It's important in a programmers everyday life. It is the question:
Is my code reusable?
If it's not, you will run into code redundancies, having the same lines of code in more than one place. This is the best starting point for bugs. Imagine you want to change the behavior somehow, e.g., because you discovered a potential problem. Then you change it in one place, but you will forget the second location. Especially if your code reaches dimensions like 1,000, 10,0000 or 100,000 lines of code.
It is summarized in the SRP, the Single-Responsibilty-Principle. It states that every class (also applicable to functions) should only have one determination, that it "should do just one thing". If a function does more than one thing, you should break it apart into smaller chunks, smaller tasks.
Every time you come across (or write) a function with more than 10 or 20 lines of (real) code, you should be skeptical. Such functions rarely stick to this principle.
For your example, you could identify as individual tasks:
generate prime numbers, one by one (generate implies using yield for me)
collect n prime numbers. Uses 1. and puts them into a list
get nth prime number. Uses 1., but does not save every number, just waits for the nth. Does not consume as much memory as 2. does.
Find pairs of primes: Uses 1., remembers the previous number and, if the difference to the current number is two, yields this pair
collect all pairs of primes: Uses 4. and puts them into a list
...
...
The list is extensible, and you can reuse it at any level. Every function will not have more than 10 lines of code, and you will not be reinventing the wheel everytime.
Put them all into a module, and use it from every script for an Euler Problem related to primes.
In general, I started a small library for my Euler Problem scripts. You really can get used to writing reusable code in "Project Euler".
Keyword arguments
Another option you didn't mention (as far as I understand) is the use of optional keyword arguments. If you regard small, atomic functions as too complicated (though I really insist you should get used to it) you could add a keyword argument to control the return value. E.g., in some scipy functions there is a parameter full_output, that takes a bool. If it's False (default), only the most important information is returned (e.g., an optimized value), if it's True some supplementary information is returned as well, e.g., how well the optimization performed and how many iterations it took to converge.
You could define a parameter output_mode, with possible values "list", "last" ord whatever.
Recommendation
Stick to small, reusable chunks of code. Getting used to this is one of the most valuable things you can pick up at "Project Euler".
Remark
If you try to implement the pattern I propose for reusable functions, you might run into a problem immediately at point 1: How to create a generator-style function for this? E.g., if you use the sieve method. But it's not too bad.
My guess, create module that contain:
private core function (example: return list of n-th first primes or even something more generall)
several wrapper/util functions that use core one and prepare output different ways. (example: n-th prime number)
Try to reduce your functions as much as possible, and reuse them.
For example you might have a function next_prime which is called repeatedly by n_primes and n_th_prime.
This also makes your code more maintainable, as if you come up with a more efficient way to count primes, all you do is change the code in next_prime.
Furthermore you should make your output as neutral as possible. If you're function returns several values, it should return a list or a generator, not a comma separated string.

Use of add(), append(), update() and extend() in Python

Is there an article or forum discussion or something somewhere that explains why lists use append/extend, but sets and dicts use add/update?
I frequently find myself converting lists into sets and this difference makes that quite tedious, so for my personal sanity I'd like to know what the rationalization is.
The need to convert between these occurs regularly as we iterate on development. Over time as the structure of the program morphs, various structures gain and lose requirements like ordering and duplicates.
For example, something that starts out as an unordered bunch of stuff in a list might pick up the the requirement that there be no duplicates and so need to be converted to a set.
All such changes require finding and changing all places where the relevant structure is added/appended and extended/updated.
So I'm curious to see the original discussion that led to this language choice, but unfortunately I didn't have any luck googling for it.
append has a popular definition of "add to the very end", and extend can be read similarly (in the nuance where it means "...beyond a certain point"); sets have no "end", nor any way to specify some "point" within them or "at their boundaries" (because there are no "boundaries"!), so it would be highly misleading to suggest that these operations could be performed.
x.append(y) always increases len(x) by exactly one (whether y was already in list x or not); no such assertion holds for s.add(z) (s's length may increase or stay the same). Moreover, in these snippets, y can have any value (i.e., the append operation never fails [except for the anomalous case in which you've run out of memory]) -- again no such assertion holds about z (which must be hashable, otherwise the add operation fails and raises an exception). Similar differences apply to extend vs update. Using the same name for operations with such drastically different semantics would be very misleading indeed.
it seems pythonic to just use a list
on the first pass and deal with the
performance on a later iteration
Performance is the least of it! lists support duplicate items, ordering, and any item type -- sets guarantee item uniqueness, have no concept of order, and demand item hashability. There is nothing Pythonic in using a list (plus goofy checks against duplicates, etc) to stand for a set -- performance or not, "say what you mean!" is the Pythonic Way;-). (In languages such as Fortran or C, where all you get as a built-in container type are arrays, you might have to perform such "mental mapping" if you need to avoid using add-on libraries; in Python, there is no such need).
Edit: the OP asserts in a comment that they don't know from the start (e.g.) that duplicates are disallowed in a certain algorithm (strange, but, whatever) -- they're looking for a painless way to make a list into a set once they do discover duplicates are bad there (and, I'll add: order doesn't matter, items are hashable, indexing/slicing unneeded, etc). To get exactly the same effect one would have if Python's sets had "synonyms" for the two methods in question:
class somewhatlistlikeset(set):
def append(self, x): self.add(x)
def extend(self, x): self.update(x)
Of course, if the only change is at the set creation (which used to be list creation), the code may be much more challenging to follow, having lost the useful clarity whereby using add vs append allows anybody reading the code to know "locally" whether the object is a set vs a list... but this, too, is part of the "exactly the same effect" above-mentioned!-)
set and dict are unordered. "Append" and "extend" conceptually only apply to ordered types.
It's written that way to annoy you.
Seriously. It's designed so that one can't simply convert one into the other easily. Historically, sets are based off dicts, so the two share naming conventions. While you could easily write a set wrapper to add these methods ...
class ListlikeSet(set):
def append(self, x):
self.add(x)
def extend(self, xs):
self.update(xs)
... the greater question is why you find yourself converting lists to sets with such regularity. They represent substantially different models of a collection of objects; if you have to convert between the two a lot, it suggests you may not have a very good handle on the conceptual architecture of your program.

Categories

Resources