is there any principle when writing python function

C

Chris Angelico

While I understand and agree with that basic tenet, I think
that the capitalized 'ONLY' is too strong.  I do split out
code into function for readability, even when the function
will only be called from the place from which I split it out.

This can be good and can be bad. It's good when it aids readability;
it's bad when you need to pass practically the entire locals() as
function arguments and/or return values. I would split the function
only when both halves (caller and callee) can be given short and
useful names - if you can't explain what a block of code does in a few
words, it's probably a poor choice for splitting out into a function.

ChrisA
 
R

rantingrick

In said:
Furthermore: If you are moving code out of one function to ONLY be
called by that ONE function then you are a bad programmer and should
have your editor taken away for six months. You should ONLY create
more func/methods if those func/methods will be called from two or
more places in the code. The very essence of func/meths is the fact
that they are reusable.

That's one very important aspect of functions, yes.  But there's another:
abstraction.
[...]
The main module keeps a high level of abstraction instead of descending
into dozens or even hundreds of lines of LDAP-specific code.

Exactly. I am not arguing against creating intuitive and
simplistically elegant interfaces. I mean, lists *could* have only one
method called apply(process, *args, **kw) which takes an argument like
("append", "value") or ("index", 42) and has a long block of logic to
handle the inputs however that would be a horrible interface.

So in that respect i agree. We must weigh the entire interface from an
empirical perspective. However i can be sure of one point: As you
increase the number of methods you also increase the mental load
required to understand that particular interface.

An interface with a small number of methods will not suffer too
terribly from one or two extra methods however at some point more
methods just equals more confusion. It is a delicate balancing act
that many programmers are not agile enough to juggle elegantly.

Take for instance the interface for Grep, Search, and Replace dialogs
in the idlelib which span two separate modules and have a mind numbing
number of methods for such remedial things as creating buttons and
entrys. All three dialogs look very similar and share many
similarities.

Now take a look at MY simple ONE module solution. It has JUST enough
methods and NOT a single more! Yes the create widgets method is fairly
long (weighing in at 80+ lines with comments!) however all of this
code needs to be contained in ONE and ONLY one method. Heck if i
wanted to get pendantic i could replace the five cb_*() methods with
partials however MY interface is so intuitive there is no need.

############################################################
# START CODE
############################################################
class FindReplaceDialog(object):
def __init__(self, textbox):
[...]

def create_widgets(self, type_):
# Create toplevel dialog window.
[...]
# Create widgets belonging to both
# search AND replace dialogs dialogs.
[...]
if type_ == 'replace':
# Add widgets unique to replace
# dialogs.
[...]
elif type_ == 'grep':
# Add widgets unique to grep
# dialogs.
[...]
# Load any initial values and states.
[...]

def show(self, type_='find'):
self.create_widgets(type_)
# Do any initial setup.

def close(self, event=None):
# destroy the dialog.

def find_again(self, event=None):
# Event callback bound to textbox.

def find(self, target):
# Search the buffer for target and
# hilight if found.

def replace(self, action='replace'):
# Fetch the old and new strings and
# mediate the work depending on the
# action.
[...]
if action == 'replace+find':
[...]
elif action == 'replaceall':
[...]

def grep():
[...]

def cb_grepbutton(self, event=None):
self.grep(target.entry.get())

def cb_findbutton(self, event=None):
self.find(target.entry.get())

def cb_replacebutton(self):
self.replace(action='replace')

def cb_replacefindbutton(self):
self.replace(action='replace+find')

def cb_replaceallbutton(self):
self.replace(action='replaceall')
############################################################
# END CODE
############################################################

Now look at the three modules in idlelib (Grep Dialog, Search Dialog,
and Replace Dialog) and ask yourself which is cleaner? Which is more
intuiitve? Which is more professional? Which would you rather debug?

*scholl-bell-rings*
 
S

Steven D'Aprano

Tobiah said:
While I understand and agree with that basic tenet, I think
that the capitalized 'ONLY' is too strong. I do split out
code into function for readability, even when the function
will only be called from the place from which I split it out.

In other words, you disagree. Which is good, because the text you quote is
terrible advice, and it is ironic that the person you quote judges others
as bad programmers when his advice is so bad.

I can think of at least five reasons apart from re-use why it might be
appropriate to pull out code into its own function or method even if it is
used in one place only:

(1) Extensibility. Just earlier today I turned one method into three:

