PEP: possibility of inline using of a symbol instead of "import"

D

dmitrey

hi all,
I have th PEP (I'm not sure something like that hadn't been proposed
although):
very often in a Python file header the following lines are present,
like:
from MyModule1 import myFunc1
import MyModule2 as mm2
from MyModule3 import myFunc3 as mf3
etc

and after several pages of code they are using somewhere, maybe only
one time, e.g.
r1 = myFunc1(...)
r2 = mm2.myFunc2(...)
r3 = mf3(...)
It makes programs less clear, you have to scroll several pages of code
in IDE to understand what it refers to.

I propose to add possibility of using a symbol instead (for simplicity
I use @ here, that is already reserved for decorators, thus it should
be other symbol, maybe from Unicode although for simplicity to type it
I would prefer something ordinary like $ or ` or !).

e.g. instead of

import MyModule
(...lots of code...)
r = MyModule.myFunc(...)

someone could just type in the single place

r = @MyModule.myFunc(...)

Also, "import MyModule2 as mm2" could be replaced to mere
mm2 = @MyModule2
and "from MyModule3 import myFunc3 as mf3" could be replaced to mere
"mf3 = @MyModule3.myFunc3".

As for __import__(ModuleTextName), it could be replaced to something
like @(ModuleTextName) or @{ModuleTextName} or @[ModuleTextName].

Regards, D.
 
T

Tim Harig

and after several pages of code they are using somewhere, maybe only
one time, e.g. [SNIP]
It makes programs less clear, you have to scroll several pages of code
in IDE to understand what it refers to.

Python doesn't require imports to be at the top of a file. They can be
imported at any time.
import MyModule
(...lots of code...)
r = MyModule.myFunc(...)

(...lots of code...)
import MyModule
r = MyModule.myFunc(...)
 
T

Tim Harig

On 2011-01-06 said:
Yes, I know, still usually it is placed in file header

1. Don't top post.

2. Your so-called PEP probably clashes with Python's use of @ for
decorators.

3. Do you really expect a language holding the mantra that there should be
a single way of doing things to embrace a language bloating feature
for what is effectively already possible with the language as it
exists?
 
M

Mike Kent

Your complaint seems to be that:

   r1 = myFunc1(...)

is unclear when you don't know where myfunc1 originates, so why don't
you write:

   r1 = MyModule1.myFunc1(...)

My interpretation of his proposal is a bit different. I thought he
meant that '@MyModule.myFunc' (yes, using '@' here is bad, but for
conversation sake...) would cause MyModule to be imported if this was
the first time '@MyModule' was encountered in the current module.
Sort of an implied 'import MyModule', which would eliminate the need
to actually use the explicit import.

My reaction to his proposal is 'Meh.' Explicit is better than
implicit. Python is not Perl.
 
I

Ian

2. Your so-called PEP probably clashes with Python's use of @ for
        decorators.

3. Do you really expect a language holding the mantra that there should be
        a single way of doing things to embrace a language bloating feature
        for what is effectively already possible with the language as it
        exists?

Isn't "Python's use of @ for decorators" a "language bloating feature
for what [was] effectively already possible with the language as it
[existed]?" ;-)

Cheers,
Ian
 
T

Tim Chase

2. Your so-called PEP probably clashes with Python's use of @ for
decorators.

3. Do you really expect a language holding the mantra that there should be
a single way of doing things to embrace a language bloating feature
for what is effectively already possible with the language as it
exists?

Just as a side note, decorators (your #2, and an approved PEP) do
exactly what you mention in #3, as

@my_decorator
def my_func(...): pass

could just as well be written as

def my_func(...): pass
my_func = my_decorator(my_func)

so you #3 point is counterargued by your #2 point :-/

So the powers-that-be have certainly deemed *some* level of
syntactic sugar worthwhile.

That said, I'm -1 (okay, -0.5) on the OP's suggestion, both in
terms of the syntax clashing with decorators, and the need for
syntactic sugar in this case.

-tkc
 
E

Erwin Mueller

hi all,
I have th PEP (I'm not sure something like that hadn't been proposed
although):
very often in a Python file header the following lines are present,
like:
from MyModule1 import myFunc1
import MyModule2 as mm2
from MyModule3 import myFunc3 as mf3
etc

and after several pages of code they are using somewhere, maybe only
one time, e.g.
r1 = myFunc1(...)
r2 = mm2.myFunc2(...)
r3 = mf3(...)
It makes programs less clear, you have to scroll several pages of code
in IDE to understand what it refers to.

Regards, D.

Why you have several pages of code in the first place? Don't you know that you
can split your code in files? Just a suggestion.
 
D

dmitrey

Why you have several pages of code in the first place? Don't you know that you
can split your code in files? Just a suggestion.

Erwin, take a look at Python language developers source code and see
how many files have *tens* of pages. Or any other mature soft, e.g.
numpy or scipy.
Also, possibility of splitting *my* files doesn't matter I can split
other files I deal with, e.g. written by other programmers.
D.
 
R

Robert Kern

Why you have several pages of code in the first place? Don't you know that you
can split your code in files? Just a suggestion.

Modules *should* have several pages of code. *Functions* should be limited to
about a page of code at maximum.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
A

Alan Meyer

> hi all,
> I have th PEP (I'm not sure something like that hadn't been proposed
> although):
> very often in a Python file header the following lines are present,
> like:
> from MyModule1 import myFunc1
> import MyModule2 as mm2
> from MyModule3 import myFunc3 as mf3
> etc
....

Personally, I always do all of my imports at the top of every
program I write and like it when others do the same. The reason
is that, in a single glance, I can see all of the dependencies of
the program.

For similar reasons of explicit clarity I prefer this construct:

import re
pat = re.compile(...)

To something like this one:

from re import compile as cp
pat = cp(...)

The only benefit I can see from your proposal is that it cuts
down slightly on the number of characters in a program, but I
think it does so at the cost of reducing explicit clarity and
increasing the learning burden for a programmer who will have to
learn two techniques (if only so she can read other people's
code) instead of one.

Also, there are only 95 printable ASCII characters most of which
are already dedicated to other uses (e.g., for use in variable
names.) I would hate to reserve one to do something that can be
done equally well without reserving a character.

I applaud your interest in improving the language but I don't
think the benefit justifies the cost in this case.

Alan
 
S

Steven D'Aprano

2. Your so-called PEP probably clashes with Python's use of @ for
        decorators.

3. Do you really expect a language holding the mantra that there should
be
        a single way of doing things to embrace a language bloating
        feature for what is effectively already possible with the
        language as it exists?

Isn't "Python's use of @ for decorators" a "language bloating feature
for what [was] effectively already possible with the language as it
[existed]?" ;-)

Yes. The difference is that the invention of decorator syntax was a huge
success, encouraging people to write code in a new way that added great
power and expressiveness to their code. Guido's intuition as a language
designer got decorator syntax right.

Although function decorators of a sort have been possible since Python
1.5 or older (functions have always been first class objects), it needed
good syntax that puts the wrapper function up near the function def to
get people to see their potential. Decorator syntax isn't merely a time-
saver, or to reduce the number of keystrokes needed from this:

def spam():
pass

spam = wrapper(spam)


to this:

@wrapper
def spam():
pass


While the two are functionally equivalent, the two are not mentally
equivalent to the reader and writer. Decorators are significantly
enhanced by the new syntax: it means you no longer have to use the
function name three times, which is a code smell. More importantly, it
puts the wrapper up with the function signature, where it belongs,
instead of obscurely down the bottom past the definition. The end result
has been to take a powerful design pattern that was always possible but
hardly ever used, and make it friendly and far more common. This has been
a huge win.

So @ loses two points for being obscure and bringing nothing new to the
language, while gaining ten thousand points for being one of the most
successful examples of syntactic sugars since people realised they could
use assembly language op codes instead of writing in hex.


The use of syntax to turn:

import module
module.function()

into something like:

@module.function()

is unlikely to give any such win. Its utility is fairly narrow: it
doesn't encourage any new design patterns. It does save a few characters
of typing, which may be a small win, but the use of this will be a code
smell. Python doesn't require all imports to be at the beginning of your
module, but it is recommended, and this inlining of imports encourages
the anti-pattern of scattering imports all throughout your code base.

Let me put it this way. The suggested syntactic sugar will encourage code
that is functionally the equivalent of this:

import math
math.sin(1.2)

# ...
# much later

import math
math.cos(2.5)

# ...
# much later

import math
math.sqrt(24)


Yes, the subsequent imports are relatively fast, but even so, we
shouldn't *encourage* that sort of thing with special syntax for it.


If you don't like this code pattern:

import function from module
# ...
# much code goes here
# ...
function(x)


then instead of creating new syntax, the conventional solution is the
best:

import module
# ...
# much code goes here
# ...
module.function(x)
 
E

Erwin Mueller

Modules *should* have several pages of code. *Functions* should be limited
to about a page of code at maximum.

I'm not quite familar with Python development, but why should modules
be so big that the user is lost in the code? What is preventing you from
splittin a module in several files, each file with a single responsibility?
 
E

Erwin Mueller

Modules *should* have several pages of code. *Functions* should be limited
to about a page of code at maximum.

I'm not quite familar with Python development, but why should modules
be so big that the user is lost in the code? What is preventing you from
splittin a module in several files, each file with a single responsibility?
 
C

Chris Rebert

       I'm not quite familar with Python development, but why should modules
be so big that the user is lost in the code?

They shouldn't, but due to Python's conciseness, the amount of code a
module can hold before it becomes unwieldy is a good bit greater than
some more verbose languages. Unlike say, Java, it is quite normal to
have several classes, functions, and constants in a single Python
module. "Several pages" is not an unreasonable upper bound for a
Python module.
What is preventing you from
splittin a module in several files, each file with a single responsibility?

Circular dependencies perhaps. Also, how a responsibility is defined
and what level of module granularity is most useful is a design
decision requiring skilled judgment; it's possible that
just-one-module is appropriate for Dmitrey's situation.

Cheers,
Chris
 
S

Steven D'Aprano

They shouldn't, but due to Python's conciseness, the amount of code a
module can hold before it becomes unwieldy is a good bit greater than
some more verbose languages. Unlike say, Java, it is quite normal to
have several classes, functions, and constants in a single Python
module. "Several pages" is not an unreasonable upper bound for a Python
module.

Have a look at the decimal.py module in the standard library. That's
nearly 5800 lines, including blanks, comments and docstrings, for 18
classes and 19 top-level functions, over 88 pages. I'd call that the
maximum size I'm comfortable with a single module. "Several pages" is
nothing to fear.

I recently split a module I'm working on into a package of seven modules
(plus about the same again for tests). My module was about 2500 lines,
for about 50 classes and functions, and I expect it to grow by another
dozen or so functions over the coming months.

Splitting a single module into multiples doesn't happen for free. You
have to worry about imports and dependencies that simply aren't an issue
in a single module. But on the plus side, I was able to rename a bunch of
similar-but-different functions from:

module.function
module.function1

to a much more sensible:

module.function
module.submodule.function
 
C

Carl Banks

hi all,
I have th PEP (I'm not sure something like that hadn't been proposed
although):
very often in a Python file header the following lines are present,
like:
from MyModule1 import myFunc1
import MyModule2 as mm2
from MyModule3 import myFunc3 as mf3
etc

and after several pages of code they are using somewhere, maybe only
one time, e.g.
r1 = myFunc1(...)
r2 = mm2.myFunc2(...)
r3 = mf3(...)
It makes programs less clear, you have to scroll several pages of code
in IDE to understand what it refers to.

I propose to add possibility of using a symbol instead (for simplicity
I use @ here, that is already reserved for decorators, thus it should
be other symbol, maybe from Unicode although for simplicity to type it
I would prefer something ordinary like $ or ` or !).

