Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #104528 > unrolled thread
| Started by | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| First post | 2016-03-10 08:27 -0700 |
| Last post | 2016-03-14 15:55 -0700 |
| Articles | 20 on this page of 49 — 10 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: Encapsulation in Python Ian Kelly <ian.g.kelly@gmail.com> - 2016-03-10 08:27 -0700
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-10 16:45 -0800
Re: Encapsulation in Python Ian Kelly <ian.g.kelly@gmail.com> - 2016-03-11 08:47 -0700
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-11 18:39 -0800
Re: Encapsulation in Python Ian Kelly <ian.g.kelly@gmail.com> - 2016-03-12 09:44 -0700
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-12 19:11 -0800
Re: Encapsulation in Python Steven D'Aprano <steve@pearwood.info> - 2016-03-13 21:11 +1100
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-14 10:32 -0700
Re: Encapsulation in Python Ian Kelly <ian.g.kelly@gmail.com> - 2016-03-14 15:09 -0600
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-14 21:23 +0000
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-14 22:07 +0000
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-14 22:20 +0000
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-14 22:40 +0000
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-14 23:19 +0000
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-14 23:56 +0000
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 11:12 +1100
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-15 00:54 +0000
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 11:58 +1100
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-15 01:22 +0000
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 13:02 +1100
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-15 00:28 +0000
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-15 01:10 +0000
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 12:23 +1100
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-15 04:41 +0000
Re: Encapsulation in Python rurpy@yahoo.com - 2016-03-14 17:17 -0700
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 11:25 +1100
Re: Encapsulation in Python Steven D'Aprano <steve@pearwood.info> - 2016-03-15 13:06 +1100
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 13:14 +1100
Re: Encapsulation in Python Steven D'Aprano <steve@pearwood.info> - 2016-03-15 13:40 +1100
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-14 21:08 -0700
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-15 00:47 +0000
Re: Encapsulation in Python Steven D'Aprano <steve@pearwood.info> - 2016-03-15 13:46 +1100
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-15 11:56 +1100
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-15 04:36 +0000
Re: Encapsulation in Python Steven D'Aprano <steve@pearwood.info> - 2016-03-15 13:01 +1100
Re: Encapsulation in Python Mark Lawrence <breamoreboy@yahoo.co.uk> - 2016-03-15 04:45 +0000
Re: Encapsulation in Python Christian Gollwitzer <auriocus@gmx.de> - 2016-03-15 22:02 +0100
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-16 00:39 +0000
Re: Encapsulation in Python BartC <bc@freeuk.com> - 2016-03-16 22:58 +0000
Re: Encapsulation in Python sohcahtoa82@gmail.com - 2016-03-14 11:11 -0700
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-14 23:09 -0700
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-11 18:56 -0800
Re: Encapsulation in Python Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2016-03-12 13:52 +1300
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-12 08:49 -0800
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-13 08:10 +1100
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-12 19:36 -0800
Re: Encapsulation in Python Chris Angelico <rosuav@gmail.com> - 2016-03-13 15:05 +1100
Re: Encapsulation in Python Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2016-03-14 12:35 +1300
Re: Encapsulation in Python Rick Johnson <rantingrickjohnson@gmail.com> - 2016-03-14 15:55 -0700
Page 1 of 3 [1] 2 3 Next page →
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-03-10 08:27 -0700 |
| Subject | Re: Encapsulation in Python |
| Message-ID | <mailman.139.1457623672.15725.python-list@python.org> |
On Thu, Mar 10, 2016 at 6:41 AM, Ben Mezger <me@benmezger.nl> wrote:
> Hi all,
>
> I've been studying Object Oriented Theory using Java. Theoretically, all
> attributes should be private, meaning no one except the methods itself
> can access the attribute;
>
> public class Foo {
> private int bar;
> ...
Encapsulation in Python is based on trust rather than the
authoritarian style of C++ / Java. The maxim in the Python community
is that "we're all consenting adults". If I don't intend an attribute
to be messed with, then I'll mark it with a leading underscore. If you
mess with it anyway, and later your code breaks as a result of it,
that's your problem, not mine. :-)
> Normally in Java, we would write getters and setters to set/get the
> attribute bar. However, in Python, we normally create a class like so;
>
> class Foo(object):
> bar = 0
> ...
>
> And we usually don't write any getters/setters (though they exist in
> Python, I have not seen much projects making use of it).
The vast majority of getters and setters do nothing other than get/set
the field they belong to. They exist only to allow the *possibility*
of doing something else at some point far in the future. That's a ton
of undesirable boilerplate for little real benefit.
In Python, OO designers are able to get away with not using getters
and setters because we have properties. You can start with an
attribute, and if you later want to change the means of getting and
setting it, you just replace it with a property. The property lets you
add any logic you want, and as far as the outside world is concerned,
it still just looks like an attribute.
> We can easily encapsulate (data hiding) Foo's class using the '_'
> (underscore) when creating a new attribute, however, this would require
> all attributes to have a underscore.
A single leading underscore is just a naming convention, not true data
hiding, which isn't really possible in Python. Even the double
underscore only does name mangling, not true data hiding. It's meant
to prevent *accidental* naming collisions. You can still easily access
the attribute from outside the class if you're determined to.
This all boils down to the fact that code inside a method has no
special privilege over external code. If you could hide data so well
that external code really couldn't access it, then you wouldn't be
able to access it either.
[toc] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2016-03-10 16:45 -0800 |
| Message-ID | <6984dafc-fffd-4d46-a173-421bb5c142d2@googlegroups.com> |
| In reply to | #104528 |
On Thursday, March 10, 2016 at 9:28:06 AM UTC-6, Ian wrote:
> Encapsulation in Python is based on trust rather than the
> authoritarian style of C++ / Java. The maxim in the Python
> community is that "we're all consenting adults". If I
> don't intend an attribute to be messed with, then I'll
> mark it with a leading underscore. If you mess with it
> anyway, and later your code breaks as a result of it,
> that's your problem, not mine. :-)
It is a strange irony that you cannot escape the
encapsulating nature of Python modules (since they are
formed by Python from your source files), but Python freely
allows us to ignore encapsulation in our OOP paradigm...
Hmm, sure, many could argue that Python's "mandatory
modules" are simply a result of convenience, they will say:
"Since we have to write code in source files anyway, why not
utilize the "encapsulation of the source file itself to
define module scope?".
I have witnessed the mayhem that occurs when a language does
not mandate module encapsulation (Ruby, i'm looking directly
at you!!!!), and while i agree with the Python designers
that modules must *ALWAYS* be mandatory, i am not convinced
that module space should be so strictly confined to source
files.
Many times, i would have preferred to define my module space
across multiple files, multiple files that could share state
without resorting to the yoga-style "import contortions",
and/or the dreaded "circular import nightmares" that plague
our community today.
In one way, Python got it right by forcing us to encapsulate
our code into modules, however, it failed by not allowing us
to define both the breadth *AND* width of that encapsulation.
Which brings us up against the brutal reality that: Whilst
python's sycophants love to parrot-off about how we are all
"Adults", it's implementation still attempts to treat us
ignorant little children who are incapable of defining our
own module space.
> The vast majority of getters and setters do nothing other
> than get/set the field they belong to. They exist only to
> allow the *possibility* of doing something else at some
> point far in the future.
But you're ignoring the most important aspect of
getters/setters, and that is, that they expose an interface.
An interface that must be *EXPLICITLY* created. Good
interfaces *NEVER* happen by accident.
> That's a ton of undesirable boilerplate for little real
> benefit.
I understand the aversion to boilerplate, but most languages
have simplified the creation of getters/setters to the point
that your lament is unfounded. And i would argue that the
benefits of creating rigid interfaces is the gift that
keeps on giving.
> In Python, OO designers are able to get away with not
> using getters and setters because we have properties. You
> can start with an attribute, and if you later want to
> change the means of getting and setting it, you just
> replace it with a property. The property lets you add any
> logic you want, and as far as the outside world is
> concerned, it still just looks like an attribute.
I used properties quite often when i first began writing
Python code. Heck, i thought they were the best thing since
sliced bread. But now, i have come to hate them. I never use
them in any new code, and when i have free time, i strip
them out of old code. When i am forced to use an interface
that was written with properties, i find that learning the
interface is more difficult
(1) In a dir listing, one cannot determine which symbols
are properties, which are attributes, and which are
methods. The beauty of pure OOP encapsulation, is that,
*EVERY* exposed symbol is a method. In pure OOP, i don't
have to wonder if i'm calling a function with no
parameters, or accessing a property, or accessing an
attribute, no, i'll know that every access is through a
method, therefore, i will append "()" when i know the
method takes no arguments. Consistency is very important.
(2) Properties and attributes encourage vague naming
schemes. When i read code, i find the code more
comprehensible when the symbols give me clues as to what
is going on. So if i read code like: `re.groups`,
befuddlement sets in. What is "groups"? A function
object? An attribute? "getCapturingGroupCount" would be a
better name (but that's semantics) In pure OOP, methods
are the only communication meduim, so we're more likely to
write "getBlah" and "setBlah", and use verbs for
procedural names -- these naming conventions are more
comprehensible to the user.
(3) Not all authors correctly utilize leading underscores
to differentiate between public and private attributes.
> This all boils down to the fact that code inside a method
> has no special privilege over external code. If you could
> hide data so well that external code really couldn't
> access it, then you wouldn't be able to access it either.
That's a ridiculous statement Ian.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-03-11 08:47 -0700 |
| Message-ID | <mailman.25.1457711277.26429.python-list@python.org> |
| In reply to | #104568 |
On Thu, Mar 10, 2016 at 5:45 PM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > Many times, i would have preferred to define my module space > across multiple files, multiple files that could share state > without resorting to the yoga-style "import contortions", > and/or the dreaded "circular import nightmares" that plague > our community today. Sounds to me like you're blaming Python for your own poor design. Possible solutions: 1) Don't do that. If your module is too big for one file, then it's likely poorly organized and doesn't all belong in one module anyway. 2) Clearly define which module is to be imported first. Then follow it. When module b is imported, it should import module a. When module a is imported, it *shouldn't* import module b until it's defined all of its own members first. If module a depends on anything from module b at import time, then refactor so it doesn't. This doesn't require "contortions". 3) Just put all your damn shared state in a class. There's nothing stopping you from spreading out your class method definitions over multiple files if you really want to, and it solves your import issue by allowing everything to be imported before you even begin to set up the shared state. >> The vast majority of getters and setters do nothing other >> than get/set the field they belong to. They exist only to >> allow the *possibility* of doing something else at some >> point far in the future. > > But you're ignoring the most important aspect of > getters/setters, and that is, that they expose an interface. > An interface that must be *EXPLICITLY* created. Good > interfaces *NEVER* happen by accident. And you're suggesting that public attributes and properties do not expose an interface? Rubbish. >> That's a ton of undesirable boilerplate for little real >> benefit. > > I understand the aversion to boilerplate, but most languages > have simplified the creation of getters/setters to the point > that your lament is unfounded. And i would argue that the > benefits of creating rigid interfaces is the gift that > keeps on giving. I don't care how easy they are to *create*. Code is read much more often than it is written, and excessive boilerplate damages readability. >> In Python, OO designers are able to get away with not >> using getters and setters because we have properties. You >> can start with an attribute, and if you later want to >> change the means of getting and setting it, you just >> replace it with a property. The property lets you add any >> logic you want, and as far as the outside world is >> concerned, it still just looks like an attribute. > > I used properties quite often when i first began writing > Python code. Heck, i thought they were the best thing since > sliced bread. But now, i have come to hate them. I never use > them in any new code, and when i have free time, i strip > them out of old code. When i am forced to use an interface > that was written with properties, i find that learning the > interface is more difficult > > (1) In a dir listing, one cannot determine which symbols > are properties, which are attributes, and which are > methods. The beauty of pure OOP encapsulation, is that, > *EVERY* exposed symbol is a method. In pure OOP, i don't > have to wonder if i'm calling a function with no > parameters, or accessing a property, or accessing an > attribute, no, i'll know that every access is through a > method, therefore, i will append "()" when i know the > method takes no arguments. Consistency is very important. How do you know the method takes no arguments from a dir listing? If you think the method does take arguments, how do you find out what those are from a dir listing? If you want to do actual coding with a class, you're eventually going to have to read something other than the dir listing, whether everything is a method or not. > (2) Properties and attributes encourage vague naming > schemes. When i read code, i find the code more > comprehensible when the symbols give me clues as to what > is going on. So if i read code like: `re.groups`, > befuddlement sets in. What is "groups"? A function > object? An attribute? "getCapturingGroupCount" would be a > better name (but that's semantics) Actually, it would be wrong. Match.groups doesn't return a count. Also, it's a method, not an attribute or property, so as an example it sort of destroys your argument that using methods naturally results in giving the methods good, meaningful names. These are merely separate aspects of interface design. > In pure OOP, methods > are the only communication meduim, so we're more likely to > write "getBlah" and "setBlah", and use verbs for > procedural names -- these naming conventions are more > comprehensible to the user. Good names for methods are *descriptive* verb phrases. Good names for attributes and properties are *descriptive* nouns or noun phrases. Do you really believe that verbs are somehow inherently easier to understand? > (3) Not all authors correctly utilize leading underscores > to differentiate between public and private attributes. > >> This all boils down to the fact that code inside a method >> has no special privilege over external code. If you could >> hide data so well that external code really couldn't >> access it, then you wouldn't be able to access it either. > > That's a ridiculous statement Ian. I invite you to demonstrate a counter-example. Show me where a Python method can hide data such that code external to the class can't find it.
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2016-03-11 18:39 -0800 |
| Message-ID | <4ddc3696-3f71-4598-98a6-929267f51fb9@googlegroups.com> |
| In reply to | #104622 |
On Friday, March 11, 2016 at 9:48:22 AM UTC-6, Ian wrote:
> On Thu, Mar 10, 2016 at 5:45 PM, Rick Johnson
> The honorable Rick Johnson wrote:
> > Many times, i would have preferred to define my module space
> > across multiple files, multiple files that could share state
> > without resorting to the yoga-style "import contortions",
> > and/or the dreaded "circular import nightmares" that plague
> > our community today.
>
> Sounds to me like you're blaming Python for your own poor design.
> Possible solutions:
>
> 1) Don't do that. If your module is too big for one file, then it's
> likely poorly organized and doesn't all belong in one module anyway.
Apparently you've missed the many heated arguments between
Chris Angelico and myself concerning the size of source
files. I have *ALWAYS* taken the position that source files
should be kept as small as possible, but that position is
more relevant in Python, were modules are defined by a
single source file. I don't take the Java position that a
module can only contain one class, but i like to keep the
number of classes (IN MY SOURCE FILES) small.
At run-time, i don't care how large a "module namespace" may
be. Sometimes a module namespace will be small, with only a
few exposed symbols, but sometimes, a module namespace will
expose thousands of symbols. The size of a "run-time module"
is irrelevant in most languages, but here in Python, were
module namespace is defined by the contents of *ONE SINGLE
SOURCE FILE*, the whole ballgame is changed. If i need to
create a module that contains many exposed symbols in
Python, i'm forced to do one of the following:
(1) Write all my code in a single *GIGANTIC* file...
or
(2) Create one file that will be the "mother-ship module",
and N files that will be the "satellite modules", and from
inside the mother-ship, import all the symbols from all
the satellites. Ha, but in reality, it's not that simple,
because state does not "magically" travel between modules!
##########
# foo.py #
##########
FOO_SHARED_STATE = "foo"
import _fooSatilite1
_fooSatilite1.FOO_SHARED_STATE = FOO_SHARED_STATE
from _fooSatilite1 import *
import _fooSatilite2
_fooSatilite2.FOO_SHARED_STATE = FOO_SHARED_STATE
from _fooSatilite2 import *
print 'This is the mother-ship called foo'
...
####################
# _fooSatilite1.py #
####################
from _fooConstants import *
print 'This is foo-fighter1, reporting for duty'
print FOO_SHARED_STATE
...
####################
# _fooSatilite2.py #
####################
from _fooConstants import *
print 'This is foo-fighter2, reporting for duty'
print FOO_SHARED_STATE
...
But i find both to be absurd. Writing all code in a single
file might be fine for a toy module that contains a handful
of functions or classes or vars, but once we start creating
anything in the "professional size range", it will become
an "editing nightmare" of epic proportions!
But option two is no better, because once we cut and paste
portions of the code into satellite files, we lose the
ability to "easily share state". Then we're forced to start
"hacking at the weeds" with import contortions and monkey
patches, all the while, fearing the dreaded circular import.
NO, THIS IS INSANITY! WHAT WE NEED IS AN OPTION 3!
(3) Allow a programmer to define module space at will
##########
# foo.py #
##########
module foo
FOO_SHARED_STATE = "foo"
print 'This is the mother-ship called foo'
...
####################
# _fooSatilite1.py #
####################
module foo
print 'This is foo-fighter1, reporting for duty'
print FOO_SHARED_STATE # NO MP REQUIRED!
...
####################
# _fooSatilite2.py #
####################
module foo
print 'This is foo-fighter2, reporting for duty'
print FOO_SHARED_STATE # NO MP REQUIRED!
...
No need for import contortions, no need for monkey patching,
but most importantly, no need for professional programmers
to feel as though they are penchant little children, who
need their "module diapers" wrapped for them by mommy
Python, who, after popping one too many "mother's little
helpers", has a nasty habit of wrapping our diapers too damn
tight -- what a drag, it is, getting old...
> 2) Clearly define which module is to be imported first. Then follow
> it. When module b is imported, it should import module a. When module
> a is imported, it *shouldn't* import module b until it's defined all
> of its own members first. If module a depends on anything from module
> b at import time, then refactor so it doesn't. This doesn't require
> "contortions".
That sounds simple in theory, but it breaks down quickly
when you create "professional sized programs"
> 3) Just put all your damn shared state in a class. There's nothing
> stopping you from spreading out your class method definitions over
> multiple files if you really want to, and it solves your import issue
> by allowing everything to be imported before you even begin to set up
> the shared state.
Your words tell me that you have not written anything substantial.
> And you're suggesting that public attributes and properties do not
> expose an interface? Rubbish.
No, what i'm suggesting, is that, from the POV of a dir
listing, they *ALL* look the same.
> I don't care how easy they are to *create*. Code is read much more
> often than it is written, and excessive boilerplate damages
> readability.
I understand the importance of readability, but is usability
of no concern to you? In fact, i would argue that, when
*ROCK SOLID* professional interfaces are combined with
proper documentation and strict adherence to style guides,
there is no need to read source code.
The only person who should be reading source, is a
maintenance programmer. And if the code was designed
properly, his job would be mostly just adding a feature here
or there, or repairing a small bug here or there -- any code
monkey can do that!
> > (2) Properties and attributes encourage vague naming
> > schemes. When i read code, i find the code more
> > comprehensible when the symbols give me clues as to what
> > is going on. So if i read code like: `re.groups`,
> > befuddlement sets in. What is "groups"? A function
> > object? An attribute? "getCapturingGroupCount" would be a
> > better name (but that's semantics)
>
> Actually, it would be wrong. Match.groups doesn't return a count.
Who said anything about match objects?
############################################################
# BEGIN INTERACTIVE SESSION
############################################################
py> import re
py> prog = re.compile(r'(Ian) (\w+)')
py> prog?
['findall', 'finditer', 'flags', 'groupindex', 'groups', 'match', 'pattern', 'scanner', 'search', 'split', 'sub', 'subn']
py> prog.groups
2
py> prog.groups?type
<type 'int'>
############################################################
# END INTERACTIVE SESSION
############################################################
Looks like an integer to me. (Well, i'll admit, first you'll
have to parse my mini-language syntax, but it's highly
intuitive -- more than a Python dir listing, i'll tell you
that much!)
> > In pure OOP, methods
> > are the only communication meduim, so we're more likely to
> > write "getBlah" and "setBlah", and use verbs for
> > procedural names -- these naming conventions are more
> > comprehensible to the user.
>
> Good names for methods are *descriptive* verb phrases. Good names for
> attributes and properties are *descriptive* nouns or noun phrases. Do
> you really believe that verbs are somehow inherently easier to
> understand?
When i see "get_width" or "set_width", i know that the first is
returning the width, and the second will set the width. And
anyone with an IQ over room temperature, can surmise that
set_width takes at least one argument.
However, when i see "width", how the hell am i supposed to
know if it is a read-only attribute, a property, or a method?
Must i read source code just to find this out? Sure, if the
author included a useful doc string, i could pull it up, but
to me, this is a giant waste of time. Self documenting names
are the *KEY* to short learning curves.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-03-12 09:44 -0700 |
| Message-ID | <mailman.42.1457801128.12893.python-list@python.org> |
| In reply to | #104667 |
On Fri, Mar 11, 2016 at 7:39 PM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > At run-time, i don't care how large a "module namespace" may > be. Sometimes a module namespace will be small, with only a > few exposed symbols, but sometimes, a module namespace will > expose thousands of symbols. Thousands, really? What system do you use to ensure that symbols don't accidentally collide with one another? Because, you know, Python won't check this for you even within a single file, unlike say C++ which does allow splitting namespaces across multiple files. A linter might, but not at runtime, and I don't expect it will be smart enough to notice if the definitions are in different files. > (2) Create one file that will be the "mother-ship module", > and N files that will be the "satellite modules", and from > inside the mother-ship, import all the symbols from all > the satellites. Ha, but in reality, it's not that simple, > because state does not "magically" travel between modules! > > ########## > # foo.py # > ########## > FOO_SHARED_STATE = "foo" > import _fooSatilite1 > _fooSatilite1.FOO_SHARED_STATE = FOO_SHARED_STATE > from _fooSatilite1 import * > import _fooSatilite2 > _fooSatilite2.FOO_SHARED_STATE = FOO_SHARED_STATE > from _fooSatilite2 import * > print 'This is the mother-ship called foo' > ... > > #################### > # _fooSatilite1.py # > #################### > from _fooConstants import * > print 'This is foo-fighter1, reporting for duty' > print FOO_SHARED_STATE > ... > > #################### > # _fooSatilite2.py # > #################### > from _fooConstants import * > print 'This is foo-fighter2, reporting for duty' > print FOO_SHARED_STATE > ... > > But i find both to be absurd. Writing all code in a single > file might be fine for a toy module that contains a handful > of functions or classes or vars, but once we start creating > anything in the "professional size range", it will become > an "editing nightmare" of epic proportions! > > But option two is no better, because once we cut and paste > portions of the code into satellite files, we lose the > ability to "easily share state". Then we're forced to start > "hacking at the weeds" with import contortions and monkey > patches, all the while, fearing the dreaded circular import. > > > NO, THIS IS INSANITY! WHAT WE NEED IS AN OPTION 3! > > (3) Allow a programmer to define module space at will > > ########## > # foo.py # > ########## > module foo > FOO_SHARED_STATE = "foo" > print 'This is the mother-ship called foo' > ... > > #################### > # _fooSatilite1.py # > #################### > module foo > print 'This is foo-fighter1, reporting for duty' > print FOO_SHARED_STATE # NO MP REQUIRED! > ... > > #################### > # _fooSatilite2.py # > #################### > module foo > print 'This is foo-fighter2, reporting for duty' > print FOO_SHARED_STATE # NO MP REQUIRED! > ... Is this meant to be equivalent to the other example? In that example, you have the two "satellite" modules being imported between the definition of FOO_SHARED_STATE and the print. In this example, how on Earth is Python supposed to know that after the FOO_SHARED_STATE line it's supposed to switch to executing these other two files before continuing on to the next statement? More generally, what order do you expect these files to be executed in when the "module" is imported? There must be some defined order, because Python isn't magically capable of executing all three of them simultaneously. If there's a defined order, then you should be able to easily add explicit import statements at the tops of modules that declare that order. So this is exactly the same as your "import contortions" except that you want to make the reader (and the Python interpreter) have to guess at the dependencies instead of making them explicit. > No need for import contortions, no need for monkey patching, > but most importantly, no need for professional programmers > to feel as though they are penchant little children, who > need their "module diapers" wrapped for them by mommy > Python, who, after popping one too many "mother's little > helpers", has a nasty habit of wrapping our diapers too damn > tight -- what a drag, it is, getting old... > >> 2) Clearly define which module is to be imported first. Then follow >> it. When module b is imported, it should import module a. When module >> a is imported, it *shouldn't* import module b until it's defined all >> of its own members first. If module a depends on anything from module >> b at import time, then refactor so it doesn't. This doesn't require >> "contortions". > > That sounds simple in theory, but it breaks down quickly > when you create "professional sized programs" I find in interesting that you seem to be equating "very large" with "professional". In my view, it's exactly the opposite. Anything very large and so unorganized looks rather sloppy and unprofessional. >> 3) Just put all your damn shared state in a class. There's nothing >> stopping you from spreading out your class method definitions over >> multiple files if you really want to, and it solves your import issue >> by allowing everything to be imported before you even begin to set up >> the shared state. > > Your words tell me that you have not written anything substantial. I'll take your lack of substantive reply to mean "Huh, I never thought of this approach that both solves my problem and improves the structure of my code at the same time. Better hurl an insult to save face!" Compliment accepted. > I understand the importance of readability, but is usability > of no concern to you? In fact, i would argue that, when > *ROCK SOLID* professional interfaces are combined with > proper documentation and strict adherence to style guides, > there is no need to read source code. > > The only person who should be reading source, is a > maintenance programmer. And if the code was designed > properly, his job would be mostly just adding a feature here > or there, or repairing a small bug here or there -- any code > monkey can do that! Yeah, you're so right. Professional software is write-once, run-forever. Software requirements never change, and original designs never have unforeseen consequences. "Maintenance" programmers exist as some lower breed of programmer who are barely unable to understand how loops work, much less invent thousands of distinct symbols to cram into a single module so that they too can be considered professional programmers. </sarcasm>
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2016-03-12 19:11 -0800 |
| Message-ID | <b2c7971d-40ab-4636-bb3e-d7711888663a@googlegroups.com> |
| In reply to | #104714 |
On Saturday, March 12, 2016 at 10:45:43 AM UTC-6, Ian wrote:
> On Fri, Mar 11, 2016 at 7:39 PM, Rick Johnson
> <rantingrickjohnson@gmail.com> wrote:
> > At run-time, i don't care how large a "module namespace" may
> > be. Sometimes a module namespace will be small, with only a
> > few exposed symbols, but sometimes, a module namespace will
> > expose thousands of symbols.
>
> Thousands, really? What system do you use to ensure that symbols don't
> accidentally collide with one another?
I use words, mostly.
> > [SNIP: Two Examples From Rick]
>
> Is this meant to be equivalent to the other example? In that example,
> you have the two "satellite" modules being imported between the
> definition of FOO_SHARED_STATE and the print. In this example, how on
> Earth is Python supposed to know that after the FOO_SHARED_STATE line
> it's supposed to switch to executing these other two files before
> continuing on to the next statement?
The examples i provided are too simplistic to convey such
details, because they were never meant to convey such
details. Of *COURSE* you'll encounter issues in *real code*
if you don't organize it's execution correctly. Spreading
the contents of a module across multiple source files does
not prevent NameErrors from raising, and it shouldn't. Heck,
you can easily break a python module today, by referencing
a symbol too early:
##############
# example.py #
##############
bar = Bar()
class Bar(object):
pass
> > That sounds simple in theory, but it breaks down quickly
> > when you create "professional sized programs"
>
> I find in interesting that you seem to be equating "very large" with
> "professional". In my view, it's exactly the opposite. Anything very
> large and so unorganized looks rather sloppy and unprofessional.
I find it interesting that you seem to be equating "very
large" with "sloppy". Not all large software's are sloppy,
and not all small software's are neat. Dealing in absolutes
is never a good idea.
> >> 3) Just put all your damn shared state in a class. There's nothing
> >> stopping you from spreading out your class method definitions over
> >> multiple files if you really want to, and it solves your import issue
> >> by allowing everything to be imported before you even begin to set up
> >> the shared state.
> >
> > Your words tell me that you have not written anything substantial.
>
> I'll take your lack of substantive reply to mean "Huh, I never thought
> of this approach that both solves my problem and improves the
> structure of my code at the same time. Better hurl an insult to save
> face!" Compliment accepted.
Why must I invoke the awesome "instancing power" of a
SharedStateObject, when a singleton would be a more
appropriate design? But even a singleton would be a nasty
hack for: sharing state across a "module space" that is
defined in multiple source files.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2016-03-13 21:11 +1100 |
| Message-ID | <56e53cd3$0$1586$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #104714 |
On Sun, 13 Mar 2016 03:44 am, Ian Kelly wrote:
> On Fri, Mar 11, 2016 at 7:39 PM, Rick Johnson
> <rantingrickjohnson@gmail.com> wrote:
>> At run-time, i don't care how large a "module namespace" may
>> be. Sometimes a module namespace will be small, with only a
>> few exposed symbols, but sometimes, a module namespace will
>> expose thousands of symbols.
>
> Thousands, really? What system do you use to ensure that symbols don't
> accidentally collide with one another? Because, you know, Python won't
> check this for you even within a single file, unlike say C++ which
> does allow splitting namespaces across multiple files. A linter might,
> but not at runtime, and I don't expect it will be smart enough to
> notice if the definitions are in different files.
I would hate to use an API with "thousands" of symbols in a single
namespace. I find `os` difficult enough, and it has less than a quarter
thousand:
py> len(dir(os))
224
The decimal module is, in my opinion, about as big as a module should ever
get before it becomes too unwieldy to maintain, and it has less than a
hundred symbols:
py> len(dir(decimal))
79
While it is true that the Zen says "Flat is better than nested", it does
also say
Namespaces are one honking great idea -- let's do more of those!
so at the point that your namespace has more symbols than can be managed by
the merely mortal, then it's well past time to split some of them off into
separate namespaces.
[...]
>> But option two is no better, because once we cut and paste
>> portions of the code into satellite files, we lose the
>> ability to "easily share state". Then we're forced to start
>> "hacking at the weeds" with import contortions and monkey
>> patches, all the while, fearing the dreaded circular import.
>>
>>
>> NO, THIS IS INSANITY! WHAT WE NEED IS AN OPTION 3!
What we actually need is a way to have less shared state. If you have so
much shared state that you cannot manage it in a single module, you have a
problem no matter what you do.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2016-03-14 10:32 -0700 |
| Message-ID | <1376c684-2e7f-417a-9683-e47789f019fe@googlegroups.com> |
| In reply to | #104753 |
On Sunday, March 13, 2016 at 5:11:50 AM UTC-5, Steven D'Aprano wrote: > On Sun, 13 Mar 2016 03:44 am, Ian Kelly wrote: > > > On Fri, Mar 11, 2016 at 7:39 PM, Rick Johnson > > <rantingrickjohnson@gmail.com> wrote: > >> At run-time, i don't care how large a "module namespace" may be. > >> Sometimes a module namespace will be small, with only a few > >> exposed symbols, but sometimes, a module namespace will expose > >> thousands of symbols. > > > > Thousands, really? What system do you use to ensure that symbols > > don't accidentally collide with one another? Because, you know, > > Python won't check this for you even within a single file, unlike > > say C++ which does allow splitting namespaces across multiple > > files. A linter might, but not at runtime, and I don't expect it > > will be smart enough to notice if the definitions are in different > > files. > > I would hate to use an API with "thousands" of symbols in a single > namespace. I find `os` difficult enough, and it has less than a > quarter thousand: > > The decimal module is, in my opinion, about as big as a module > should ever get before it becomes too unwieldy to maintain, and it > has less than a hundred symbols: > > While it is true that the Zen says "Flat is better than nested", it > does also say Namespaces are one honking great idea -- let's do more > of those! so at the point that your namespace has more symbols than > can be managed by the merely mortal, then it's well past time to > split some of them off into separate namespaces. But exactly where, and exactly how to drawn those lines, is not always obvious. Splitting a large module, of similar functionality, into smaller modules, can make the interface confusing. Consider the following "large sized modules". # BEGIN INTERACTIVE SESSION PY> import OpenGL.GL PY> import OpenGL.GLU PY> import OpenGL.GLX PY> import OpenGL.GLUT PY> import OpenGL.GLE PY> len(dir(OpenGL.GL)) 3656 PY> len(dir(OpenGL.GLU)) 250 PY> len(dir(OpenGL.GLX)) 390 PY> len(dir(OpenGL.GLUT)) 394 PY> len(dir(OpenGL.GLE)) 64 PY> import Tkinter as tk PY> len(dir(tk)) 199 PY> root = tk.Tk() PY> f = tk.Frame(root) PY> len(dir(f)) 200 # END INTERACTIVE SESSION Ignoring Tkinter, which is a gawd awful mess, how would you re-organize the 3,656 symbols in OpenGL.GL into smaller modules, without dividing them up along some random or arbitrary lines? > [...] > >> But option two is no better, because once we cut and paste > >> portions of the code into satellite files, we lose the ability to > >> "easily share state". Then we're forced to start "hacking at the > >> weeds" with import contortions and monkey patches, all the while, > >> fearing the dreaded circular import. NO, THIS IS INSANITY! WHAT > >> WE NEED IS AN OPTION 3! > > What we actually need is a way to have less shared state. If you > have so much shared state that you cannot manage it in a single > module, you have a problem no matter what you do. You're missing my point. I can manage the *STATE* just fine in a single module, actually, managing *STATE* in the same module is very easy, regardless of how many lines are in the file. No, it is not state that becomes unwieldy, it is *EDITING* that becomes unwieldy. I break large source files into small source files, simply so i don't go insane when trying to edit them.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2016-03-14 15:09 -0600 |
| Message-ID | <mailman.130.1457989824.12893.python-list@python.org> |
| In reply to | #104847 |
On Mon, Mar 14, 2016 at 11:32 AM, Rick Johnson <rantingrickjohnson@gmail.com> wrote: > Ignoring Tkinter, which is a gawd awful mess, how would you > re-organize the 3,656 symbols in OpenGL.GL into smaller > modules, without dividing them up along some random or > arbitrary lines? In that particular case, I wouldn't, except possibly as an implementation detail with the main OpenGL package importing the contents of all its sub-packages into itself (and I think that if you look at the PyOpenGL source you'll find that it's doing something similar). It's following a well-documented API that is separate from its Python wrapper. It's unfortunate that the only namespacing considered in the design of that API was "everything starts with the prefix gl", but that's what we're stuck with. Moving things around would just confuse users who can't then find them where they expect.
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2016-03-14 21:23 +0000 |
| Message-ID | <mailman.132.1457990663.12893.python-list@python.org> |
| In reply to | #104847 |
On 14/03/2016 21:09, Ian Kelly wrote: > On Mon, Mar 14, 2016 at 11:32 AM, Rick Johnson > <rantingrickjohnson@gmail.com> wrote: >> Ignoring Tkinter, which is a gawd awful mess, how would you >> re-organize the 3,656 symbols in OpenGL.GL into smaller >> modules, without dividing them up along some random or >> arbitrary lines? > > In that particular case, I wouldn't, except possibly as an > implementation detail with the main OpenGL package importing the > contents of all its sub-packages into itself (and I think that if you > look at the PyOpenGL source you'll find that it's doing something > similar). It's following a well-documented API that is separate from > its Python wrapper. It's unfortunate that the only namespacing > considered in the design of that API was "everything starts with the > prefix gl", but that's what we're stuck with. Moving things around > would just confuse users who can't then find them where they expect. > If it was reorganised rr would claim that it had split the community in the same way that the disastrous migration from Python 2 to 3 has done. The minor snag to his argument is that I'm not aware of any such split. Python 2.8, RickedPython, and the latest entry into the race, BartCPython, all vapourware. At least rr knows something about tkinter/IDLE, whereas the latter appears to know squat about anything. You can fool all of the programmers, all of the time? -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-03-14 22:07 +0000 |
| Message-ID | <nc7chi$lbu$1@dont-email.me> |
| In reply to | #104865 |
On 14/03/2016 21:23, Mark Lawrence wrote: > Python 2.8, RickedPython, and the latest entry into the race, > BartCPython, all vapourware. I'm not creating a new version of Python or CPython (you should have used an underscore). But I do have considerable experience of creating dynamically-typed languages and writing byte-code interpreters for them. They are not vapourware. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2016-03-14 22:20 +0000 |
| Message-ID | <mailman.133.1457994074.12893.python-list@python.org> |
| In reply to | #104866 |
On 14/03/2016 22:07, BartC wrote: > On 14/03/2016 21:23, Mark Lawrence wrote: > >> Python 2.8, RickedPython, and the latest entry into the race, >> BartCPython, all vapourware. > > I'm not creating a new version of Python or CPython (you should have > used an underscore). > > But I do have considerable experience of creating dynamically-typed > languages and writing byte-code interpreters for them. They are not > vapourware. > Really? So why do you keep arguing, most notably with Steven D'Aprano, about the benefits of dynamic typing, whereby you appear to be completely against it? The RUE kept stating that he was an expert in unicode, but never once provided a single shred of evidence to support his claim. Until I see substantiated evidence from you I am going to state quite cleary that you've no idea, you're just another RUE. Your dreadful piece of code published earlier today around a switch statement summed it up. When are you running the profile that I asked for? -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-03-14 22:40 +0000 |
| Message-ID | <nc7ef9$sgf$1@dont-email.me> |
| In reply to | #104868 |
On 14/03/2016 22:20, Mark Lawrence wrote: > On 14/03/2016 22:07, BartC wrote: >> On 14/03/2016 21:23, Mark Lawrence wrote: >> >>> Python 2.8, RickedPython, and the latest entry into the race, >>> BartCPython, all vapourware. >> >> I'm not creating a new version of Python or CPython (you should have >> used an underscore). >> >> But I do have considerable experience of creating dynamically-typed >> languages and writing byte-code interpreters for them. They are not >> vapourware. >> > > Really? So why do you keep arguing, most notably with Steven D'Aprano, > about the benefits of dynamic typing, whereby you appear to be > completely against it? I'm not against dynamic typing. I'm against mutable, dynamic names, among other dynamic features that are well known to make Python hard to optimise, and which for me appear to give little added value. Your dreadful piece of code > published earlier today around a switch statement summed it up. Was that in Python? It was /supposed/ to be dreadful. I was making a case for it to be supported directly. > The RUE kept stating that he was an expert in unicode, but never once > provided a single shred of evidence to support his claim. Until I see > substantiated evidence from you I am going to state quite cleary that > you've no idea, you're just another RUE. Sorry, I'm not going to do that, and I don't expect anyone here to have to do so either. You will have to take my posts as they are. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2016-03-14 23:19 +0000 |
| Message-ID | <mailman.137.1457997645.12893.python-list@python.org> |
| In reply to | #104871 |
On 14/03/2016 22:40, BartC wrote: > On 14/03/2016 22:20, Mark Lawrence wrote: >> On 14/03/2016 22:07, BartC wrote: >>> On 14/03/2016 21:23, Mark Lawrence wrote: >>> >>>> Python 2.8, RickedPython, and the latest entry into the race, >>>> BartCPython, all vapourware. >>> >>> I'm not creating a new version of Python or CPython (you should have >>> used an underscore). >>> >>> But I do have considerable experience of creating dynamically-typed >>> languages and writing byte-code interpreters for them. They are not >>> vapourware. >>> >> >> Really? So why do you keep arguing, most notably with Steven D'Aprano, >> about the benefits of dynamic typing, whereby you appear to be >> completely against it? > > I'm not against dynamic typing. > > I'm against mutable, dynamic names, among other dynamic features that > are well known to make Python hard to optimise, and which for me appear > to give little added value. There is no need to optimise python, it is fast enough. For me every advantage of Python is that I can do what I like with it, when I like with it, and I'm not stuck in the dreadful straight jacket of the statically typed languages. If someone wants to make it faster I'm not going to complain, but your obsession with speed is going to have me dying of laughter if this goes on much longer. > > Your dreadful piece of code >> published earlier today around a switch statement summed it up. > > Was that in Python? It was /supposed/ to be dreadful. I was making a > case for it to be supported directly. You mean the huge great long list of hard coded function calls. They are directly supported. So is the loop. Anything wrong with the Paul Rubin response? And as my earlier link showed you often simply don't need a switch statement in an OO language. Not much point providing something, much worse optimising it, if it isn't needed in the first place? > > > The RUE kept stating that he was an expert in unicode, but never once > > provided a single shred of evidence to support his claim. Until I see > > substantiated evidence from you I am going to state quite cleary that > > you've no idea, you're just another RUE. > > Sorry, I'm not going to do that, and I don't expect anyone here to have > to do so either. You will have to take my posts as they are. > Drivel. Any establised member of this community, or any other community for that matter, will always publish, unless, like the RUE, they've got something to hide. So you're just a chicken. Where do you buy the paint from for the streaks down your back? Just in case you can't guess it is yellow. I'll state the colour just in case your knowledge of colours is the same as your so called knowledge of computing, something of which I'm far from persuaded, on the grounds that speed simply is not the sole criteria for a language. -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-03-14 23:56 +0000 |
| Message-ID | <nc7it9$ejq$1@dont-email.me> |
| In reply to | #104875 |
On 14/03/2016 23:19, Mark Lawrence wrote:
> On 14/03/2016 22:40, BartC wrote:
>> Was that in Python? It was /supposed/ to be dreadful. I was making a
>> case for it to be supported directly.
>
> You mean the huge great long list of hard coded function calls. They
> are directly supported. So is the loop. Anything wrong with the Paul
> Rubin response?
I tried it. It wasn't bad, but still 1/3 the speed of an if-elif chain
with discrete range-checking.
> And as my earlier link showed you often simply don't
> need a switch statement in an OO language. Not much point providing
> something, much worse optimising it, if it isn't needed in the first place?
I disagree. And presumably so do others as there are so many different
attempts to implement switch, with varying degrees of success. Here's
how I do it outside Python:
switch c
when 'A'..'Z','a'..'z','_' then
++name
when '0'..'9' then
++numeric
when "()[]<>{}" then
++brackets
else
++other
end
Anything so terrible about that that Python needs to keep well clear of
or that you think its users should be deprived of?
>> Sorry, I'm not going to do that, and I don't expect anyone here to have
>> to do so either. You will have to take my posts as they are.
>>
>
> Drivel. Any establised member of this community, or any other community
> for that matter, will always publish, unless, like the RUE, they've got
> something to hide. So you're just a chicken. Where do you buy the
> paint from for the streaks down your back?
OK, we've got another Rod Speed! He also gets a kick out of being rude
and insulting to everyone.
> on the grounds that speed simply is not
> the sole criteria for a language.
I agree with you. But once you've got the language right, then there's
no harm looking at performance. A switch statement like the above can be
executed in a single byte-code.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-03-15 11:12 +1100 |
| Message-ID | <mailman.138.1458000749.12893.python-list@python.org> |
| In reply to | #104877 |
On Tue, Mar 15, 2016 at 10:56 AM, BartC <bc@freeuk.com> wrote:
> I disagree. And presumably so do others as there are so many different
> attempts to implement switch, with varying degrees of success. Here's how I
> do it outside Python:
>
> switch c
> when 'A'..'Z','a'..'z','_' then
> ++name
> when '0'..'9' then
> ++numeric
> when "()[]<>{}" then
> ++brackets
> else
> ++other
> end
>
> Anything so terrible about that that Python needs to keep well clear of or
> that you think its users should be deprived of?
Yes: the complete lack of colons at the ends of lines that introduce
suites. This is utterly unacceptable in Python!
Seriously though - the one thing that I'm very concerned about here is
your brackets one. In Python, there's no reason to restrict 'switch'
to integers, so I would expect its semantics to be based on either
equality comparisons or inequality comparisons (possibly with a
requirement that all values be hashable); you could have something
like "when in <string>" but a simple "when <string>" would look to me
like it's testing for that entire string. (Don't forget that, in
Python, there's no difference between 'single quoted strings' and
"double quoted strings", as there is in C-like languages.)
Although... come to think of it, you could actually define it the
other way around: the 'when' statement checks if the current switch
object is contained within any of its arguments. Coupled with a
range-like object with its own literal syntax, that would pretty much
give you what you're looking at there. However, you'd need to have an
awkward notation for the cases where you _are_ looking for equality:
switch c:
when 'A'..'Z', 'a'..'z', ['_']:
++name
Or, in a long tree:
switch c:
when [1]:
...
when [2]:
...
when [3]:
...
Which could work. It'd be well-defined, and not unreasonable. It
would, however, be entirely predicated on a "comparison range" object
with a literal syntax:
class Range:
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __contains__(self, obj):
return self.start <= obj <= self.stop
def __repr__(self):
return "%r..%r" % (self.start, self.stop)
But that's not overly hard either.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-03-15 00:54 +0000 |
| Message-ID | <nc7man$obt$1@dont-email.me> |
| In reply to | #104879 |
On 15/03/2016 00:12, Chris Angelico wrote:
> On Tue, Mar 15, 2016 at 10:56 AM, BartC <bc@freeuk.com> wrote:
>> switch c
>> when 'A'..'Z','a'..'z','_' then
>> ++name
>> Anything so terrible about that that Python needs to keep well clear of or
>> that you think its users should be deprived of?
>
> Yes: the complete lack of colons at the ends of lines that introduce
> suites. This is utterly unacceptable in Python!
>
> Seriously though - the one thing that I'm very concerned about here is
> your brackets one.
Yeah, I'm not sure about that either. I'd already written:
when '(', ')', ....
when I thought having a string constant here would be neat, and
implemented that just before posting.
> In Python, there's no reason to restrict 'switch'
> to integers, so I would expect its semantics to be based on either
> equality comparisons or inequality comparisons
I use two forms of switch: one for integers only (very fast), and the
other for any other values, which does tests in sequence.
> (possibly with a
> requirement that all values be hashable); you could have something
> like "when in <string>" but a simple "when <string>" would look to me
> like it's testing for that entire string. (Don't forget that, in
> Python, there's no difference between 'single quoted strings' and
> "double quoted strings", as there is in C-like languages.)
>
> Although... come to think of it, you could actually define it the
> other way around: the 'when' statement checks if the current switch
> object is contained within any of its arguments. Coupled with a
> range-like object with its own literal syntax, that would pretty much
> give you what you're looking at there. However, you'd need to have an
> awkward notation for the cases where you _are_ looking for equality:
>
> switch c:
> when 'A'..'Z', 'a'..'z', ['_']:
> ++name
>
> Or, in a long tree:
>
> switch c:
> when [1]:
> ...
> when [2]:
> ...
> when [3]:
> ...
>
> Which could work. It'd be well-defined, and not unreasonable. It
> would, however, be entirely predicated on a "comparison range" object
> with a literal syntax:
>
> class Range:
> def __init__(self, start, stop):
> self.start = start
> self.stop = stop
> def __contains__(self, obj):
> return self.start <= obj <= self.stop
> def __repr__(self):
> return "%r..%r" % (self.start, self.stop)
>
> But that's not overly hard either.
The tests I do for the more general switch are either equality, or 'in'
for certain combinations of types (mainly testing integers for
membership of ranges and sets. Sets are Pascal-style bit-sets).
I've also looked at the problem of when the choice might be ambiguous:
case x # general 'switch'
when y then
...
What happens when y is a list; should it do x==y or x in y? (Or both?)
I haven't solved that yet but it's never come up. When x is anything
other than an int, you invariably want an equality test.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-03-15 11:58 +1100 |
| Message-ID | <mailman.147.1458003523.12893.python-list@python.org> |
| In reply to | #104889 |
On Tue, Mar 15, 2016 at 11:54 AM, BartC <bc@freeuk.com> wrote: >> In Python, there's no reason to restrict 'switch' >> to integers, so I would expect its semantics to be based on either >> equality comparisons or inequality comparisons > > > I use two forms of switch: one for integers only (very fast), and the other > for any other values, which does tests in sequence. I'm not sure what you gain by restricting to integers that you couldn't also gain with other hashable types. Can you elaborate on these optimizations? ChrisA
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-03-15 01:22 +0000 |
| Message-ID | <nc7nuv$sgd$1@dont-email.me> |
| In reply to | #104892 |
On 15/03/2016 00:58, Chris Angelico wrote: > On Tue, Mar 15, 2016 at 11:54 AM, BartC <bc@freeuk.com> wrote: >>> In Python, there's no reason to restrict 'switch' >>> to integers, so I would expect its semantics to be based on either >>> equality comparisons or inequality comparisons >> >> >> I use two forms of switch: one for integers only (very fast), and the other >> for any other values, which does tests in sequence. > > I'm not sure what you gain by restricting to integers that you > couldn't also gain with other hashable types. Can you elaborate on > these optimizations? The integer-switch is intended for use with jump-tables, which requires not only that the case expressions are known at compile-time, but that they don't span too large a range. (When a jump-table couldn't be used, then there was a slightly different implementation which scanned a list of the case-expressions. Linearly; a binary search or hash look-up could be done too, but this was in fast static code, not interpreted, so was not too critical. But I don't use this any more anyway.) For use with Python, because constant expressions are going to be limited, such a switch would only work with case expressions that are numeric literals or character constants, which have to be written b"A"[0] iirc. So rather limited unless someone introduces named constants at the same time... -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2016-03-15 13:02 +1100 |
| Message-ID | <mailman.149.1458007386.12893.python-list@python.org> |
| In reply to | #104896 |
On Tue, Mar 15, 2016 at 12:22 PM, BartC <bc@freeuk.com> wrote: > The integer-switch is intended for use with jump-tables, which requires not > only that the case expressions are known at compile-time, but that they > don't span too large a range. > Okay, which is what I mean by "compact". There'd be some lowest value and some highest value, and the table has that many entries in it, regardless of how many of them actually have meaningful information in them. With a hashtable, the values can be sparse. They would, however, still need to be constant; otherwise it'd be hard to build the table in advance. ChrisA
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | comp.lang.python
csiph-web