def select(self):
response = input(self)
if response:
index = self.find(response)
else:
index = self.default
return self.menuitems[index-1]

turned into:

def choose(self, response):
if response:
index = self.find(response)
else:
index = self.default
return self.menuitems[index-1]

def raw_select(self):
return input(self)

def select(self):
return self.choose(self.raw_select())


I did this so that subclasses could override the behaviour of each component
individually, even though the caller is not expected to call raw_select or
choose directly. (I may even consider making them private.)

(2) Testing. It is very difficult to reach into the middle of a function and
test part of it. It is very difficult to get full test coverage of big
monolithic blocks of code: to ensure you test each path through a big
function, the number of test cases rises exponentially. By splitting it
into functions, you can test each part in isolation, which requires much
less work.

(3) Fault isolation. If you have a 100 line function that fails on line 73,
that failure may have been introduced way back in line 16. By splitting the
function up into smaller functions, you can more easily isolate where the
failure comes from, by checking for violated pre- and post-conditions.

(4) Maintainability. It's just easier to document and reason about a
function that does one thing, than one that tries to do everything. Which
would you rather work with, individual functions for:

buy_ingredients
clean_kitchen_work_area
wash_vegetables
prepare_ingredients
cook_main_course
fold_serviettes
make_desert
serve_meal
do_washing_up

etc., or one massive function:

prepare_and_serve_five_course_meal

Even if each function is only called once, maintenance is simpler if the
code is broken up into more easily understood pieces.

(5) Machine efficiency. This can go either way. Code takes up memory too,
and it may be easier for the compiler to work with 1000 small functions
than 1 big function. I've actually seen somebody write a single function so
big that Python couldn't import the module, because it ran out of memory
trying to compile it! (This function was *huge* -- the source code was many
megabytes in size.) I don't remember the details, but refactoring the
source code into smaller functions fixed it.

On the other hand, if you are tight for memory, 1 big function may have less
overhead than 1000 small functions; and these days, with even entry level
PCs often having a GB or more of memory, it is rare to come across a
function so big that the size of code matters. Even a 10,000 line function
is likely to be only a couple of hundred KB in size:
90028


So that's four really good reasons for splitting code into functions, and
one borderline one, other than code re-use. There may be others.
 
C

Chris Angelico

Now take a look at MY simple ONE module solution. It has JUST enough
methods and NOT a single more!

I disagree - create_widgets() is completely unnecessary in the
presence of show(), unless it's possible to show the dialog, hide it,
and then re-show it without recreating the widgets.


I can think of at least five reasons apart from re-use why it might be
appropriate to pull out code into its own function or method even if it is
used in one place only:

I'm glad you say "might be", because your five reasons aren't always
reasons for refactoring. I'll play devil's advocate for a moment,
because discussion is both fun and informative: :)
(1) Extensibility. Just earlier today I turned one method into three:
I did this so that subclasses could override the behaviour of each component
individually, even though the caller is not expected to call raw_select or
choose directly. (I may even consider making them private.)

Definitely, but it's no value if you make every tiny thing into your
own function. Sometimes the best way to code is to use lower-level
functionality directly (not wrapping input() inside raw_select() for
instance), and letting someone monkey-patch if they want to change
your code. A judgment call.
(2) Testing. It is very difficult to reach into the middle of a function and
test part of it. ... By splitting it
into functions, you can test each part in isolation, which requires much
less work.

Yes, but 100% coverage isn't that big a deal. If the function does
precisely one logical thing, then you don't _need_ to test parts in
isolation - you can treat it as a black box and just ensure that it's
doing the right thing under various circumstances. However, this ties
in nicely with your next point...
(3) Fault isolation. If you have a 100 line function that fails on line 73,
that failure may have been introduced way back in line 16. By splitting the
function up into smaller functions, you can more easily isolate where the
failure comes from, by checking for violated pre- and post-conditions.

.... and here's where #2 really shines. If you break your function in
two, the natural thing to do is to test each half separately, with the
correct preconditions, and examine its output. If your fault was on
line 16, your test for that half of the function has a chance of
detecting it. I don't have a Devil's Advocate put-down for this one,
save the rather weak comment that it's possible to check pre- and
post-conditions without refactoring. :)
(4) Maintainability. It's just easier to document and reason about a
function that does one thing, than one that tries to do everything. Which
would you rather work with, individual functions for:
... omnomnom ...
Even if each function is only called once, maintenance is simpler if the
code is broken up into more easily understood pieces.