e.g. instead of

import MyModule
(...lots of code...)
r = MyModule.myFunc(...)

someone could just type in the single place

r = @MyModule.myFunc(...)

Also, "import MyModule2 as mm2" could be replaced to mere
mm2 = @MyModule2
and "from MyModule3 import myFunc3 as mf3" could be replaced to mere
"mf3 = @MyModule3.myFunc3".

As for __import__(ModuleTextName), it could be replaced to something
like @(ModuleTextName) or @{ModuleTextName} or @[ModuleTextName].


I actually wouldn't mind this; in fact Python's importing mechanism is
bad enough that a complete overhaul might not be a bad thing.

But, first of all, one can already do in-line imports in Python with
the __import__ built-in function (and I used to do this frequently in
throwaway scripts before list comprehensions were added). For
instance, a one-liner to generate a password would be this:

python -c 'for i in xrange(8):
__import__("sys").stdout.write(__import__("random").choice(__import__("string").letters))'

Today a better way to do it would be like this:

python -c 'import random,string; print
"".join(random.choice(string.letters) for i in xrange(8))'

But that's a digression.

The problem with in-line imports is that it can lead to deadlock in
multithreaded programs, so for the most part it's a good idea to avoid
importing within functions.

Therefore, a syntax for it would really be needed to gain full
benefit. This would allow the compiler to scan the file to collect a
list of prerequisite modules. In my mind, the module itself wouldn't
import the dependencies itself, it simply lists prerequisites and
leaves it to the runtime to ensure that they've been imported.

A side benefit to this is to keep module namespaces clean.

Main drawback is that it makes accessing symbols in deepely nested
packages unwieldy (since presumably you'd have to write out the fully-
qualified name). Meh, I pretty much avoid deeply nested packages, and
typically spell out the fully-qualified module names anyway. So not
my problem.

As for listing imports at the top of the program--I can't say I have
much use for it. Sometimes it helps to see a list of prerqequisites
in one place, but I can't say it's the most useful thing ever, and
anyway it's misleading since the imports can become stale. I'd rather
not have to stop and scroll up ten pages to add an import to the top
of the module when I suddenly need to access time.sleep or
itertools.count.

So, pending a better syntax, I'll give it a +0; and the only reason I
don't give it a +1 is it's such a drastic change.

The syntax probably would deserve a lot of thought (being such a
drastic change) but drawing from C++ a postfix operator would seem to
fit.

sys:: -> evaulates to the sys module
sys::version -> evaluates to sys.version
xml::etree::ElementTree:: -> as expected

That has the unfortunate effect of making Python look like C++ though.


Won't ever happen though.


Carl Banks
 

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,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top