On 12/03/2016 16:56, Steven D'Aprano wrote:
On Sun, 13 Mar 2016 12:42 am, BartC wrote:
Ad-hoc attributes I don't have as much of a problem with, as they can be
handy. But predefined ones also have their points. (For one thing, I
know how to implement those efficiently.)
However, when you have a function call like this: M.F(), where M is an
imported module, then it is very unlikely that the functions in M are
going to be created, modified, deleted or replaced while the program
runs. [I mean, after the usual process of executing each 'def' statement.]
What do you consider "very unlikely"? And how do you know what people will
choose to do?
Common sense tells you it is unlikely.
Why then should it have to suffer the same overheads as looking up
arbitrary attributes? And on every single call?
Because they *are* arbitrary attributes of the module. There's only one sort
of attribute in Python. Python doesn't invent multiple lookup rules for
attributes-that-are-functions, attributes-that-are-classes,
attributes-that-are-ints, attributes-that-are-strings, and so on. They are
all the same.
You gain a simpler implementation,
(Have you tried looking at the CPython sources? I tried last year and
couldn't head or tail of them. What was the layout of the pyObject
struct? I couldn't figure it out, the source being such a mess of
conditional code and macros within macros.
So I wouldn't like to see a complex implementation!)
a simpler execution model, simpler rules
for users to learn, and the ability to perform some pretty useful dynamic
tricks on those occasions where it is useful. For example, monkey-patching
a module for testing or debugging purposes.
In languages where functions are different from other values, you have to
recognise ahead of time "some day, I may need to dynamically replace this
function with another" and write your code specially to take that into
account, probably using some sort of "Design Pattern".
No it's very easy. In Python terms:
def f(): return "One"
def g(): return "Two"
h=f
h() returns "One". Later you do h=g, and h() returns "Two". No need for
f and g themselves to be dynamic. h just needs to be a variable.
The same with modules:
import A
import B
M=A
Now M.F() calls A.F(). Do M=B, and M.B now calls B.F(). No need for
module names to be dynamic either! Just variables.
When you dabble with lots of little things, then they can add up. To the
point where an insignificant optimisation can become significant.
Of course. Reduced runtime efficiency is the cost you pay for the
flexibility gained by significant dynamism. It's a trade-off between
efficiency, convenience, simplicity, etc. It's quite legitimate for
language designers to choose to put that trade-off in different places, or
indeed for the trade-off to change over time.
Maybe the designer(s) of Python didn't know how popular it would get.
Do you think some of the design decisions would be different now?
--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list