Yes, as long as you do the job intelligently. Goes back to what I said
about naming functions - in your kitchen example, every function has a
self-documenting name, which means you've broken it out more-or-less
correctly. (I'd still want to have
prepare_and_serve_five_course_meal() of course, but it would be
calling on all the others.) Breaking something out illogically doesn't
help maintainability at all - in fact, it'll make it worse. "So this
function does what, exactly? And if I need to add a line of code,
ought I to do it here, or over there? Does anyone else actually call
this function? MIGHT someone be reaching into my module and calling
this function directly? I'd better keep it... ugh."
(5) Machine efficiency. This can go either way.

And that's the very best thing to say about efficiency. Ever. In C, I
can write static functions and let the compiler inline them; in Java,
I tried to do the same thing, and found ridiculous overheads. Ended up
making a monolith rather than go through Java's overhead. But if I'd
changed what VM I was running it on, that might well have changed.
Profile, profile, profile.
So that's four really good reasons for splitting code into functions, and
one borderline one, other than code re-use. There may be others.

I'm sure there are. But let's face it: We're programming in PYTHON.
Not C, not Erlang, not Pike, not PHP. Python. If this has been the
right choice, then we should assume that efficiency isn't king, but
readability and maintainability probably are; so the important
considerations are not "will it take two extra nanoseconds to execute"
but "can my successor understand what the code's doing" and "will he,
if he edits my code, have a reasonable expectation that he's not
breaking stuff". These are always important.

ChrisA
 
R

rantingrick

I disagree - create_widgets() is completely unnecessary in the
presence of show(),

Well since you cannot see the underlying code i won't be too harsh on
you :), but yes, i can assure you that create widgets IS necessary for
readability. show() calls "self.create_widgets()" then adds a special
hit tag to the text widget and sets up a modal behavior of the dialog,
it's only 5-7 lines of setup code but i think the separation is
warranted.

Could i have rolled all the create_widgets() code into the show()
method? Of course, however i do see a good reason for separation here
for the sake of readability. Although i must admit, had the interface
been much larger i most assuredly would have rolled it together.
unless it's possible to show the dialog, hide it,
and then re-show it without recreating the widgets.

Yes the instance lives on between session to save state. Also the
"find_again" binding of the text widget calls the
SearchReplaceDialog.find_again() method when {CONTROL+G} event fires.
I'm sure there are. But let's face it: We're programming in PYTHON.
Not C, not Erlang, not Pike, not PHP. Python. If this has been the
right choice, then we should assume that efficiency isn't king, but
readability and maintainability probably are; so the important
considerations are not "will it take two extra nanoseconds to
execute" but "can my successor understand what the code's doing" and
"will he, if he edits my code, have a reasonable expectation that
he's not breaking stuff". These are always important.

Bravo! That has to be most lucid and intelligent statement from you to
date. And i must say the warm fuzzies i got from imagining the defeat
D'Aprano must have felt whist reading it left me with a nice feeling.

How do like them apples, D'Aprano? :)
 
R

rantingrick

(3) Fault isolation. If you have a 100 line function that fails on line 73,
that failure may have been introduced way back in line 16. By splitting the
function up into smaller functions, you can more easily isolate where the
failure comes from, by checking for violated pre- and post-conditions.

What's wrong Steven, are track backs too complicated for you?

############################################################
# START DUMMY SCRIPT
############################################################
def very_long_function():
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(object)
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
max(range(5))
#
print 'blah'
print 'blah'
print 'blah-blah'
very_long_function()
############################################################
# END DUMMY SCRIPT
############################################################

Traceback (most recent call last):
File "C:/Python27/test33333.py", line 48, in <module>
very_long_function()
File "C:/Python27/test33333.py", line 26, in very_long_function
max(object)
TypeError: 'type' object is not iterable

Oh the humanity!
 
S

Steven D'Aprano

Chris said:
I'm glad you say "might be", because your five reasons aren't always
reasons for refactoring. I'll play devil's advocate for a moment,
because discussion is both fun and informative: :)

Naturally :)

I say "might be" because I mean it: these arguments have to be weighed up
against the argument against breaking code out of functions. It's easy to
imagine an extreme case where there are a billion *tiny* functions, each of
which does one micro-operation:

def f1(x): return x + 1
def f2(x): return 3*x
def f3(x): return f2(f1(x)) # instead of 3*(x+1)
....

