def is_prime(n):
if n % 2 == 0:
return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
def main():
with concurrent.futures.ProcessPoolExecutor() as executor:
for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
print('%d is prime: %s' % (number, prime))
uglier than (borrowing some JavaScript syntax): def main():
with concurrent.futures.ProcessPoolExecutor() as executor:
for number, prime in zip(PRIMES, executor.map(
function(n) {
if n % 2 == 0:
return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
}
, PRIMES)):
print('%d is prime: %s' % (number, prime))
I don't, mostly because in the second example, I cannot unit test the anon version of is_prime in isolation. This is a rather trivial case, but I've seen much more complex and enigmatic anon functions in Node applications.Note: the original comes from http://docs.python.org/dev/library/concurrent.futures.html#p...
Do people really think that? I ask in all seriousness. I am a hardware developer by profession and don't often dive very deep in software, though I love exploring software space.
I find example A to be very clear and readable. I like to look at things in bite sized chunks.
I also like to create things in bite sized chunks. In hardware design, specifically digital chip design, I will know what my overall problem is to solve (aka the requirements), but I don't always have a clear view of what pieces I need to get there.
In the cases where I'm not sure about the smaller pieces, I'll write the larger overall structure and when I get to a spot where I'll need a block of smaller functionality, I'll just make up a function name on the spot and pretend it's already written and does the right thing.
Then I take a second pass, implementing those smaller blocks, and keep going down. I guess that's a typical top-down approach? I don't know, but it is what I do.
But I also do bottom up. Even without knowing all the steps between, I'll often have some idea that there are some basic building blocks I'm going to need, and I'll implement those.
So I iterate with some steps top-down, others bottom-up, until I meet in the middle.
All that is a long winded way for me to say that your example A fits both approaches for me. I can start with the overall structure and implement "main" first, or know what my basis will need and start with "is_prime" first.
Whereas example B seems like an all at once approach that is both more difficult to write and read. At least, that is how it seems to me.
edit: wording
People have been investing a lot of time in this. That certainly indicates someone considers it a worthwhile endeavor.
public int CountRelevantItems(IEnumerable<Thing> things)
{
// Non-trivial filter that you don't want in a where lamdba
Func<Thing, bool> isRelevant = (t) =>
{
...
}
return things.Where(t => isRelevant(t)).Count()
}
But in Python you can already define functions inside of functions so you have a better solution: def CountRelevantThings(things):
def isRelevant(thing):
...
return len(filter(isRelevant, things))Why wouldn't you just create another function in the same class?
Doing this without code blocks adds extra code like launching another thread, connecting the scope to the new thread.
Code blocks let you write
with myfunc(iter) << 'x, y':
code which uses x and y
instead of def some_func_name(x, y):
code which uses x and y
myfunc(iter, some_func_name)
If you prefer the second form, then you don't need code blocks.
I think the first form is much better.
It's not just a matter of saving one single line: you don't have to define a function which you'll never use again, so the first code is actually more readable. "Here is what my DSL can look like with Blocks in Smalltalk"
(condition)
ifTrue: [ ... ]
ifFalse: [ ... ]
ifMaybe: [ ... ]
You can accomplish the same thing with named functions and function pointers, but it makes the DSL very awkward to use. Imagine if you had to write all of your conditional logic (if-then and if-then-else and switch) using the names of functions defined elsewhere. That would be much less readable than being able to write block of code inline.In the right environment, that might actually encourage developers to write short methods. In the wrong one, it might encourage longer ones. It would discourage me from writing DSL control structures.
Gedankenexperiment. Imagine this: An IDE that quickly lets you browse the code for a function by pressing a key, or hovering over its name invoked in code. Some smart cookie then comes up with an add-on that provides a switchable view with in-lines for the function code, as if in a code block.