If spaghetti code (GOTOs tangled all through the code with no structure) is
bad, so is ravioli code (code bundled up into tiny parcels and then thrown
together higgledy-piggledy). Both cases can lead to an unmaintainable mess.
Nobody is arguing that "More Functions Is Always Good". Sensible coders
understand that you should seek a happy medium and not introduce more
functions just for the sake of having More! Functions!.

But I'm not arguing with you, we're in agreement.


One last comment though:

[...]
Definitely, but it's no value if you make every tiny thing into your
own function. Sometimes the best way to code is to use lower-level
functionality directly (not wrapping input() inside raw_select() for
instance), and letting someone monkey-patch if they want to change
your code. A judgment call.

I agree on the first part (don't split *everything* into functions) but I
think that the monkey-patch idea is tricky and dangerous in practice. The
first problem is, how do you know what needs to be monkey-patched? You may
not have access to the source code to read, and it may not be as obvious
as "oh, it gets input from the user, so it must be calling input()".

Second, even if you know what to monkey-patch, it's really hard to isolate
the modification to just the method you want. By their nature, monkey-
patches apply globally to the module. And if you patch the builtins module,
they apply *everywhere*.

So while monkey-patching can work, it's tricky to get it right and it should
be left as a last resort.
 
C

Chris Angelico

I say "might be" because I mean it: these arguments have to be weighed up
against the argument against breaking code out of functions. It's easy to
imagine an extreme case where there are a billion *tiny* functions, each of
which does one micro-operation:

def f1(x): return x + 1
def f2(x): return 3*x
def f3(x): return f2(f1(x))  # instead of 3*(x+1)

This fails the "give it a decent name" test. Can you name these
functions according to what they do, as opposed to how they do it? For
instance:

def add_flagfall(x): return x + 1 # add a $1 flagfall to the price
def add_tax(x): return 3*x # this is seriously nasty tax
def real_price(x): return add_tax(add_flagfall(x))  # instead of 3*(x+1)

This would be acceptable, because each micro-operation has real
meaning. I'd prefer to do it as constants rather than functions, but
at least they're justifying their names.

And you're absolutely right about monkey-patching.

ChrisA
 
R

Roy Smith

Chris Angelico said:
the important
considerations are not "will it take two extra nanoseconds to execute"
but "can my successor understand what the code's doing" and "will he,
if he edits my code, have a reasonable expectation that he's not
breaking stuff". These are always important.

Forget about your successor. Will *you* be able to figure out what you
did 6 months from now? I can't tell you how many times I've looked at
some piece of code, muttered, "Who wrote this crap?" and called up the
checkin history only to discover that *I* wrote it :)
 
C

Chris Angelico

Forget about your successor.  Will *you* be able to figure out what you
did 6 months from now?  I can't tell you how many times I've looked at
some piece of code, muttered, "Who wrote this crap?" and called up the
checkin history only to discover that *I* wrote it :)

Heh. In that case, you were your own successor :) I always word it as
a different person to dodge the "But I'll remember!" excuse, but you
are absolutely right, and I've had that exact same experience myself.

Fred comes up to me and says, "How do I use FooMatic?" Me: "I dunno,
ask Joe." Fred: "But didn't you write it?" Me: "Yeah, that was years
ago, I've forgotten. Ask Joe, he still uses the program."

ChrisA
 
E

Emile van Sebille

the important
considerations are not "will it take two extra nanoseconds to execute"
but "can my successor understand what the code's doing" and "will he,
if he edits my code, have a reasonable expectation that he's not
breaking stuff". These are always important.

Forget about your successor. Will *you* be able to figure out what you
did 6 months from now? I can't tell you how many times I've looked at
some piece of code, muttered, "Who wrote this crap?" and called up the
checkin history only to discover that *I* wrote it :)[/QUOTE]

When you consider that you're looking at the code six months later it's
likely for one of three reasons: you have to fix a bug; you need to add
features; or the code's only now getting used.

So you then take the extra 20-30 minutes, tease the code apart, refactor
as needed and end up with better more readable debugged code.

I consider that the right time to do this type of cleanup.

For all the crap I write that works well for six months before needing
to be cleaned up, there's a whole lot more crap that never gets looked
at again that I didn't clean up and never spent the extra 20-30 minutes
considering how my future self might view what I wrote.

I'm not suggesting that you shouldn't develop good coding habits that
adhere to established standards and result in well structured readable
code, only that if that ugly piece of code works that you move on. You
can bullet proof it after you uncover the vulnerabilities.

Code is first and foremost written to be executed.

Emile
 
C

Chris Angelico

Code is first and foremost written to be executed.

+1 QOTW. Yes, it'll be read, and most likely read several times, by
humans, but ultimately its purpose is to be executed.

And in the case of some code, the programmer needs the same treatment,
but that's a different issue...

ChrisA
 
S

Steven D'Aprano

Chris said:
+1 QOTW. Yes, it'll be read, and most likely read several times, by
humans, but ultimately its purpose is to be executed.

You've never noticed the masses of code written in text books, blogs, web
pages, discussion forums like this one, etc.?

Real world code for production is usually messy and complicated and filled
with data validation and error checking code. There's a lot of code without
that, because it was written explicitly to be read by humans, and the fact
that it may be executed as well is incidental. Some code is even written in
pseudo-code that *cannot* be executed. It's clear to me that a non-trivial
amount of code is specifically written to be consumed by other humans, not
by machines.

It seems to me that, broadly speaking, there are languages designed with
execution of code as the primary purpose:

Fortran, C, Lisp, Java, PL/I, APL, Forth, ...

and there are languages designed with *writing* of code as the primary
purpose:

Perl, AWK, sed, bash, ...

and then there are languages where *reading* is the primary purpose:

Python, Ruby, Hypertalk, Inform 7, Pascal, AppleScript, ...

and then there are languages where the torment of the damned is the primary
purpose:

INTERCAL, Oook, Brainf*ck, Whitespace, Malbolge, ...

and then there are languages with few, or no, design principles to speak of,
or as compromise languages that (deliberately or accidentally) straddle the
other categories. It all depends on the motivation and values of the
language designer, and the trade-offs the language makes. Which category
any specific language may fall into may be a matter of degree, or a matter
of opinion, or both.
 
C

Chris Angelico

You've never noticed the masses of code written in text books, blogs, web
pages, discussion forums like this one, etc.?

Real world code for production is usually messy and complicated and filled
with data validation and error checking code. There's a lot of code without
that, because it was written explicitly to be read by humans, and the fact
that it may be executed as well is incidental. Some code is even written in
pseudo-code that *cannot* be executed. It's clear to me that a non-trivial
amount of code is specifically written to be consumed by other humans, not
by machines.

Yes, I'm aware of the quantities of code that are primarily for human
consumption. But in the original context, which was of editing code
six months down the track, I still believe that such code is primarily
for the machine. In that situation, there are times when it's not
worth the hassle of writing beautiful code; you'd do better to just
get that code generated and in operation.

Same goes for lint tools and debuggers - sometimes, it's easier to
just put the code into a live situation (or a perfect copy of) and see
where it breaks, than to use a simulation/test harness.

ChrisA
 
E

Emile van Sebille

Code is first and foremost written to be executed.


“Programs must be written for people to read, and only incidentally for
machines to execute.â€
—Abelson& Sussman, _Structure and Interpretation of Computer Programs_
[/QUOTE]

That's certainly self-fulfilling -- code that doesn't execute will need
to be read to be understood, and to be fixed so that it does run.
Nobody cares about code not intended to be executed. Pretty it up as
much as you have free time to do so to enlighten your intended audience.

Code that runs from the offset may not ever again need to be read, so
the only audience will ever be the processor.

I find it much to easy to waste enormous amounts of time prettying up
code that works. Pretty it up when it doesn't -- that's the code that
needs the attention.

Emile
 
R

rantingrick

On 8/27/2011 2:57 PM Ben Finney said...



That's certainly self-fulfilling -- code that doesn't execute will need
to be read to be understood, and to be fixed so that it does run.
Nobody cares about code not intended to be executed.  Pretty it up as
much as you have free time to do so to enlighten your intended audience.

Code that runs from the offset may not ever again need to be read, so
the only audience will ever be the processor.

WRONG!

Code may need to be extended someday no matter HOW well it executes
today. Also, code need to be readable so the readers can learn from
it.
 
R

Roy Smith

Emile van Sebille said:
code that doesn't execute will need to be read to be understood, and
to be fixed so that it does run.

That is certainly true, but it's not the whole story. Even code that
works perfectly today will need to be modified in the future. Business
requirements change. Your code will need to be ported to a new OS.
You'll need to make it work for 64-bit. Or i18n. Or y2k (well, don't
need to worry about that one any more). Or with a different run-time
library. A new complier. A different database. Regulatory changes
will impose new requirements Or, your company will get bought and
you'll need to interface with a whole new system.

Code is never done. At least not until the project is dead.
 
S

Stephen Hansen

“Programs must be written for people to read, and only
incidentally for
machines to execute.â€
—Abelson& Sussman, _Structure and Interpretation of Computer
Programs_

That's certainly self-fulfilling -- code that doesn't execute will need
to be read to be understood, and to be fixed so that it does run. Nobody
cares about code not intended to be executed. Pretty it up as much as
you have free time to do so to enlighten your intended audience.[/QUOTE]

Er, you're interpreting the quote... way overboard. No one's talking
about code that isn't intended to be executed, I don't think; the quote
includes, "and only incidentally for machines to execute." That's still
the there, and its still important. It should just not be the prime
concern while actually writing the code.

The code has to actually do something. If not, obviously you'll have to
change it.

The Pythonic emphasis on doing readable, pretty code isn't JUST about
making code that just looks good; its not merely an aesthetic that the
community endorses.

And although people often tout the very valid reason why readability
counts-- that code is often read more then written, and that coming back
to a chunk of code 6 months later and being able to understand fully
what its doing is very important... that's not the only reason
readability counts.

Readable, pretty, elegantly crafted code is also far more likely to be
*correct* code.

However, this:
Code that runs from the offset may not ever again need to be read, so
the only audience will ever be the processor.

I find it much to easy to waste enormous amounts of time prettying up
code that works. Pretty it up when it doesn't -- that's the code that
needs the attention.

... seems to me to be a rather significant self-fulfilling prophecy in
its own right. The chances that the code does what its supposed to do,
accurately, and without any bugs, goes down in my experience quite
significantly the farther away from "pretty" it is.

If you code some crazy, overly clever, poorly organized, messy chunk of
something that /works/ -- that's fine and dandy. But unless you have
some /seriously/ comprehensive test coverage then the chances that you
can eyeball it and be sure it doesn't have some subtle bugs that will
call you back to fix it later, is pretty low. In my experience.

Its not that pretty code is bug-free, but code which is easily read and
understood is vastly more likely to be functioning correctly and reliably.

Also... it just does not take that much time to make "pretty code". It
really doesn't.

The entire idea that its hard, time-consuming, effort-draining or
difficult to make code clean and "pretty" from the get-go is just wrong.

You don't need to do a major "prettying up" stage after the fact. Sure,
sometimes refactoring would greatly help a body of code as it evolves,
but you can do that as it becomes beneficial for maintenance reasons and
not just for pretty's sake.

--

Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.10 (Darwin)

iQEcBAEBAgAGBQJOWX1YAAoJEKcbwptVWx/lQuMH/At1QkTrnFHogXwu1tK3uYcP
vmq6UKOtIhDmD225qGfmUnAQ5+GEoDHxdNWZKW/VckU1nR2NMjxLdfkjWIiGRslw
JI8LJaJ17TrSptmdJAxY/r0WvEYEPK2CGEurAU9etDiREry5BnvB7AiabW3/Rgzx
vPp9qA4lUHHokF2RGV97cq9HBA+1dKIsBCIUl0tfEdTn675HXKlJOvxpWCBUehOi
kee6fprCT3wyFLeVp8RJv3SNJJgsTPRZ+p47nin6to3bHDxXOcvHqshDYm66JPLm
5DWRWDagaGb3o/QmOHRtr/mrIr86ggn2flzjtvsI2gleHio8uxTI+9TtapUV70g=
=MvCo
-----END PGP SIGNATURE-----
 
H

harrismh777

smith said:
i have heard that function invocation in python is expensive, but make
lots of functions are a good design habit in many other languages, so
is there any principle when writing python function?
for example, how many lines should form a function?

Once Abraham Lincoln was asked how long a man's legs should be. (Well,
he was a tall man and had exceptionally long legs... his bed had to be
specially made.)

Old Abe said, "A man's legs ought to be long enough to reach from his
body to the floor".


One time the Austrian Emperor decided that one of Wolfgang Amadeus
Mozart's masterpieces contained too many notes... when asked how many
notes a masterpiece ought to contain it is reported that Mozart
retorted, "I use precisely as many notes as the piece requires, not one
note more, and not one note less".


After starting the python interpreter import this:

import this


.... study carefully. If you're not Dutch, don't worry if some of it
confuses you. ... apply liberally to your function praxis.


kind regards,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top