Re: How can a function find the function that called it?

2010-12-24 Thread Mark Wooding
kj no.em...@please.post writes:

 But OrderedDict's functionality *requires* that its __init__ be
 run, and this __init__, in turn, does part of its initialization
 by calling the update method.

 Therefore, the update method of the new subclass needs to be able
 to identify the calling function in order to make a special allowance
 for calls coming from OrderedDict.__init__

That doesn't follow at all.  Why not set a `frozen' flag when your
initialization is complete?  Something like

class ImmutableOrderedDict (OrderedDict):
  def __init__(me, *args, **kw):
me._frozen = False
OrderedDict.__init__(me, *arg, **kw)
me._frozen = True
  def _check(me):
if me._frozen:
  raise ImmutableError

And so on.

Thank you for explaining your actual objective, by the way.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Regular expression for key = value pairs

2010-12-22 Thread Mark Wooding
Ciccio franap...@gmail.com writes:

 suppose I have:

 s='a=b, c=d'

 and I want to extract sub-strings a,b,c and d from s (and in general
 from any longer list of such comma separated pairs).
[...]
 In [12]: re.findall(r'(.+)=(.+)', s)
 Out[12]: [('a=b, c', 'd')]

I think there are two logically separate jobs here: firstly, extracting
the comma-separated pairs, and secondly parsing the individual pairs.

If you want the extra problem of dealing with regular expressions, this
seems to be the way to do it.

R_PAIR = re.compile(r'''
^\s*
([^=\s]|[^=\s][^=]*[^=\s])
\s*=\s*
(\S|\S.*\S)
\s*$
''', re.X)

def parse_pair(pair):
  m = R_PAIR.match(pair)
  if not m:
raise ValueError, 'not a `KEY = VALUE\' pair'
  return m.groups([1, 2])

The former is even easier.

R_COMMA = re.compile(r'\s*,\s*')

kvs = [parse_pair(p) for p in R_COMMA.split(string)]

Apply gold-plating to taste.

But actually, it's much easier to avoid messing with regular expressions
at all.

def parse_pair(pair):
  eq = pair.index('=')
  return pair[:eq].strip(), pair[eq + 1:].strip()

kvs = [parse_pair(p) for p in string.split(',')]

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Regular expression for key = value pairs

2010-12-22 Thread Mark Wooding
André andre.robe...@gmail.com writes:

 How about the following:

  s = 'a=b,c=d'
  t = []
  for u in s.split(','):
 ... t.extend(u.split('='))

s = 'a = b = c, d = e'
= ['a ', ' b ', ' c', ' d ', ' e']

Ugh.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: If/then style question

2010-12-17 Thread Mark Wooding
Steve Holden st...@holdenweb.com writes:

 I think the choice of keyword is probably not Guido's crowning
 language achievement,

I remember the behaviour by considering a typical application:

for thing in things:
  if shinyp(thing):
break
else:
  raise DullError, 'nothing shiny found'

In this kind of search loop, `break' signifies a kind of successful
completion: the `for' loop can be considered to be a test acting over an
iterable, and `else' therefore denotes the action if the test fails.

I don't know whether that's the official intuition, or even if there is
an official intuition, but it works well enough for me.  I'm quite fond
of Python's extra `else' clauses in `for' and (particularly) `try'.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: PyArg_ParseTuple question

2010-12-14 Thread Mark Wooding
Mark Crispin nos...@panda.com writes:

 In a C module, I want to pick up the arguments for a Python call like:
 module.call(string1,[string2a, string2b, string2c], string3)
 and stash these into:
   char *arg1;
   char *arg2[];
   char *arg3;
 All arguments are required, and we can assume that the arg2 vector is
 terminated with a null pointer.

 It doesn't look like PyArg_ParseTuple will do this easily; and that
 instead I have to use either the O! format with a PyList prototype,
 or use O and write a converter.

I think the latter is probably your best bet.

 If I use O!, at what level does it check?  In particular, does it
 just check that the argument is a list, so I can get away with
 something like:

It does the equivalent of `isinstance', so you'll accept a `list' or an
instance of any subclass of `list'.

The `O' converter is pretty straightforward.  Something like this ought
to do.

static int convertlist(PyObject *o, void *p)
{
  PyObject **v;
  Py_ssize_t i, n;

  /* Could allow general sequences using PySequence_Fast */
  if (!PyList_Check(o)) return (0);

  /* Copy stuff */
  n = PyList_GET_SIZE(o);
  if ((v = PyMem_New(PyObject *, n + 1)) == 0) return (0);
  for (i = 0; i  n; i++) {
v[i] = PyList_GET_ITEM(o, n);
Py_INCREF(v[i]);
  }
  v[n] = 0;

  return (1);
}

If you want to do a more complex conversion (e.g., to the individual
items) there's more work to be done.

I could have used PySequence_* functions to read the size and items, but
that makes error handling more complicated.  One could also borrow the
references from the underlying list, which would leave the underlying
storage for the vector as the only thing to free.

I ended up writing a lot of conversion functions when I was doing Python
library bindings (for a crypto library); they're generally a good thing.
I found that the trickiest thing about PyArg_ParseTuple is in making
sure that you can clean everything up even if it goes wrong half way
through.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparisons of incompatible types

2010-12-10 Thread Mark Wooding
Steven D'Aprano steve+comp.lang.pyt...@pearwood.info writes:

 On Thu, 09 Dec 2010 12:21:45 +, Mark Wooding wrote:

  John Nagle na...@animats.com writes:

  sort has failed because it assumes that a  b and b  c implies a 
  c. But that's not a valid assumption here.
 
  It's not good to break trichotomy.
  
  You're confused.  The property
  
  a  b and b  c = a  c
  
  is called `transitivity'.  

 Yes, but I believe that John is referring to the trichotomy (like a
 dichotomy,

Then why did he say `it assumes that a  b and b  c implies a  c'?
This assumption is transitivity, not trichotomy.

2. Totality: a = b or b = a
  
  The above list sorting goes wrong because the `float' ordering isn't
  total.  In particular, x /= NaN and NaN /= x for all x (including x =
  NaN!).

 I believe this is equivalent to trichotomy.

No, it isn't.  In particular, the definition of totality I gave above
allows a = b and b = a and a /= b.  You gave a perfectly good
definition of trichotomy, which I have moved out of its original order:

 exactly one of these relations are true:

 a  b
 a == b
 a  b

A total preorder (as defined above) doesn't exhibit this property -- but
can be described in terms of a total order (which /does/ exhibit proper
trichotomy) applied to a set of equivalence classes.

  So, your last remark is in the right direction (though strict trichotomy
  is unnecessary, as I've mentioned), but apparently only by accident
  since the preceding discussion is completely wrong.

 Completely is surely a tad strong -- John might not be using the
 exact same terminology as you, but he's clearly talking about the
 equivalent concepts. He wants and expects all data types to either
 meet a total order, or raise an exception to any of the   = and =
 operators.

No.  He was hopelessly confused, describing the problem in terms of a
failure of transitivity (which doesn't, in fact, fail), but using the
word `trichotomy', apparently more by luck than judgement.

I don't want to insist on a total order.  Efficient sorting requires a
total preorder, and that's all I want.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparisons of incompatible types

2010-12-09 Thread Mark Wooding
John Nagle na...@animats.com writes:

  NaN = float(nan)
  arr = [1.0, 4.0, 3.0, 2.0, 5.0, NaN, 6.0, 3.0, NaN, 0.0, 1.0, 4.0, 
 3.0, 2.0, 5.0, NaN, 6.0, 3.0, NaN, 0.0]
  sorted(arr)
 [0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 5.0, nan, 5.0, 6.0,
 nan, 4.0, nan, 6.0, nan]

 The sorted numerical values aren't in order. 

Indeed.  You failed to provide a valid ordering to `sorted'.  By failing
to satisfy its precondition, you relieved it of its obligation to
satisfy its postcondition.

 sort has failed because it assumes that a  b and b  c implies a 
 c. But that's not a valid assumption here.

 It's not good to break trichotomy.

You're confused.  The property

a  b and b  c = a  c

is called `transitivity'.  But the `float' ordering /is/ transitive.
Note that a  b implies that neither a nor b is a NaN.

Also, trichotomy is unnecessary for sorting, and Python's `sort' method
doesn't require it; it does require a total preorder, though.  What
properties does a total preorder require?

  1. Transitivity: a = b and b = c = a = c

  2. Totality: a = b or b = a

The above list sorting goes wrong because the `float' ordering isn't
total.  In particular, x /= NaN and NaN /= x for all x (including x =
NaN!).

So, your last remark is in the right direction (though strict trichotomy
is unnecessary, as I've mentioned), but apparently only by accident
since the preceding discussion is completely wrong.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparison with False - something I don't understand

2010-12-08 Thread Mark Wooding
OKB (not okblacke) brennospamb...@nobrenspambarn.net writes:

   This is an interesting setup, but I'm not sure I see why you need 
 it.  If you know that, in a particular context, you want toy(x, 0) to 
 result in 42 instead of ZeroDivisionError, 

... and that's the point.  You don't know whether you'll need it at the
call site.  Something further up has decided that, in its context, 42
shall be the magic value returned.  In some other context, there
shouldn't be a magic value, and the exception should terminate the
program.

My toy example was just that: a minimal example showing the machinery in
action.  The value of separating out exception handling like this is
only apparent if there's a fair amount of code in between the policy
(`return 42') and the site where the exception is signalled.

Small examples of powerful abstractions aren't very convincing: a small
example trivially doesn't require powerful abstraction.  Sorry.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Exception handling in Python 3.x

2010-12-07 Thread Mark Wooding
John Nagle na...@animats.com writes:

PEP 255, like too much Python literature, doesn't distinguish
 clearly between the language definition and implementation detail.  It
 says The mechanics of StopIteration are low-level details, much like
 the mechanics of IndexError in Python 2.1.  Applications shouldn't be
 explicitly using StopIteration.

You've twisted the words by quoting them out of context, and have
attempted to force a misinterpretation of `low-level details' as
`implementation detail'.

That text comes from a question-and-answer section, in response to the
question `why not force termination to be spelled StopIteration?'.
This is a fine answer to the question: the details of the (preexisting
-- see PEP 234) iteration protocol are abstracted by the generator
syntax.  But it doesn't at all mean that the StopIteration exception
isn't an official, use-visible part of Python.

IronPython doesn't do StopIteration the same way CPython does.

 http://ironpython.codeplex.com/wikipage?title=IPy1.0.xCPyDifferences

IronPython's behaviour when you try to fetch items from a spent
generator is different.  It still implements the same iterator protocol,
and raises StopIteration when it has no more items to yield.

You're not stupid, but you'd have to be in order to think that these
references support your claim that

  You're not entitled to assume that StopIteration is how a generator
  exits.  That's a CPyton thing; generators were a retrofit, and
  that's how they were hacked in.  Other implementations may do
  generators differently.

I don't want to conclude that you're not arguing in good faith but I'm
not seeing many other possibilities.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparisons of incompatible types

2010-12-07 Thread Mark Wooding
John Nagle na...@animats.com writes:

[Stepanov]
 makes the point that, for generic programs to work right, the basic
 operations must have certain well-defined semantics.  Then the same
 algorithms will work right across a wide variety of objects.

 This is consistent with Python's duck typing, but inconsistent with
 the current semantics of some operators.

This isn't a disaster.  You should check that the arguments define the
necessary operations and obey the necessary axioms.  Python is already
dynamically typed: this kind of proof-obligation is already endemic in
Python programming, so you've not lost anything significant.

 For example, + as concatenation makes + non-commutative.  In other
 words,

   a + b

 is not always equal to

   b + a

 which is not good.

I think I probably agree with this.  Concatenation yields a nonabelian
monoid (usually with identity); `+' is pretty much universally an
abelian group operator (exception: natural numbers, where it's used in
an abelian monoid which extends to a group in a relatively obvious way).
But then we'd need another operator symbol for concatenation.
Nonnegative integers act on strings properly, but the action doesn't
distribute over concatenation, which is also a shame.  i.e.,

n*(a + b) != n*a + n*b

But it's a familiar notation, by no means peculiar to Python, and
changing it would be difficult.

 Exactly one of

   a  b
   a = b
   a  b

 is true, or an type exception must be raised.

This will get the numerical people screaming.  Non-signalling NaNs are
useful, and they don't obey these axioms.

I think, more generally, that requiring a full total order (rather than
either a preorder or a partial order) is unnecessarily proscriptive.
Sorting only requires a preorder, for example, i.e., { (a, b) | a = b
= a } is an equivalence relation, and the preorder naturally induces a
total order on the equivalence classes.  Topological sorting requires
only a partial order, and makes good use of the notation.  As an
example, sets use `=' to denote subsetness, which is well known to be a
partial order.

(I presume you weren't going to deny

a = b iff a  b or a == b

or

a  b iff b  a

because that really would be bad.)

 The basic Boolean identities

   (a or b) == (b or a)
   not (a or b) == (not a) and (not b)
   not (not a) == a

 should all hold, or an type exception should be raised.

The first of these contradicts the axiom

x = x or _|_ == x

which is probably more useful.  The last can't usefully be true since
`not' is lossy.  But I think that, for all values a, b,

not (a or b) == not (b or a) == (not a) and (not b)
not (not (not a)) == not a

which is probably good enough.  (The application of `not' applies a
boolean coercion, which canonifies adequately.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparisons of incompatible types

2010-12-07 Thread Mark Wooding
Carl Banks pavlovevide...@gmail.com writes:

 I think that feeling the need to sort non-homogenous lists is
 indictative of bad design.

Here's a reason you might want to.

You're given an object, and you want to compute a hash of it.  (Maybe
you want to see whether someone else's object is the same as yours, but
don't want to disclose the actual object, say.)  To hash it, you'll need
to serialize it somehow.  But here's a problem: objects like
dictionaries and sets don't impose an ordering on their elements.  For
example, the set { 1, 'two' } is the same as the set { 'two', 1 } -- but
iterating the two might well yield the elements in a different order.
(The internal details of a hash table tend to reflect the history of
operations on the hash table as well as its current contents.)

The obvious answer is to apply a canonical ordering to unordered objects
like sets and dictionaries.  A set can be serialized with its elements
in ascending order; a dictionary can be serialized as key/value pairs
with the keys in ascending order.  But to do this, you need an
(arbitrary, total) order on all objects which might be set elements or
dictionary keys.  The order also needs to be dependent only on the
objects' serializable values, and not on any incidental facts such as
memory addresses or whatever.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparison with False - something I don't understand

2010-12-06 Thread Mark Wooding
Paul Rubin no.em...@nospam.invalid writes:

 You know, I've heard the story from language designers several times
 over, that they tried putting resumable exceptions into their languages
 and it turned out to be a big mess, so they went to termination
 exceptions that fixed the issue.

That seems very surprising to me.

 Are there any languages out there with resumable exceptions?

Common Lisp and Smalltalk spring to mind.  It's fairly straightforward
to write one in Scheme.  (Actually, implementing the Common Lisp one in
terms of fluids, closures and blocks isn't especially difficult.)

 Escaping to a debugger doesn't really count as that.

Indeed not.

 I guess one way to do it would be call a coroutine to handle the
 exception, and either continue or unwind after the continue returns,
 but doing it in a single-threaded system just seems full of hazards.

It seems pretty straightforward to me.  Handlers are simply closures;
the registered handlers are part of the prevailing dynamic context.
When an exception occurs, you invoke the handlers, most-recently
registered first.  A handler that returns normally can be thought of as
`declining' to handle the exception; a handler that explicitly transfers
control elsewhere can be thought of as having handled it.

To make this work, all you need is:

  * a fluid list (i.e., one which is part of the dynamic context) of
handlers, which you can build in pure Python if you try hard enough
(see below);

  * closures to represent handlers, which Python has already, and;

  * a nonlocal transfer mechanism, and a mechanism like try ... finally
to allow functions to clean up if they're unwound.

We can actually come up with a nonlocal transfer if we try, by abusing
exceptions.

[The code in this article is lightly tested, but probably contains
stupid bugs.  Be careful.]

class block (object):
  
  Context manager for escapable blocks.

  Write

with block() as escape:
  ...

  Invoking the `escape' function causes the context body to exit
  immediately.  Invoking the `escape' function outside of the
  block's dynamic context raises a ValueError.
  
  def __init__(me):
me._tag = None
  def _escape(me, value = None):
if me._tag is None:
  raise ValueError, 'defunct block'
me.result = value
raise me._tag
  def __enter__(me, value = None):
if me._tag:
  raise ValueError, 'block already active'
me._tag = type('block tag', (BaseException,), {})
me.result = value
return me._escape
  def __exit__(me, ty, val, tb):
tag, me._tag = me._tag, None
return ty is tag

This is somewhat brittle, since some intervening context might capture
the custom exception we're using, but I don't think we can do
significantly better.

Implementing fluids badly is easy.  Effectively what we'd do to bind a
fluid dynamically is

try:
  old, fluid = fluid, new
  ...
finally:
  fluid = old

but this is visible in other threads.  The following will do the job in
a multithreaded environment.

import threading as T
import weakref as W

class FluidBinding (object):
  Context object for fluid bindings.
  def __init__(me, fluid, value):
me.fluid = fluid
me.value = value
  def __enter__(me):
me.fluid._bind(me.value)
  def __exit__(me, ty, val, tb):
me.fluid._unbind()

class Fluid (object):
  
  Represents a fluid variable, i.e., one whose binding respects
  the dynamic context rather than the lexical context.

  Read and write the Fluid through the `value' property.

  The global value is shared by all threads.  To dynamically
  bind the fluid, use the context manager `binding':

  with myfluid.binding(NEWVALUE):
...

  The binding is visible in functions called MAP within the
  context body, but not in other threads.
  

  _TLS = T.local()
  _UNBOUND = ['fluid unbound']
  _OMIT = ['fluid omitted']

  def __init__(me, value = _UNBOUND):

Iinitialze a fluid, optionally setting the global value.

me._value = value

  @property
  def value(me):

Return the current value of the fluid.

Raises AttributeError if the fluid is currently unbound.

try:
  value, _ = me._TLS.map[me]
except (AttributeError, KeyError):
  value = me._value
if value == me._UNBOUND:
  raise AttributeError, 'unbound fluid'
return value
  @value.setter
  def value(me, 

Re: Resumable exceptions bad:

2010-12-06 Thread Mark Wooding
John Nagle na...@animats.com writes:

 Resumable exceptions were a popular idea in the early days of
 programming.  LISP, PL/I, and early COBOL had constructs which could
 be considered resumable exceptions.  They didn't work out well,
 because the exception handler gets control in an ambiguous situation,
 perhaps in the middle of an expression.  Changing the state of the
 execution, then returning, can leave the program in an invalid state.

Right, but that's not the important really important trick.  The
important bit is separating out the `how should I fix this?' logic from
the point where execution should resume.  There's no good reason why the
former should have to come from a dynamic context smaller than the
latter: it's just an unnecessary conflation.

[Snip stuff about signals.  I agree that Unix signals are a disaster.]

 So that's why resumable exceptions are a bad idea.

That's why a primitive resumable exception system, used naively, is a
bad idea.  Now look at the good ones.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparisons of incompatible types

2010-12-06 Thread Mark Wooding
Terry Reedy tjre...@udel.edu writes:

 And indeed, code like this that has not been updated does break in
 3.x. to some people's annoyance. We really really cannot please
 everyone ;-).

The problem is that there are too many useful properties that one might
expect from comparison operators.  For example, it's frequently nice to
have a total ordering on all objects.  For real numbers, it's nice that
the ordering obey the usual ordered-field axioms; but the complex
numbers don't have an ordering compatible with the field operators, and
imposing a default ordering (e.g., degree-lexicographic) is probably
asking for trouble.

I agree that the Python 3 behaviour is an improvement, by the way.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Exception handling in Python 3.x

2010-12-06 Thread Mark Wooding
John Nagle na...@animats.com writes:

 Right.  You're not entitled to assume that StopIteration is how a
 generator exits.  That's a CPyton thing; generators were a retrofit,
 and that's how they were hacked in.  Other implementations may do
 generators differently.

This is simply wrong.  The StopIteration exception is a clear part of
the generator protocol as described in 5.2.8 of the language reference;
the language reference also refers to 3.5 of the library reference,
which describes the iterator protocol (note, not the generator
implementation -- all iterators work the same way), and explicitly
mentions StopIteration as part of the protocol.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparison with False - something I don't understand

2010-12-06 Thread Mark Wooding
Carl Banks pavlovevide...@gmail.com writes:

 On Dec 6, 12:58 pm, m...@distorted.org.uk (Mark Wooding) wrote:
          def toy(x, y):
            r = restart('use-value')
            with r:
              if y == 0:
                error(ZeroDivisionError())
              r.result = x/y
            return r.result
 
          def example():
            def zd(exc):
              if not isinstance(exc, ZeroDivisionError):
                return
              r = find_restart('use-value')
              if not r: return
              r.invoke(42)
            print toy(5, 2)
            with handler(zd):
              print toy(1, 0)

 You could do that.

 Or, you could just put your try...finally inside a loop.

[You correct `finally' to `except' in a follow-up.]

I think you've missed the point almost entirely.

Any code called from within the `with handler' context will (unless
overridden) cause a call `toy(x, 0)' to return 42.  Even if the `with
handler' block calls other functions and so on.  Note also that the
expression of this is dynamically further from where the error is
signalled than the resume point (which is within the same function).
You can't do this with `try' ... `except'.  Which was, of course, the
point.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Comparison with False - something I don't understand

2010-12-03 Thread Mark Wooding
Steven D'Aprano steve+comp.lang.pyt...@pearwood.info writes:

 On Thu, 02 Dec 2010 16:35:08 +, Mark Wooding wrote:
  There are better ways to handle errors than Python's exception system.

 I'm curious -- what ways would they be?

The most obvious improvement is resumable exceptions.

In general, recovering from an exceptional condition requires three
activities:

  * doing something about the condition so that the program can continue
running;

  * identifying some way of rejoining the program's main (unexceptional)
flow of control; and

  * actually performing that transfer, ensuring that any necessary
invariants are restored.

Python's `try ... finally' helps with the last; but Python intertwines
the first two, implementing both with `try ... except'.  The most
important consequence of this is that the logic which contains knowledge
about how to fix the condition must be closer to the code that
encountered the condition than the resume point is.  It's therefore hard
to factor out high-level policy about fixing conditions from the
relatively tedious business of providing safe points at which to resume
main execution.  (Effectively, each section of your program which wants
to avail itself of some high-level condition-fixing policy has to
provide its own protocol for expressing and implementing them.)

Phew.  That was abstract.  Can I come up with some examples?

I've been writing a (sort of) compiler recently.  When it encounters
errors, it reports a message to the user containing the position it had
reached in the source, updates a counter so that it can report a summary
at the end of the run and produce a sensible exit status, and then
attempts to carry on compiling as best it can.

The last bit -- attempting to carry on as best it can -- needs local
knowledge of what the compiler's doing and what actually went wrong.  If
the parser expected to find a delimiter, maybe it should pretend that it
found one, for example.

The other stuff, printing messages, updating counters, and so on, is all
done with some condition handlers wrapped around the meat of the
compiler.  That's written only once.  Everything that signals errors,
including standard I/O functions like open-a-file, gets the same
treatment.

(The remaining missing ingredient is a fluid variable which tracks the
current position in the source and is updated by the scanner; bits of
the compiler's semantic analysis machinery will temporarily focus
attention on other parts of the source using locations they saved during
the parse.  Implementing fluids in Python can be done with a context
manager: if you don't care about concurrency then you can use simple
variables; otherwise it's little fiddly and the syntax isn't very
comfortable, but it's still possible.)

A more familiar example, maybe, is the good old DOS `abort/retry/fail'
query.  Implementing such a thing in Python, as a general policy for
handling I/O errors, isn't possible.  Viewed narrowly, this is probably
a good thing: the old DOS query was very annoying.  But the difficulty
of implementing this policy illustrates the missing functionality.  And,
of course, if DOS had a proper resumable exception system, programs
could have overridden the annoying query.

In general, the code which discovers an exceptional condition may have
several options for how to resume.  It might be possible to ignore the
situation entirely and carry on regardless (`false alarm!').  It might
be possible to try again (`transient failure').  Alas, the logic which
is capable of implementing these options is usually too low-level and
too close to the action to be able to decide among them sensibly.
(Maybe a human user should be consulted -- but that can drag in user
interface baggage into a low-level networking library or whatever.)
Resumable exceptions provide a way out of this mess by separating the
mechanics of resumption from policy of which resumption option to
choose.

It's easy to show that a resumable exception system can do everything
that a nonresumable system (like Python's) can do (simply put all of the
recovery logic at the resume point); but the converse is not true.

There are some other fringe benefits to resumable exceptions.

  * It's usual to report a stack backtrace or similar if an exception
occurs but nothing manages to resume execution.  If unwinding the
stack is intertwined with working out how to resume execution, then
whenever you /try/ to run an applicable handler, you have to reify
the stack context and stash it somewhere in case the handler doesn't
complete the job.  This makes raising exceptions more expensive than
they need to be.

  * You can use the same mechanism for other kinds of communication with
surrounding context.  For example, Python occasionally emits
`warnings', which have their own rather simple management system
(using global state, so it's hard to say `don't issue MumbleWarnings
while we frob the widgets

Re: Assigning to __class__ attribute

2010-12-03 Thread Mark Wooding
kj no.em...@please.post writes:

  class Spam(object): pass

 Now I define an instance of Spam and an instance of Spam's superclass:
  x = Spam()
  y = Spam.__mro__[1]() # (btw, is there a less uncouth way to do this???)

There's the `__bases__' attribute, which is simply a tuple of the
class's direct superclasses in order.  Spam.__bases__[0] will always be
equal to Spam.__mro__[1] because of the way the linearization works.

There's also `__base__' attribute, which seems to correspond to a
PyTypeObject's `tp_base' slot; this /isn't/ always the first direct
superclass; I'm not quite sure what the rules are, and it doesn't seem
to be documented anywhere.

  [z.__class__.__name__ for z in x, y]
 ['Spam', 'object']

  class Ham(object): pass
 ... 

  x.__class__ = Ham
  [isinstance(x, z) for z in Spam, Ham]
 [False, True]

 First question: how kosher is this sort of class transmutation
 through assignment to __class__?  

Yep.  That's allowed, and useful.  Consider something like a red/black
tree: red and black nodes behave differently from one another, and it
would be convenient to make use of method dispatch rather than writing a
bunch of conditional code; unfortunately, nodes change between being red
and black occasionally.  Swizzling classes lets you do this.

Various other languages have similar features.  The scariest is probably
Smalltalk's `become: anObject' method, which actually swaps two objects.
Python `__class__' assignment is similarly low-level: all it does is
tweak a pointer, and it's entirely up to the program to make sure that
the object's attributes are valid according to the rules for the new
class.  The Common Lisp Object System has CHANGE-CLASS, which is a
rather more heavyweight and hairy procedure which tries to understand
and cope with the differences between the two classes.

 I've never seen it done.  Is this because it considered something to
 do only as a last resort, or is it simply because the technique is not
 needed often, but it is otherwise perfectly ok?

It's not needed very often, and can be surprising to readers who aren't
familiar with other highly dynamic object systems, so I don't think it's
particularly encouraged; but it seems like it might be the best approach
in some cases.  I think it's one of those things where you'll just
/know/ when it's the right answer, and if you don't know that it's the
right answer, it isn't.

  y.__class__ = Ham
 Traceback (most recent call last):
   File stdin, line 1, in module
 TypeError: __class__ assignment: only for heap types

`Heap types' are types which are allocated dynamically.  Non-heap types
are ones which are dreamt up by C extensions or built into Python.

I suspect that the logic here is that non-heap types in general are
magical and weird, and their instances might have special C stuff
attached to them, so changing their classes is a Bad Idea, though
there's an extra check which catches most problems:

In [1]: class foo (str): pass
In [2]: class bar (object): pass
In [3]: x = foo()
In [4]: x.__class__ = bar
TypeError: __class__ assignment: 'foo' object layout differs from 'bar'

Anyway, I'd guess it's just a bug that `object' is caught this way, but
it doesn't seem an especially important one.

 This definitely rattles my notions of inheritance: since the
 definition of Spam was empty, I didn't expect it to have any
 significant properties that are not already present in its superclass.

Yes, sorry.  I think this is a bit poor, really, but it's hard to do a
much better job.

Pure Python objects are pretty simple things, really: they have a
pointer to their class, and a bunch of attributes stored in a
dictionary.  What other languages call instance variables or methods are
found using attribute lookup, which just searches the object, and then
its class and its superclasses in the method resolution order.  If you
fiddle with `__class__', then attribute lookup searches a different
bunch of classes.  Nothing else needs to change -- or, at least, if it
does, then you'd better do it yourself.

Types implemented in C work by extending the underlying Python object
structure.  The magical type-specific stuff is stored in the extra
space.  Unfortunately, changing classes is now hard, because Python code
can't even see the magic C stuff -- and, besides, a different special C
type may require a different amount of space, and the CPython
implementation can't cope with the idea that objects might move around
in memory.

Similar complications occur if one of the classes has a `__slots__'
attribute: in this case, both the original and new class must have a
`__slots__' attribute and they must be the same length and have the same
names.

 What is the most complete, definitive, excruciatingly detailed
 exposition of Python's class and inheritance model?

It's kind of scattered.  The language reference sections 3.3 and 3.4
contain some useful information, but it's rather detailed and it's a
(mostly) comprehensive list of what a bunch of 

Re: Comparison with False - something I don't understand

2010-12-02 Thread Mark Wooding
Harishankar v.harishan...@gmail.com writes:

 There are some reasons why I hate exceptions but that is a different 
 topic. However, in short I can say that personally:

 1. I hate try blocks which add complexity to the code when none is 
 needed. Try blocks make code much more unreadable in my view and I use it 
 only for the built-in exceptions when absolutely needed.

Very little code actually needs `try' blocks.

 2. I prefer the less irksome True or False to do error checking.
 Exceptions seem too heavyweight for simple problems.

Just write simple programs as if errors never happen; if an exception is
raised, the program prints a vaguely useful message and exits.

Besides, this complaint is incoherent.  One needs at least as much
structure to check an error code as to catch an exception.

 3. Philosophically I think exception handling is the wrong approach to 
 error management.

There are better ways to handle errors than Python's exception system.
Passing error codes around manually is most definitely not one of them.

(One of the main reasons I ditched Perl in favour of Python is the
former's insistence on returning error codes for I/O and system calls.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Catching user switching and getting current active user from root on linux

2010-12-01 Thread Mark Wooding
Grant Edwards inva...@invalid.invalid writes:

 On 2010-11-30, mpnordland mpnordl...@gmail.com wrote:
  and catch user switching eg user1 locks screen, leaves computer,
  user2 comes, and logs on. basically, when there is any type of user
  switch my script needs to know.

 What do you do when there are multiple users logged in?

In case it's not clear: this situation doesn't just occur on `exotic'
systems like Unix servers.  Even Windows systems can have several people
logged into the console (with one active, using `fast user switching')
and another one or two connected using terminal services.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Needed: Real-world examples for Python's Cooperative Multiple Inheritance

2010-11-28 Thread Mark Wooding
Steve Holden st...@holdenweb.com writes:

 It isn't. Even inheritance itself isn't as useful as it at first
 appears, and composition turns out in practice to be much more useful.
 That goes double for multiple inheritance.

Composition /with a convenient notation for delegation/ works fairly
well.  Indeed, this can be seen as the basis of Self.  But downwards
delegation -- where a superclass leaves part of its behaviour
unspecified and requires (concrete) subclasses to fill in the resulting
blanks -- is hard to express like this without some kind of means of
identifying the original recipient of the delegated message.  Once
you've done that, there isn't much of a difference between a superclass
and a component with implicit delegation.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Needed: Real-world examples for Python's Cooperative Multiple Inheritance

2010-11-27 Thread Mark Wooding
John Nagle na...@animats.com writes:

 On 11/26/2010 4:21 PM, Mark Wooding wrote:
  John Naglena...@animats.com  writes:
  @This catches the case where two classed both inherit from, say
  threading.thread, each expecting to have a private thread.
 
  Why on earth would anyone do such a bizarre thing?  If you want a
  private thread, then attach one as an attribute.  Inheriting is simply
  madness.

 This must be from someone who hasn't used threads in Python.

Wrong again.

 The usual way to write a thread in Python is to subclass
 threading.thread.  The subclass provides a run function, which
 will be called from the new thread.

Yes, it is.  Does that conflict with what I wrote?  No.

If you want you class to have a private thread, make /another/ class to
represent the behaviour of this private thread, and attach an instance
of this to the first class.  Or you can pass a closure or a bound method
to the thread constructor.  (That's probably cleaner, actually, but
doesn't fit culturally.)

  If you stopped whining about how Python's object system might
  theoretically go wrong if you try to use it like it was C++ and
  started thinking about how to actually make effective use of the
  features it offers -- features which long predate Python, and have
  been thought about over many years, in languages such as Zetalisp,
  Common Lisp, Dylan, Scheme, and variants of Smalltalk -- you might
  got on much better.

Ah, fanboys.

Not exactly.  I collect programming languages like some people collect
postage stamps; it gives one a useful perspective.  I mentioned those
languages because they seem most historically relevant.  Zetalisp's
`Flavors' system introduced multiple inheritance; Common Lisp and Dylan
fix the linearization properly (eventually culminating in the C3
linearization algorithm); Scheme has no standardized object system, but
there are a number of -- mainly CLOS-like -- object systems available;
and Smalltalk is both the classic dynamic object-oriented language and a
single-dispatch contrast to the CLOS/Dylan generic-functions approach.

 Of those, I've written code in Common Lisp, Scheme, and Smalltalk.
 Most of the LISP variants really did objects very well; objects were
 an afterthought.  Smalltalk went a bit too far in the other direction;
 the everything is an object mindset was overdoing it.

CLOS actually does a remarkable integration job, bringing the existing
types into the object system; but, yes, the seams are still visible,
because you can't subclass some of the classes.

 Python is reasonably well balanced in the object area.  Everything
 isn't an object.  There are explicit classes, unlike the
 instance-copying model of Self and Javascript.

Is that a major win?  Self's prototype-based approach seems quite
capable of expressing anything you might want to express with classes,
and a few other things besides.  (The implementation works by attempting
to deduce class structures dynamically, so there's an isomorphism here,
of a sort, but the dynamism would make inventing classes on the fly
rather inconvenient.)  There's a significant difference between
Javascript and Self, by the way: a Self object can have multiple
`parent' slots, consequently with a form of multiple inheritance, while
Javascript is limited to single inheritance (unless you fake it up).

 However, multiple inheritance is something of a mess, as the original
 starter of this thread found when he tried to document how to use it.

Python's object system certainly isn't ideal.

The main problem that I see is that dynamic delegation with `super' is
hideously inconvenient to use, which means that programmers will tend
towards C++'s static delegation instead.

The Python object construction protocol (__new__ and __init__) is
somewhat simplistic; constructing instances of multiply inherited
classes in general requires a somewhat complicated dance with *args and
**kw arguments -- and you lose the ability to reject unknown arguments
-- which again leads to programmers taking shortcuts.

Most of the rest of the object system seems pretty sound to me.

 If you have real trouble writing documentation for a feature, it's
 usually because the feature is badly designed.

It might be that it was misunderstood.

There seem to be two obvious ways of learning a programming language.
One is to try and interpret its concepts in terms of concepts that you
already understand.  This works, but you end up having to `translate'
between the new language; if the translation is imperfect then you'll be
confused or frustrated.  There's a constant temptation to force one's
existing conceptual framework onto the new language -- to use it as if
it worked just like something else one is more familiar with that
doesn't quite work `right'.  The new language is `broken Blub with funny
syntax'.

The other is to try to understand it on its own terms.  This is the
harder road that leads to mastery.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo

Re: inverse of a matrix with Fraction entries

2010-11-27 Thread Mark Wooding
casevh cas...@gmail.com writes:

 I coded a quick matrix inversion function and measured running times
 using GMPY2 rational and floating point types. For the floating point
 tests, I used a precision of 1000 bits. With floating point values,
 the running time grew as n^3. With rational values, the running time
 grew as n^4*ln(n).

Did you clear the denominators before you started?

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Needed: Real-world examples for Python's Cooperative Multiple Inheritance

2010-11-26 Thread Mark Wooding
John Nagle na...@animats.com writes:

 I'd argue that a better implementation would require that when there's
 a name clash, you have to specify the class containing the name. In
 other words, if A is a subclass of B, then B.foo() overrides
 A.foo().  But if C is a subclass of A and B, and there's an A.foo() and
 a B.foo(), calling self.foo() in C should be an error, because it's
 ambiguous. You should have to specify the parent class, using super.

How peculiar.  `super' is /specifically/ for working out dynamically
which superclass to delegate behaviour to, because working it out
statically isn't possible in general.

 The same issue applies in the other direction.  If A and B are
 subclasses of D, and A.foo() and B.foo() are defined, and D calls
 self.foo(), that's an ambiguity and should be reported.

No it isn't.  It's downward delegation, which is an essential feature of
object oriented design.

 @This catches the case where two classed both inherit from, say
 threading.thread, each expecting to have a private thread.

Why on earth would anyone do such a bizarre thing?  If you want a
private thread, then attach one as an attribute.  Inheriting is simply
madness.

 Someone then inherits from both classes, getting totally unexpected
 results when one of the run methods is chosen somewhat arbitrarily.

But only because the original design was crazy.  If you make a subclass
of `thread' it's because you wanted a more specific kind of thread.  If
you subclass two other subclasses of `thread', it's because you wanted a
very specific kind of thread which included the behaviour of those other
two subclasses.

 Detecting a clash requires machinery CPython's lookup machinery
 currently lacks. 

What you see as a `clash' is more likely deliberate factoring of
behaviour.

Again, you seem to think that C++ is, for some reason, the `one true
way'.  It really isn't.  Actually, it's a pretty poor way.  But that's
not the point: the point is that there are other ways, and if you
stopped whining about how Python's object system might theoretically go
wrong if you try to use it like it was C++ and started thinking about
how to actually make effective use of the features it offers -- features
which long predate Python, and have been thought about over many years,
in languages such as Zetalisp, Common Lisp, Dylan, Scheme, and variants
of Smalltalk -- you might got on much better.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: inverse of a matrix with Fraction entries

2010-11-25 Thread Mark Wooding
Daniel Fetchinson fetchin...@googlemail.com writes:

  I wouldn't do it that way.  Let M be your matrix.  Work out the LCM l of
  the denominators, and multiply the matrix by that to make it an integer
  matrix N = l M.  Then work out the determinant d of that integer matrix.
  Next, the big step: use Gaussian elimination to find a matrix A (the
  `adjugate matrix') such that A N = d I.  This should be doable entirely
  using integer arithmetic, and I think without needing any divisions.
  Finally, we have l A M = d I, so (l/d A) M = I and l/d A is the inverse
  you seek.
 
  Does that make sense?

 Absolutely! But there is nothing wrong with working out the inverse
 directly using fractions.Fraction arithmetic, I'd think.

It'll work, certainly; but the Fraction implementation will have to do a
buttload of GCD computations that it wouldn't need to do if you worked
with plain integers.  And GCDs are relatively hard, as arithmetical
computations go: the usual algorithms require either a number of
divisions (which are themselves rather costly) or a bitwise traversal of
one of the operands.

A million entries seems nontrivial for a matrix, and Gaussian
elimination has cubic running time if I remember rightly; I suspect that
the transformations I describe would reduce the running time by a fair
amount.  Of course, I might be drastically underestimating the
performance of modern hardware -- I often do -- so this may not be
especially relevant.  Anyway, the possibility's there.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Needed: Real-world examples for Python's Cooperative Multiple Inheritance

2010-11-25 Thread Mark Wooding
John Nagle na...@animats.com writes:

Multiple inheritance in Python is basically what fell out of
 CPython's internals, not a design.  It's one of those areas where
 order of execution matters, and that wasn't well worked out.

I'm not sure about the history, but this doesn't sound right to me.

 Allowing classes to form a directed acyclic graph isn't very
 useful.

This is simply wrong.

 It just fell out of the semantics of a naive interpreter.

No: there's some essential work needed to make it happen.

 Originally, the semantics were just wrong.

Agreed.

 Now the awful cases have well-defined semantics, but aren't very
 useful.

Disagree strongly.  I think linearization is the only coherent approach
to multiple inheritance, and the C3 linearization seems to have almost
all of the necessary properties.  I'm not quite sure what you mean by
`awful' here: the old Python linearization rules were wrong even for
very simple graphs (they failed to respect the superclass ordering
properly).  The CLOS, Dylan and C3 linearizations agree on most commonly
occurring class graphs, including many graphs for which the old Python
orderings disagreed; the exceptions are where CLOS or Dylan failed to be
monotonic or to obey the extended precedence graph.  The semantics are
extremely useful in the hands of a careful designer.

Part of the problem is the notion that if a base class is duplicated
 in the hierarchy, there's only one copy.

This is a problem?  No!  Duplicating superclass state (as is done in C++
and, I believe, Eiffel) is incoherent.

 So if you inherit from two classes, both of which inherit from dict,
 there will be only one dict at the bottom.  (I think.)

Yes.  You end up (probably) with an enhanced dictionary which supports
both protocols.  This happens frequently, and is very useful.

 This probably won't do what the authors of any of the classes involved
 expected.  The author of the class which does the multiple inheritance
 might not even be aware that there's a clash further up in the
 hierarchy.  This is one of those areas where all the code looks right
 locally, but it's wrong globally.

This is only likely if there's a misdesign -- probably using inheritance
where containership is required.

Best practice for this is don't do it.  Some name clashes ought
 to simply be detected as errors, rather than being given such
 complex semantics.

It sounds like you've been scarred by experiences with C++'s dementedly
inadequate object system, with its bizarre `repeated inheritance' rules
and hopelessly primitive manual (static!) method combination -- possibly
even to the extent of believing that they're in some way `right' or
`necessary'.  I'm sorry.  You have my pity.

Python's object system is different, and doesn't have those problems.
You probably need a viewpoint shift to be able to think about it
properly, but that won't happen if you continue to cling to the idea
that C++'s approach is anything like a model of how to do it right.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: inverse of a matrix with Fraction entries

2010-11-24 Thread Mark Wooding
Daniel Fetchinson fetchin...@googlemail.com writes:

 So after all I might just code the inversion via Gauss elimination
 myself in a way that can deal with fractions, shouldn't be that hard.

I wouldn't do it that way.  Let M be your matrix.  Work out the LCM l of
the denominators, and multiply the matrix by that to make it an integer
matrix N = l M.  Then work out the determinant d of that integer matrix.
Next, the big step: use Gaussian elimination to find a matrix A (the
`adjugate matrix') such that A N = d I.  This should be doable entirely
using integer arithmetic, and I think without needing any divisions.
Finally, we have l A M = d I, so (l/d A) M = I and l/d A is the inverse
you seek.

Does that make sense?

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Some syntactic sugar proposals

2010-11-18 Thread Mark Wooding
Steven D'Aprano steve-remove-t...@cybersource.com.au writes:

 On Wed, 17 Nov 2010 16:31:40 +, Mark Wooding wrote:

  But I don't think that's the big problem with this proposal.  The real
  problem is that it completely changes the evaluation rule for the
  conditional expression.  (The evaluation rule is already pretty screwy:
  Python is consistently left-to-right -- except here.)

 Not quite...

  1+2*3
 7
  (1+2)*3
 9

You're wrong.  Python evaluates these left-to-right, as I said.
Parentheses override operator associativity; they don't affect
evaluation order at all.

Consider:

def say(x):
  print 'seen %s' % x
  return x

print say(1) + say(2) * say(3)
print (say(1) + say(2)) * say(3)

Run this program and you get

seen 1
seen 2
seen 3
7
seen 1
seen 2
seen 3
9

So definitely left-to-right.  Translating into reverse-Polish, say with
Dijkstra's shunting-yard algorithm, is enlightening: you get

1 2 3 * +

for the first and

1 2 + 3 *

for the second.  This preserves evaluation order; indeed, this is a
general property of the shunting-yard algorithm.

Finally, I quote from the language reference (5.13 of the 2.5 version),
just to show that (this time, at least) I'm not trying to impose
unfamiliar terminology, and that Python is defined to behave like this
and I'm not relying on implementation-specific details.  Alas, it also
highlights a genuine inconsistency, but one which might be considered
tolerable.

: 5.13 Evaluation order
: =
: 
: Python evaluates expressions from left to right. Notice that while
: evaluating an assignment, the right-hand side is evaluated before the
: left-hand side.
: 
: In the following lines, expressions will be evaluated in the
: arithmetic order of their suffixes:
: 
:  expr1, expr2, expr3, expr4
:  (expr1, expr2, expr3, expr4)
:  {expr1: expr2, expr3: expr4}
:  expr1 + expr2 * (expr3 - expr4)
:  func(expr1, expr2, *expr3, **expr4)
:  expr3, expr4 = expr1, expr2

So the above example is /explicitly/ dealt with in the language
reference, if only you'd cared to look.

 Not everything needs to be a one liner. If you need this, do it the old-
 fashioned way:

 t = foo()
 if not pred(t): t = default_value

I already explained how to write it as a one-liner:

t = (lambda y: y if pred(y) else default_value)(foo())

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is Unladen Swallow dead?

2010-11-18 Thread Mark Wooding
John Nagle na...@animats.com writes:

  Python is defined by what a naive interpreter with late binding
 and dynamic name lookups, like CPython, can easily implement.  Simply
 emulating the semantics of CPython with generated code doesn't help
 all that much.

Indeed.

  Because you can monkey patch Python objects from outside the
 class, a local compiler, like a JIT, can't turn name lookups into hard
 bindings.  Nor can it make reliable decisions about the types of
 objects.

But it /can/ make guesses.  A dynamic runtime doesn't have to predict
everything right in advance; it only has to predict most things sort of
well enough, and fix up the things it got wrong before anyone notices.
For example, A Python compiler could inline a function call if it makes
a note to recompile the calling function if the called function is
modified.  Most functions aren't redefined, so this is probably a pretty
good guess.

 That adds a sizable performance penalty. Short of global program
 analysis, the compiler can't tell when code for the hard cases needs
 to be generated.

The right approach is to guess that things are going to be done the easy
way, and then detect when the guess is wrong.

 So the hard-case code, where you figure out at run-time, for ever use
 of +, whether + is addition or concatenation, has to be generated
 every time.  Making that decision is far slower than doing an add.

There's an old trick here called `inline caching'.  The first time a
function is called, compile it so as to assume that types of things are
as you found this time: inline simple methods, and so on.  Insert some
quick type checks at the top: is this going to work next time?  If not,
take a trap back into the compiler.  The traditional approach is to
replace the mispredictions with full dispatches (`monomorphic inline
caching'); the clever approach tolerates a few different types,
dispatching to optimized code for each (`polymorphic inline caching'),
unless there are just too many decision points and you give up.

There are time/space tradeoffs to be made here too.  Fortunately, you
don't have to compile everything super-optimized from the get-go: you
can dynamically identify the inner loops which need special attention,
and get the compiler to really stare hard at them.  The rest of the
program might plausibly be left interpreted much of the time for all
anyone will care.

  I've referred to this problem as gratuitous hidden dynamism.
 Most things which could be changed dynamically in a Python program
 usually aren't.

This is one of the crucial observations for making a dynamic language go
fast; the other is that you still have the compiler around if you
guessed wrong.

An aggressively dynamic runtime has two enormous advantages over batch
compilers such as are traditionally used for C: it gets the entire
program in one go, and it gets to see the real live data that the
program's meant to run against.  Given that, I'd expect it to be able to
/beat/ a batch compiler in terms of performance.

  This has been pointed out many times by many people.  There's
 even a PhD thesis on the topic.  Without a few restrictions, so
 that a compiler can at least tell when support for the hard cases
 is needed, Python cannot be compiled well.

This assumes static compilation.  It's the wrong approach for a dynamic
language like Python.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Some syntactic sugar proposals

2010-11-18 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

  Not everything needs to be a one liner. If you need this, do it the
  old- fashioned way:
 
  t = foo()
  if not pred(t): t = default_value
  
  I already explained how to write it as a one-liner:
  
  t = (lambda y: y if pred(y) else default_value)(foo())

 I didn't say it couldn't be written as a one-liner. I suggested that it 
 was better not to.

Ahh.  I misunderstood the first sentence above as dismissing the
possibility.  Sorry.  I agree that it's not a /nice/ one-liner. ;-)

 The costs of the one-liner are:

 * reduced readability;
 * requires an increased level of knowledge of the reader (what's lambda 
 do?);
 * runtime inefficiency (you create a function object, only to use it once 
 then throw it away).

This last can be obviated by a clever compiler (which, in our case, we
have not got).  The second could be considered an advantage: it's
educational!

 The advantages?

 * one fewer line of code.

 In my experience, the obsessiveness in which some people look for one-
 liners is far from helpful, and goes against the spirit of Python. This 
 isn't Perl :)

Oh, I agree completely.  On the other hand, it's just /fun/.  Python is
a fun language and using its features in playfully unusual ways is
enjoyable; like a good pun in a natural language.  Just as puns aren't
always appropriate in written language, playful code isn't always
appropriate either; but that doesn't mean it's never appropriate.

(Java has no sense of humour.  C++ does have, but it's a bit weird.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Program, Application, and Software

2010-11-18 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

 On Thu, 18 Nov 2010 14:21:47 +, Martin Gregorie wrote:

  I use 'script' to refer to programs written in languages that don't have
  a separate compile phase which must be run before the program can be
  executed. IOW Python and Perl programs are scripts aloing with programs
  written as awk, Javascript and bash scripts.

 You're mistaken then about Python, because it does have a separate 
 compilation phase that runs before the program can be executed. Where do 
 you think the .pyc files come from, and what did you think the compile() 
 function did? It just happens automatically, rather than manually.

I think Martin meant that there's no /explicit/ compilation phase.  As a
case in point, tcc is an optimizing native-code compiler for C which is
so fast at generating code that it has a mode which accepts an initial
`#!' line in its input; the documentation refers to C `scripts'.

Awk, Javascript and Perl have full compilation phases too, but they're
hidden from the user; bash certainly builds a parse tree but I don't
know whether it just walks that or has some other kind of internal
representation.

 Maybe, once upon a time, there was a meaningful distinction to be made 
 between purely interpreted languages and purely compiled languages.

No, there never was; only between interpreting and compiling
implementations.


 But today, when interpreted languages have a compilation phase, and
 compiled languages have the equivalent of eval() and do their
 compilation at runtime, such a distinction is now fairly arbitrary.
 Better questions are:

 * Does the program compile to native machine code or byte code?

 * How efficient is the machine code, or the virtual machine that executes 
 the byte code? What do you mean by efficient?

 * Is there an integrated parse-compile-execute cycle, or does the 
 developer have to perform them individually?

 * To what degree is the syntax of the language aimed at rapid development 
 and/or runtime efficiency?

 Harder questions to ask, and answer, than Is that language for writing 
 scripts or programs or applications?, but the answers are far more 
 meaningful.

Maybe.  I note that there are Lisp systems (plural!) which compile to
native code (only -- with no interpreter at all), but fully support
runtime `eval', batch compilation of source files, aggressive
optimization for speed and/or space, and so on.  So I think that some of
the above questions, at least, present false dichotomies: one doesn't
have to choose one or the other; one can have cake and eat it too.

Also some of the questions are about the language and some are about the
implementation.  It's important not to get the two confused.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: how to use socket to get packet which destination ip is not local?

2010-11-17 Thread Mark Wooding
Hans hans...@gmail.com writes:

 I tried socket bind to 0.0.0.0, but it only binds to any local ip, not
 any ip which may not be local. therefore the socket cannot get that
 dhcp offer packet even I can use wireshark to see that packet did come
 to this pc.

You must use a raw socket for this.  Raw sockets are fiddly, not very
portable, and require privilege.  Sorry.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Some syntactic sugar proposals

2010-11-17 Thread Mark Wooding
Christopher nadiasver...@gmail.com writes:

 i don't like magic names. what about:

 t = foo() as v if pred(v) else default_value

This is an improvement on `it'; anaphorics are useful in their place,
but they don't seem to fit well with Python.

But I don't think that's the big problem with this proposal.  The real
problem is that it completely changes the evaluation rule for the
conditional expression.  (The evaluation rule is already pretty screwy:
Python is consistently left-to-right -- except here.)

Evaluating a conditional expression starts in the middle, by evaluating
the condition.  If the condition is true, then it evaluates the
consequent (to the left); otherwise it evaluates the alternative (to the
right).  Screwy, but tolerable.

The proposal is to evaluate the /consequent/, stash it somewhere,
evaluate the condition, and then either output the consequent which we
evaluated earlier or the alternative which we must evaluate now.

Of course, the implementation must be able to tell which of these
evaluation rules to apply.  The marker to look for is either `it'
(original anaphoric proposal -- this is the real reason why `it' should
be a reserved word: its presence radically alters the evaluation rule,
so it ought to be a clear syntactic marker) or `as' (as suggested
above).

Elsewhere in the language, `as' is pretty consistent in what it does:
it provides a name for a thing described elsewhere (a `with' context
object, or an imported thing) -- but nothing else.  It certainly doesn't
suggest a change in the way anything else is evaluated.

1/x if x != 0 else None

works for any numeric x; it'd be really surprising to me if

1/x as hunoz if x != 0 else None

didn't.

-1 on this one.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: simple(?) Python C module question

2010-11-17 Thread Mark Wooding
Mark Crispin nos...@panda.com writes:

 I have a Python module written in C that interfaces with an external C
 library.  Basically, the project is to make it possible to use that
 library from Python scripts.  If you know who I am, you can guess
 which library.  :)

You have your very own Wikipedia page, so others probably needn't guess.

 However, I now need to write a method that creates what the library calls a
 stream, and I need method calls to work on that stream.

 The obvious way to do this in any other OO language is to have an
 object that holds the stream from the library in an instance variable
 (which actually will be constant for that object instance), and has
 various object methods for operating on that stream.

Yeah, that's pretty much the way it works in Python, though it's a bit
more tedious.  (I suppose it's too late to suggest using Cython now.  It
makes this sort of thing much less unpleasant.)

 I assume that the object methods are defined by a PyMethodDef table,
 just as they are for the module.  But how do I:
  [1] define the object

You need two things here: a C structure to represent the innards of your
custom Python type, and a Python type block (a PyTypeObject) providing
everything the Python interpreter needs to know about it.

The C structure can be pretty much whatever you like, as long as it
begins with the macro PyObject_HEAD:

typedef struct thingy {
  PyObject_HEAD
  /* your stuff here; maybe: */
  stream *s;
} thingy;

The PyTypeObject is big and boring to fill in but you can probably leave
most of it null.  The structure is described in the Python API manual,
but I think you'll need to fill in:

  * a name for the type (qualified by your module's name; tp_name);
  * the object size (sizeof(thingy); tp_basicsize);
  * a deallocation function (tp_dealloc);
  * some flags (you probably want Py_TPFLAGS_DEFAULT and maybe
Py_TPFLAGS_BASETYPE if you don't mind people making subclasses;
tp_flags);
  * a string to be shown to the user if he asks for help about your type
(tp_doc);
  * a pointer to a methods table (tp_methods);
  * a pointer to a table of attribute getters and setters (if you want
to expose stuff as attributes rather than methods; tp_getset);
  * an allocator (probably PyType_GenericAlloc; tp_alloc); and
  * a function to construct a new instance (to be called when Python
tries to construct an object by calling the type -- leave it null if
you construct instances in some other way; tp_new).

You might also want to implement the tp_str function to provide useful
information about your object's state (e.g., for debugging scripts).
There are some standard protocols which might be useful to implement; it
doesn't sound like your streams would benefit from behaving like numbers
or sequences, but maybe they might be iterable.

You attach methods on the type by mentioning them in the PyMethodDef
table you set in tp_methods; they get a pointer to the recipient object
(a `thingy' as above) so they can find the underlying stream if they
want.  Getters and setters are pretty similar, but have a simpler
interface because they don't need to mess with argument parsing..

  [2] create an instance of the object with the stream and methods

If you want Python programs to be able to make streams by saying

stream = mumble.stream(...)

or whatever then you'll need to implement tp_new: this is pretty much
like a standard method, except it gets a pointer to a PyTypeObject to
tell it what kind of type to make.  (The constructor may be called to
construct a subclass of your type.)  Parse the arguments and check that
they're plausible; then make a new skeleton instance by

t = (thingy *)ty-tp_alloc(ty, 0);

(where ty is the type pointer you received), fill in your bits, and
return (PyObject *)t.

Otherwise, well, you go through the same procedure with tp_alloc, only
you know which type you want statically.

  [3] hook the object's destruction to a library stream-close function

This is the tp_dealloc function.  It should free up any of your
resources, and then say

obj-ob_type-tp_free(obj);

Python will have arranged for this function to exist if you left tp_free
as a null pointer.

 Python does NOT need to look at the stream in any way.  Ideally, the
 object is just a blob that only has method calls.

That's what you get anyway, if you use the C API.  If you want Python
programs to be able to poke about inside your objects, you have to let
them explicitly, and that means writing code.

 This ought to be simple, and not even require me to know much Python
 since basically the task is just this module and a few very basic
 Python scripts to use it.  Other people will be writing the real
 scripts.

It doesn't require you to know any Python at all.  It /does/ require a
certain familiarity with the implementation, though.

 Of course, I could just have the open method return the stream pointer
 as a big 

Re: Program, Application, and Software

2010-11-17 Thread Mark Wooding
Alexander Kapps alex.ka...@web.de writes:

 Application: Usually a large(er), complex program

I'd say that an `application' is specifically a program intended for
direct human use.  Other things are servers, daemons and utilities.  But
I might just be weird.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-15 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

  def foo():
l = []
for i in xrange(10):
  (lambda j: l.append((lambda: i, lambda: j)))(i)
print [(f(), g()) for f, g in l]

 Here's a slightly less condensed version that demonstrates the same 
 behaviour, but may be slightly easier to understand:

The output is the same but the reasons for it are different:

 def spam():
 a = []
 b = []
 for i in xrange(5):
 a.append(lambda: i)
 b.append(lambda i=i: i)

Here, you've replaced lambda-binding by a default argument value.

 print [f() for f in a]
 print [f() for f in b]

 In your function foo, the name i is bound to the objects 0, 1, 2, ... 9 
 sequentially, each time around the for-loop. Inside the loop, a function 
 object is created and then called:

 (lambda j: l.append((lambda: i, lambda: j)))(i)

 (Aside: this depends on scoping rules that were introduced quite late in 
 Python's history -- prior to version 2.2, this wouldn't work at all.)

Indeed.  The default-argument trick above was used to simulate it.  Not
coincidentally, it was around version 2.2 that Python became interesting
to me...

 The outer lambda:

 lambda j: l.append(...)

 has a name in the function namespace (a local variable) called j. On 
 entry to this function, this j is bound to the same object which is bound 
 to i *at the time that the function is called*. That is, each of the 
 sequence of outer lambdas get a distinct j = 0, 1, 2, ... 

Ahh.  You've invented a new concept of localness instead, which is
equivalent to the usual notion of binding.

 None of the function A0, A1, A2, ... have any local variable i.

i.e., i is free in the An functions and in the outer lambda...

 Functions B0, B1, B2, ... similarly have no local variable j. When you 
 call any of the Bs, Python looks in the enclosing scopes for a variable 
 j. However, in this case it *does* find one, in the outer lambda,

... but j is bound in the outer lambda.

This is not new terminology: it goes back to lambda calculus: a variable
x occurs free in a term T if

  * T is x;
  * T is U V where x occurs free in U or V; or
  * T is lambda y.U where y is not x and x occurs free in U.

If x occurs free in T then it occurs bound in lambda x.T.

See also SICP.

* Python's `for' loop works by assignment.  The name `i' remains bound
  to the same storage location throughout; 

 This is not necessarily true. It's true for CPython, where function 
 locals are implemented as fixed slots in the function object; since the 
 slot doesn't move relative to the function, and the function doesn't move 
 relative to the heap, the name i is in a fixed storage location for the 
 life of foo. But that's not necessarily the case for all implementations 
 -- locals could be stored in a data structure that moves data around 
 (say, a red-black tree), or objects could be free to move in the heap, or 
 both.

Don't be silly.  In a tree, the `location' would be the tree node
containing the corresponding key.  You're working at the wrong level of
abstraction.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-15 Thread Mark Wooding
Arnaud Delobelle arno...@gmail.com writes:

  exec a=2 in d
 assigning 2 to 'a'
  d['a']
 2

  exec global a; a = 3 in d
  d['a']
 3

Oooh, now isn't that an interesting wrinkle?  I've been careful (without
drawing attention) to restrict my arguments to variables inside
functions, largely because Python's global scopes work completely
differently.  (Python's global scopes work similarly to traditional Lisp
and Scheme, which isn't at all objectionable, but it's not the only way
of managing global scopes.  Queinnec's Lisp In Small Pieces describes
others.)

 So even if the globals() dictionary is custom, its __setitem__ method is
 *not* called.

Fascinating.  Thank you.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Some syntactic sugar proposals

2010-11-15 Thread Mark Wooding
Dmitry Groshev lambdadmi...@gmail.com writes:

 First of all: how many times do you write something like
 t = foo()
 t = t if pred(t) else default_value
 ? Of course we can write it as
 t = foo() if pred(foo()) else default_value
 but here we have 2 foo() calls instead of one. Why can't we write just
 something like this:
 t = foo() if pred(it) else default_value
 where it means foo() value?

How about

t = (lambda y: y if pred(y) else default_value)(foo(x))

You could even package the lambda into a named function if you get bored
of typing or your aesthetic senses are offended.

 And the third. The more I use python the more I see how natural it
 can be. By natural I mean the statements like this:
 [x.strip() for x in reversed(foo)]
 which looks almost like a natural language. But there is some
 pitfalls:
 if x in range(a, b): #wrong!
 it feels so natural to check it that way, but we have to write
 if a = x = b

This, I think, is your error.  The test `x in range(a, b)' means the
same as `a = x  b' (only in Python 2 it builds a list and then throws
it away again).  Such half-open intervals turn out to be what you want
most of the time, and I think you'll avoid many bugs if you embrace them
rather than trying to cling to the fully-closed intervals above.

Python very definitely made the right decision to use half-open
intervals pervasively, e.g., for `rangeand 'in sequence slicing.  It's a
bad idea to fight against it.

Advantages of half-open intervals [a, b):

  * The number of elements is exactly b - a; closed intervals contain an
extra element which is often forgotten.

  * They compose and split nicely: if a = c = b then [a, b) is exactly
the disjoint union of [a, c) and [c, b).

  * Sums over these intervals are often better behaved; indeed, there's
a rather pretty analogy between sums on half-open intervals and
definite integrals which is lost if you use closed intervals.  (The
above two observations are special cases of this one.)  See Concrete
Mathematics (Graham, Knuth, Patashnik) for more on this.

  * It's easy to express an empty interval.  You can't do that if you
work entirely with closed intervals, but empty sets are an important
boundary case and it's annoying to have to handle them separately.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-13 Thread Mark Wooding
Tracubik affdfsdfds...@b.com writes:

  def change_integer(int_value):
 ... int_value = 10
 ... 
 ... def change_list(list):
 ... list[0] = 10

[...]

 why the integer value doesn't change while the list value do?

Because in the first case you changed a variable local to the function,
and that variable was lost when the function returned; and in the second
case, you modified the list value that was passed to the function.

 in Pascal i can choose the behavour of parametres, how this work on
 Python?

You must learn to distinguish two notions to understand how this works
in Python: the notions are /assigning a value to a variable/, and
/mutating a value/.  The former is what simple assignment `foo = ...'
does: it makes the variable store a different value.  Assigning a value
to a function argument /never/ affects the caller in Python.  It's
simply not possible to write a `swap' function in Python.  The latter
means that a value itself changes but the relevant variables continue to
store the same values.

Alas, Python is actually slightly confusing here, since the same
notation `=' sometimes means assignment and sometimes means mutation.
You can tell which is which by looking at the left hand side: if it's a
simple variable name, the variable is assigned a new value; if it's
something more complicated (e.g., indexing (`foo[0]'), or attribute
selection (`foo.bar') then some mutation is (probably) going to happen:
these kinds of assignment are translated into method calls, so what
actually happens is up to the object in question.  It gets worse:
compound assignment -- statements like `foo += ...' -- might either be
mutation or assignment.  What happens if the current value of `foo' has
the an appropriate method is that the method is called, and probably
mutates the value of foo; otherwise Python treats the statement as if it
had been `foo = foo + (...)'.

Returning, sort of, to the point: if you want to write a function which
causes side-effects on its caller, then you have[1] to do it by mutating
the caller's argument values.  So you could write an awful `swap'
function like

def awful_swap(x, y):
  x[0], y[0] = y[0], x[0]

and then you have to call it as

xx = [x]
yy = [y]
awful_swap(xx, yy)
x = xx[0]
y = yy[0]

but there's no good reason to actually do such a thing in Python when
you can write

x, y = y, x

anyway.

In Pascal, one tends to use `var' parameters to work around the fact
that Pascal functions can only return a single value.  This is true in
Python too, but it isn't anywhere near as annoying because Python makes
it easy (a) to combine multiple values together into a tuple (`return x,
y, z') and (b) to pick tuples apart into their components again at the
other end (`a, b, c = some_function()').  If you have a number of values
which you find that you're combining and splitting apart repeatedly then
maybe you're better off putting them together in a class with some
appropriate operations.

[1] In general; if the called function happens to be lexically enclosed
in its caller, then it can play with its caller's variables
directly -- well, in Python 3, anyway.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-13 Thread Mark Wooding
Terry Reedy tjre...@udel.edu writes:

 On 11/13/2010 11:29 AM, Mark Wooding wrote:

  Alas, Python is actually slightly confusing here, since the same
  notation `=' sometimes means assignment and sometimes means mutation.

 I disagree somewhat. An object is mutated by an internal assignment.

Some object types are primitive, provided by the runtime system; there
are no `internal' variables to be assigned in these cases.  (It is
possible in principle in Python 3 to implement all of the compound data
types using only assignment and closures.)

 ll[0] = 1 assigns 1 to the 0 slot of ll.
 o.a = 1 assigns 1 to the 'a' attribute of o.
 This which might be implemented by assigning 1 to the 'a' slot of o.__dict__,
 just as a=1 might be implemented by assigning 1 to the 'a' slot of a
 namespace dict.

There's a qualitative difference here: simple assignment has semantics
defined by the language and provided by the implementation, and can
therefore be understood in isolation, using only lexically apparent
information; whereas the complex assignments are implemented by invoking
methods on the objects mentioned on the left hand side.  The objects in
question may choose not to implement some other semantics, so the
runtime behaviour might not be determinable even in principle without
actually executing the program.  (Compound assignment has the same
problem writ large.)

 Assignment *always* binds an object to a target.

No!  Assignment /never/ binds.  There is syntactic confusion here too,
since Python interprets a simple assignment in a function body -- in the
absence of a declaration such as `global' to the contrary -- as
indicating that the variable in question should be bound to a fresh
variable on entry to the function.  But assignment itself doesn't
perform binding.  (This is a persistent error in the Python community;
or, less charitably, the Python community gratuitously uses the word in
a different sense from the wider programming-language-theory community.
See Lisp literature passim, for example.)

There's a two step mapping: names - storage locations - values.
Binding affects the left hand part of the mapping; assignment affects
the right hand part.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-13 Thread Mark Wooding
Dave Angel da...@ieee.org writes:

 No, an (=) assignment is always an assignment.  

No.  In `foo[0] = bar' it's a method call in disguise.

 It changes the item on the left hand side to refer to a new object.

Not necessarily.  It could do anything at all depending on the type of
the recipient object.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-13 Thread Mark Wooding
Arnaud Delobelle arno...@gmail.com writes:

 m...@distorted.org.uk (Mark Wooding) writes:

  Assignment /never/ binds.  There is syntactic confusion here too,
  since Python interprets a simple assignment in a function body -- in
  the absence of a declaration such as `global' to the contrary -- as
  indicating that the variable in question should be bound to a fresh
  variable on entry to the function.  But assignment itself doesn't
  perform binding.  (This is a persistent error in the Python community;
  or, less charitably, the Python community gratuitously uses the word
  in a different sense from the wider programming-language-theory
  community.  See Lisp literature passim, for example.)
 
  There's a two step mapping: names - storage locations - values.
  Binding affects the left hand part of the mapping; assignment affects
  the right hand part.


 I'm not sure the notion of storage location is useful in Python.

We'll see.

 I think I understand Python programs correctly using only the notions
 of name and value (or object).

Challenge: explain the following code using only those concepts.

def foo():
  l = []
  for i in xrange(10):
(lambda j: l.append((lambda: i, lambda: j)))(i)
  print [(f(), g()) for f, g in l]

I explain this as follows.

  * Python's `for' loop works by assignment.  The name `i' remains bound
to the same storage location throughout; this binding is established
on entry to the function.  Since `i' is not rebound in any function
lexically enclosed in `foo', every occurrence of `lambda: i' refers
to this same storage location.  At the end of the loop, this storage
location contains the value 9.

  * The name `j' is rebound repeatedly: in each iteration of the `for'
loop, the function `lambda j: ...' is invoked, binding `j' to a
fresh storage location into which the value of `i' at the time is
stored.  Since the function `lambda: j' is lexically enclosed within
this function, the name `j' refers to a different storage location
in each of these functions, these storage locations are initialized
with distinct values 0 up to 9, and they are never changed.

  * Therefore each `lambda: i' function, when called after the loop,
outputs the same value 9; and each `lambda: j' function, when called
after the loop, outputs a distinct value.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-13 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

 On Sat, 13 Nov 2010 20:01:42 +, Mark Wooding wrote:
  Some object types are primitive, provided by the runtime system;
  there are no `internal' variables to be assigned in these cases.

 You seem to be making up your own terminology here, or at least using 
 terminology that isn't normally used in the languages I'm used to.

I was attempting to define possibly unfamiliar terms as I went along.
Did you not notice?

 If you mean primitive in the sense of built-in, your conclusion is 
 wrong. Such primitive types include dicts and lists,

Yes, those are precisely the ones I was thinking of.

 which are sophisticated container objects with internal variables to
 be assigned to:

They have internal state.  I don't think that internal state consists of
(Python) variables, though.  This is why I brought up the possibility of
a pure Python implementation, maintaining its state by assigning to
variables captured using closures.

  There's a qualitative difference here: simple assignment has semantics
  defined by the language and provided by the implementation, and can
  therefore be understood in isolation, using only lexically apparent
  information; whereas the complex assignments are implemented by invoking
  methods on the objects mentioned on the left hand side.

 Again, you're using unfamiliar terminology.

I'm sorry.  I thought I defined those terms recently.  (It appears not.
Sorry.)  I meant to refer to assignments in which the target is an
identifier (to use the actual terminology from the manual).

 Simple and complex assignment -- I can guess you mean name
 binding = simple and any other reference binding = complex in
 Python terminology:

Again: assignment is not binding.  See the explanation below.

 The thing is, the semantics of assigning to built-in components are
 equally defined by the language as the semantics of name binding.

Did you read what I said?

 You are right to point out that for arbitrary types:

 x[2] = 5

 need not be an assignment, 

Good.  This was /precisely/ what I was pointing out: determining
/whether/ the value named by an identifier inhabits one of the built-in
types is, in general, hard.

 The distinction between the two count as an important proviso to the
 discussion: x[2] = 5 is only an assignment if the type of x is
 non-pathological and not broken.

The latter is not an assignment: it's a disguised method call.

 But putting aside such pathological cases, I don't think you can justify 
 distinguishing between simple and complex assignment.

To conflate them is to confuse two different levels of meaning.  Simple
assignments occur because the language is hard-wired that way; complex
assignments are disguised method calls which often mutate values.

 Names are only one type of reference in Python, not the only one, and
 assignments other than name-binding can be fully understood from the
 language semantics *provided you know the type is a built-in*.

  Assignment *always* binds an object to a target.
  
  No!  Assignment /never/ binds.

 A shocking claim that requires more explanation. If it doesn't bind,
 what does it do?

Duh!  It assigns.  You're not usually this slow.  Fortunately I explain
below.

  There is syntactic confusion here too, since Python interprets a
  simple assignment in a function body -- in the absence of a
  declaration such as `global' to the contrary -- as indicating that
  the variable in question should be bound to a fresh variable on
  entry to the function.

 Well, there seems to be some confusion here, but I don't think it's 
 ours... local variables in functions aren't bound on *entry* to the 
 function. How could they be? They are bound *when the assignment is 
 executed*, which may be never -- hence it is possible to get an 
 UnboundLocalError exception, if you try to retrieve the value of a local 
 which hasn't yet had a value bound to it.

The exception name perpetuates the misunderstanding, alas; but it's
traditional, from Lisp, to say that a variable is `unbound' if it
contains no value.

  But assignment itself doesn't perform binding.  (This is a
  persistent error in the Python community; or, less charitably, the
  Python community gratuitously uses the word in a different sense
  from the wider programming-language-theory community.  See Lisp
  literature passim, for example.)

 *Less* charitably? I'm sorry, you think that being *wrong* is better
 than being *different*? That's not a moral judgment I can agree with.

Being wrong is perhaps justifiable, and is rectifiable by learning.
Being gratuitously different in such a case is to intentionally do a
disservice to those coming from or going to other communities where they
encounter more conventional uses for the terms in question.

  There's a two step mapping: names - storage locations - values.
  Binding affects the left hand part of the mapping; assignment affects
  the right hand part.

 That gratuitously

Re: strange behavor....

2010-11-13 Thread Mark Wooding
Dennis Lee Bieber wlfr...@ix.netcom.com writes:

 def swapFunc(a, b):
   return b, a

That's not what a `swap' function should do.

  Alas, Python is actually slightly confusing here, since the same
  notation `=' sometimes means assignment and sometimes means mutation.

   = means just one thing, a rebinding of some identifier to a
 different object.

Names aren't bound to objects.  See elsewhere.

   Or, in more general, = rebinds the fully qualified name to a
 different object, which has the result of mutating a partially qualified
 name (a name whose suffix has be removed).

Names aren't mutated at all.  Values (or, synonymously, objects) are
mutated.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: strange behavor....

2010-11-13 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

 On Sat, 13 Nov 2010 21:42:03 +, Mark Wooding wrote:

  Dave Angel da...@ieee.org writes:
  
  No, an (=) assignment is always an assignment.
  
  No.  In `foo[0] = bar' it's a method call in disguise.

 How does that imply that can't also be an assignment?

Is `splat(34)' an assignment?  If so, I think the term's meaning is
grievously diluted.  I'd rather say that `splat(34)' might mutate a
value, or have side effects, and reserve the term `assignment' for the
job of explaining how variables work.  That seems pretty tricky, because
we're arguing about it a lot, so I think we need sharply defined
concepts so that we don't get more confused than we have to be.

 Of course, you're correct that it's not *necessarily* an assignment,

[...]

 I don't think it helps to overload newbies struggling with the basics
 with such pathological cases though.

I think that we're better off giving `newbies' a conceptual framework
which is robust, so that they can understand pathological situations
when they occur.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to test if a module exists?

2010-11-11 Thread Mark Wooding
r0g aioe@technicalbloke.com writes:

 Really? I get a metric butt-ton of spam every day to this address.

I'm sure I get sent a lot of spam (though I don't know for sure -- see
below).  But I don't think much of it comes from Usenet harvesters any
more.

 Right now it simply filtered by address straight into my recycle bin,
 I suppose if it ever becomes burdensome or starts to choke my
 bandwidth I'll tell my mailserver to bounce it :)

Don't do that.  Get your mailserver to /reject/ spam during SMTP with a
5xx code.  Bouncing spam is really bad because it implicitly assumes
that the envelope sender address is good.  Spam rarely has a valid
envelope sender.  If you're lucky, the envelope sender is simply
invalid, and you'll end up with a double-bounce when your mailserver
finds out.  If you're unlucky, the envelope sender is a /valid/ address
from the spammer's list and some innocent victim will end up receiving
your bounce (this is called `backscatter').

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to test if a module exists?

2010-11-11 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message mailman.894.1289510633.2218.python-l...@python.org, MRAB wrote:

  ... the next one at 3 Nov 2010 22:40 Re: Allowing comments after the line
  continuation backslash and _all_ the subsequent ones arrived with an
  _unobfuscated_ email address.

 You mean from this one on
 http://mail.python.org/pipermail/python-list/2010-November/1259515.html?

No.  More like http://article.gmane.org/gmane.comp.python.general/677953

We'll accept your apologies now.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to test if a module exists?

2010-11-10 Thread Mark Wooding
r0g aioe@technicalbloke.com writes:

 You use your main address on USENET rather than a junk one!? Obfuscated or
 not that's either brave or foolhardy!

I use my real email address.  I also have an aggressive spam filter.
But I don't think that much of my comes from Usenet harvesters any more,
to be honest.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Am I The Only One Who Keeps Reading ?Numpy? as ?Numpty??

2010-11-10 Thread Mark Wooding
Lou Pecora pec...@anvil.nrl.navy.mil writes:
 Bigger question:  How do you pronouce it?

Rhymes with `grumpy'.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: subclassing str

2010-11-10 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message 87lj52kwln.fsf@metalzone.distorted.org.uk, Mark Wooding 
 wrote:

  One option is to implement a subclass which implements the additional
  protocol.

 This is why I think object orientation ruins your ability to think
 properly.  For “protocol” read “function”. If you want to implement a
 new function, then implement a new function, why do you have to go
 through this “subclassing” malarkey just to do something so simple.

Functions don't do type-dependent dispatch, which was, of course, the
whole point.

A `protocol' is a collection of messages understood by a number of
different kinds of objects, causing potentially object-specific
behaviour.  I gave the explicit example of serialization: string
probably serializes differently from an integer or a list.  The
`__str__' and `__repr__' methods form a simple protocol for object
printing, as an additional example.  The `str' and `repr' functions
provides a potentially useful external entry points into the protocol,
but they work by doing a type-dependent dispatch on the argument --
calling the appropriate method.

Object orientation isn't useless or an impediment to clear thinking.  It
does seem to have turned into a bizarre kind of religion by some, and
many `mainstream' languages provide very poor object orientation
features (yes, Java and C#, I'm looking at you).  But OO can be useful.

I think the notion of `protocol' is central to coherent OO design, but
this seems largely overlooked in much of the literature I've read.  This
may mean that many people are muddled about what OO is actually for.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Allowing comments after the line continuation backslash

2010-11-10 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message 878w12kt5x.fsf@metalzone.distorted.org.uk, Mark Wooding 
 wrote:
2. The MainWindow class only has the `Window' attribute described in
   its definition.  Apparently there are other attributes as well (the
   ColorMumbleList family for one, also `LayerDisplay').  Similarly,
   the LoadedImage class has attributes `Contents' and `FileName', but
   I see attributes `RowStride', `ImageDrawSize' and `SrcDimensions'
   used immediately below.

 These are really just namespaces, one for the GUI context and the other for 
 the image data.

I think my point was about the rather selective documentation of the
namespaces.  The trivial-class trick is something I use myself (though
usually to simulate a structure rather than just to carve up namespace)
so I don't find it objectionable in and of itself.

3. In SelectSaveMenu, there's a curious `for' loop:
  
  for State in (gtk.STATE_NORMAL,) : # no need for
  gtk.STATE_INSENSITIVE
## blah
  
   Firstly, this is obviously equivalent to `state = gtk.STATE_NORMAL'
   followed by the loop body (YAGNI).

 It’s a tuple of one element. It used to be a tuple of two, and there is the 
 possibility it might need to become that again (as intimated at in the 
 attached comment). That’s why it stays a tuple.

I guessed the history.  I'm in two minds about this sort of thing.  I
/like/ history: I'm fascinated by the history of old programs and
programming languages; but looping over a single thing just seems weird.

   Of course, being boilerplate, the similarities visually outweigh the
   differences, when in fact it's the differences that are
   interesting.

 That is generally how code reuse works. All the “boilerplate” is in the 
 function definition, so I just have to call it parameterized by the 
 differences appropriate to each instance.

Except that's not the case.  There are extremely close similarities
between the six calls which strongly suggest (to me, anyway) that
further factoring would be beneficial.  I detest writing anything more
than once, and don't much enjoy playing spot-the-difference when reading
code.  The six calls are a screenful of spot-the-difference.

   It doesn't help that all of the names of the things involved are so
   wretchedly verbose.

 Oh please, no. Since when are explanatory names “wretchedly verbose”?

When the start and end bits are the same and the different bits are
hidden in the middle.  After staring at a screenful of
MainWindow.MumbleDisplay my head starts spinning.

   How about the following?
  
  def make_listview_l1 ...

 And what, pray tell, is the significance of the name “make_listview_l1”? If 
 there is something I would describe as “wretched”, it is the use of random 
 numerical suffixes like this.

It's a terse reference to List1Box (your name).  Since it was only being
used in the following two lines, I figured the name didn't matter much.
(In Lisp, I'd have wrapped the two lines in FLET and simply called the
function FROB.)

  Looking at some of the rest of the code, it might (or might not) be
  worthwhile actually making a class to gather together a list's model
  and view; subclasses can then vary their individual parameters, and
  the various colour lists can also keep the various captions with
  them.

 Most of that variation is already handled without the limitations of 
 thinking in classes. For example, selection of a colour in all three lists 
 is handled through a single EditColor routine. And of course you’ve already 
 seen how a single DefineScrollingList routine can be used to set up all the 
 scrolling lists used in this GUI.

There's so much commonality in the arguments that I'm not convinced that
they're fully factored.  Worse, there are several tables involving your
various ColorMumbleLists: adding another would require fiddling with all
of them, which suggests that things have been sliced up the wrong way.
(I'm aware in this instance that the set of such things is externally
constrained in this case.)  Maybe packaging all of the information about
each individual list in one object and having a list of these objects
would be better.

5. Much of the indentation and layout is rather unconventional, though
   not intolerable.  But I found (deep in `SelectSaveMenu'):
  
  NewRenderPixels = array.array \
(
  B,
  FillColor
  *
  (ImageRowStride // 4 * ImageBounds[1])
)
  
to be most disconcerting.

 Is the structure of the expression not apparent to you?

No, it really isn't.  Oddly enough, I'd find

(setf new-render-pixels
  (array:array B
   (* fill-color
  (floor image-row-stride 4)
  (aref

Re: How to test if a module exists?

2010-11-10 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 I see that you published my unobfuscated e-mail address on USENET for all to
 see. I obfuscated it for a reason, to keep the spammers away. I'm assuming
 this was a momentary lapse of judgement, for which I expect an apology.
 Otherwise, it becomes grounds for an abuse complaint to your ISP.

Don't be silly!  If anything, using forged email addresses in Usenet
headers is closer to abuse.  Note that there's nothing to stop
`new_zealand' from becoming a TLD at some point (the underscore makes it
unlikely, I grant).  If you'd mangled the local part, or used an
explicitly reserved TLD such as `example', then there wouldn't be a
problem.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Pythonic/idiomatic?

2010-11-09 Thread Mark Wooding
Seebs usenet-nos...@seebs.net writes:

   ' '.join([x for x in target_cflags.split() if re.match('^-[DIiU]', x)])

 This appears to do the same thing, but is it an idiomatic use of list
 comprehensions, or should I be breaking it out into more bits?

It looks OK to me.  You say (elsewhere in the thread) that you're stuck
with 2.4 compatibility.  I'd personally avoid the regexp, though, and
write this (actually tested with Python 2.4!):

' '.join(i for i in target_cflags.split()
   for p in 'DIiU' if i.startswith('-' + p))

 You will note that of course, I have carefully made it a one-liner so I
 don't have to worry about indentation*.

I failed at that.  You have to put up with my indentation.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Compare source code

2010-11-09 Thread Mark Wooding
Arnaud Delobelle arno...@gmail.com writes:

 python-mode has python-beginning-of-block (C-c C-u) and
 python-end-of-block.

Yes.  It was one of my explicit gripes that editing Python requires one
to learn entirely new and unfamiliar keystrokes for doing fairly
familiar editing tasks.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: functions, list, default parameters

2010-11-09 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message mailman.608.129032.2218.python-l...@python.org, Robert Kern 
 wrote:
  So examining LHS selectors is not sufficient for determining
  immutability.

 Yes it is. All your attempts at counterexamples showed is that it is not 
 necessary, not that it is not sufficient.

You've got them the wrong way around.  A is sufficient for B if and only
if B is true whenever A is true; i.e., it is never the case that A is
true and B is false.  In this case, we also say that B is necessary for
A.

See also http://en.wikipedia.org/wiki/Necessary_and_sufficient_condition

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Silly newbie question - Caret character (^)

2010-11-09 Thread Mark Wooding
Philip Semanchuk phi...@semanchuk.com writes:

 What's funny is that I went looking for a printed copy of the C
 standard a few years back and the advice I got was that the cheapest
 route was to find a used copy of Schildt's Annotated ANSI C Standard
 and ignore the annotations. So it serves at least one useful purpose.

The book was much cheaper than a copy of the C standard from ANSI or ISO
even when it was new.  It was a common joke (HHOS) at the time that the
difference in price reflected the value of the annotations.

(It also has two errors in the actual text of the standard.  There's a
character missing in the syntax summary, and one page was omitted
entirely, replaced by a copy of the previous page: my copy came with a
corrected page ineptly glued in at the relevant place.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: subclassing str

2010-11-09 Thread Mark Wooding
rantingrick rantingr...@gmail.com writes:

 One thing i love about Python is the fact that it can please almost
 all the religious paradigm zealots with it's multiple choice
 approach to programming. However some of the features that OOP
 fundamentalists hold dear in their heart are not always achievable in
 a clean manner with Python. Yes you could use a function but that is
 not the OOP way.

It can be more than just an aesthetic difference.  Sometimes it can be
nice to extend existing classes to understand additional protocols.  For
example, suppose you're implementing some object serialization format:
it'd be really nice if you could add `serialize' methods to `str',
`int', `list' and friends.  This is certainly the Smalltalk way.
Unfortunately, you can't do it in Python.

One option is to implement a subclass which implements the additional
protocol.  This causes fragmentation: now each protocol wants its own
subclass: if you want an object which understands both protocols, you
need to mess with multiple inheritance[1] (and, in Python, at least,
hope that everyone is using `super' properly to implement upwards
delegation).

Otherwise you have to do the dispatch yourself, either by hand or by
using one of the generic function/multimethod frameworks.

[1] At least Python gives you a fighting chance of getting this to work.
Java and C# won't countenance multiple inheritance at all, and C++
will botch it all by giving you a separate copy of the common
superclass's state for each protocol implementation (what are the
chances that everyone decided to use a virtual base class?) /and/
hideously breaking upwards delegation.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: populating a doubly-subscripted array

2010-11-09 Thread Mark Wooding
Gregory Ewing greg.ew...@canterbury.ac.nz writes:

 A reasonably elegant way to fix this is to use list comprehensions
 for all except the innermost list:

ff = [[0.0]*5 for i in xrange(5)]

Yes, this is a good approach.  I should have suggested something like
this as a solution myself, rather than merely explaining the problem.

 If you're computing heavily with arrays, you might also consider
 using numpy arrays instead of lists.

Also a good idea.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Allowing comments after the line continuation backslash

2010-11-09 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message 87fwvdb69k.fsf@metalzone.distorted.org.uk, Mark Wooding
 wrote:
  for descr, attr, colours in [
  ('normal',  'image','Normal'),
  ('highlighted', 'highlight','Highlighted'),
  ('selected','select',   'Selected')]:
colourlist = getattr(MainWindow, 'Colors%sList' % colours)
## ...

 But then you lose the ability to match up the bracketing symbols. 

You're right.  I do.

 That’s why I put them on lines by themselves.

But the bracketing symbols are thoroughly uninteresting!  All that
putting them on their own lines achieves is to draw attention to the
scaffolding at the expense of the building.  It's great if you like the
Pompidou Centre, I suppose...

Besides, any editor worth its salt will highlight bracket mismatches for
the reader, or at least get its automatic indentation in a twist if you
get the brackets wrong.

 Maybe you should look at the code in context
 https://github.com/ldo/dvd_menu_animator, then you can express some
 more opinions on how to improve it.

  1. class keyval: `are there official symbolic names for these
 anywhere?'  The gtk.keysyms module contains `Return', `KP_Enter',
 `Left', `Up', `Right', and `Down'.  Question: why are `returnkey'
 and `enterkey' defined in hex and the others in decimal?

  2. The MainWindow class only has the `Window' attribute described in
 its definition.  Apparently there are other attributes as well (the
 ColorMumbleList family for one, also `LayerDisplay').  Similarly,
 the LoadedImage class has attributes `Contents' and `FileName', but
 I see attributes `RowStride', `ImageDrawSize' and `SrcDimensions'
 used immediately below.

  3. In SelectSaveMenu, there's a curious `for' loop:

for State in (gtk.STATE_NORMAL,) : # no need for gtk.STATE_INSENSITIVE
  ## blah

 Firstly, this is obviously equivalent to `state = gtk.STATE_NORMAL'
 followed by the loop body (YAGNI).  Secondly, the loop is followed
 by an `#end if' comment.  If you're going to write the things, at
 least get them right!

  4. Ahh!  I've tracked down where the MainWindow is actually
 populated.  Ugh.  The code appears to revel in boilerplate.  (For
 those at home, we're now looking at `SetupMainWindow', specifically
 at the calls to `DefineScrollingList'.)  I count six calls, each
 nearly (but not quite) identical, of about eleven lines each.  Of
 course, being boilerplate, the similarities visually outweigh the
 differences, when in fact it's the differences that are
 interesting.

 It doesn't help that all of the names of the things involved are so
 wretchedly verbose. How about the following?

def make_listview(label, render, colattr, head, bounds, osc, box):
  setattr(MainWindow, label + 'Display',
  DefineScrollingList(getattr(MainWindow, label + 'List'),
  0, render, colattr, head,
  bounds, osc, box)
  
def make_listview_l1(label, head, osc):
  make_listview(label, None, 'text, head, (160, 160), osc, List1Box)
make_listview_l1('Button', 'Buttons', None)
make_listview_l1('Layer', 'Button Layer', LayerSelectionChanged)

MainWindow.colourlist = {}
MainWindow.colourview = {}
for head in ['Normal', 'Highlight', 'Select']:
  MainWindow.colourlist[head] = gtk.ListStore(gobject.TYPE_PYOBJECT)
  MainWindow.colourview[head] = \
DefineScrollingList(MainWindow.colourlist[head],
0, ColorCellRenderer(), None,
head, (120, 120), None, List2Box)

make_listview('LoadedColors', ColorCellRenderer(), None, '',
  (120, 240), None, MiddleBox)

Looking at some of the rest of the code, it might (or might not) be
worthwhile actually making a class to gather together a list's model
and view; subclasses can then vary their individual parameters, and
the various colour lists can also keep the various captions with
them.  (Sometimes a strong separation between model and view is a
good thing; this doesn't seem to be one of those times.)

  5. Much of the indentation and layout is rather unconventional, though
 not intolerable.  But I found (deep in `SelectSaveMenu'):

NewRenderPixels = array.array \
  (
B,
FillColor
*
(ImageRowStride // 4 * ImageBounds[1])
  )

  to be most disconcerting.  Also, I couldn't work out why some
  parens are indented only two spaces and others are indented the
  full eight.  Oh!  It's inconsistent tab/space selection.

I'm afraid that about this point I had to get on with some other stuff.

I've done enough throwing

Re: Allowing comments after the line continuation backslash

2010-11-09 Thread Mark Wooding
Tim Chase python.l...@tim.thechases.com writes:

 On 11/09/10 18:05, Robert Kern wrote:
  For me, putting the brackets on their own lines (and using a
  trailing comma) has little to do with increasing readability. It's
  for making editing easier.

 It also makes diff's much easier to read (my big impetus for doing the
 same as Robert)

Hmm.  That's a good point, actually.  I'm not overly fussed about the
ease of editing: it doesn't seem especially hard either way.  But nice
diffs are definitely valuable.  Food for thought; thanks.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Popen Question

2010-11-08 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message ib0kor01...@news5.newsguy.com, Chris Torek wrote:

  ['/bin/sh', '-c', 'echo', '$MYVAR']
  
  (with arguments expressed as a Python list).  /bin/sh takes the
  string after '-c' as a command, and the remaining argument(s) if
  any are assigned to positional parameters ($0, $1, etc).

 Doesn’t work.

What doesn't work?  You were being given an explanation, not a solution.

 I don’t know what happens to the extra arguments, but they just seem
 to be ignored if -c is specified.

The argument to -c is taken as a shell script; the remaining arguments
are made available as positional parameters to the script as usual (only
starting with $0 rather than $1, for some unknown reason).

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: populating a doubly-subscripted array

2010-11-08 Thread Mark Wooding
g...@accutrol.com writes:

 What am I missing?  I am using Python 3.1.2.

 ff = [[0.0]*5]*5
 ff#(lists 5x5 array of 0.0)
 for i in range(5):
   for j in range(3):
 ff[i][j] = i*10+j
 print (i,j,ff[i][j])  # correctly prints ff array values

 ff# try this and see what happens!

 result of third print of ff
 [[40, 41, 42, 0.0, 0.0], [40, 41, 42, 0.0, 0.0], 
 [40, 41, 42, 0.0, 0.0], [40, 41, 42, 0.0, 0.0], 
 [40, 41, 42, 0.0, 0.0]]

 Obviously there is something missing in my understanding of 
 how array values are populated.  Why do all rows get 
 populated with the same set of values (40, 41, 42)?  

[I suppose that the trailing 0.0 entries aren't in question: they're
because the individual rows have width 5 -- from `[0.0]*5' -- but only
the first three items of each is initialzed -- because j iterates only
over range(3).]

So, why do they all come out the same?  The answer is because in fact
there are only two lists involved.  You probably thought that you were
building something like the thing on the left.  In fact, you have the
thing on the right.  (Try to forgive the rubbish ASCII art.)

.--..--.--.--.--.--..--.
| -|  |  |  |  |  || --.
|__|`--^--^--^--^--'|__| \
|  |.--.--.--.--.--.|  |  \
| -|  |  |  |  |  || ---. \
|__|`--^--^--^--^--'|__|  \v 
|  |.--.--.--.--.--.|  |   \.--.--.--.--.--.
| -|  |  |  |  |  || -|  |  |  |  |  |
|__|`--^--^--^--^--'|__|   /`--^--^--^--^--'
|  |.--.--.--.--.--.|  | /  ^
| -|  |  |  |  |  || --'  /
|__|`--^--^--^--^--'|__|  /
|  |.--.--.--.--.--.|  | /
| -|  |  |  |  |  || --'
`--'`--^--^--^--^--'`--'

What [x] * n does is make a list, whose length is n, and all of whose
entries are precisely the value x.  If x itself is a list, then you get
an outer list all of whose entries are the /same/ inner list -- not
copies of it.  So when you appear to change entries in one of the inner
lists, all the other inner lists seem to change too -- because they're
actually the same list.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Compare source code

2010-11-07 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 I would never do that. “Conserving vertical space” seems a stupid reason for 
 doing it.

Vertical space is a limiting factor on how much code one can see at a
time.  I use old-fashioned CRT monitors with 4x3 aspect ratios and
dizzyingly high resolution; I usually work with two columns of code, but
can get four if I give up on things like xterms.  I still find it rather
limiting: I have to remember everything which won't fit on the screen.

I've no idea how people manage with these ridiculous widescreen monitors.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Silly newbie question - Carrot character (^)

2010-11-07 Thread Mark Wooding
Nobody nob...@nowhere.com writes:

 You're taking how too literally, so let me rephrase that:

   A reference manual tells you what you need to know in order to use
   the language. A specification tells you what you need to know in
   order to implement it.

I still don't see those as being different.

A language reference should set out all of the details of the language
syntax and semantics.  It should answer every question of the form `what
happens if I write this?'  In so doing, it /must/ also provide enough
information for an implementer to write an new implementation.

 A tutorial provides an overview of the language, but won't necessarily
 describe every aspect (maybe not even close), and is generally
 designed to be read in order.

Agreed.

 A reference manual would describe whatever you need to know in order
 to use the language. It shouldn't omit anything short of the you
 are not expected to understand this level. IOW, any omissions
 shouldn't matter unless you are e.g. writing analysis utilities which
 need to accept /any/ valid program and interpret it correctly.

`Using' a language involves two activities: writing it, and reading it.
You're only considering one of those activities, and I think it's the
less important one.

 E.g. a reference manual would need to describe indentation, but
 details such as the interpretation of a mixture of tabs and spaces can
 be limited to don't do this, whereas a specification would need to
 either specify the details or at least specify that it invokes
 undefined behaviour.

I'm confronted with some code, written by someone else, and when I run
it I get an unexpected result.  The language reference should be able to
explain to me precisely why I get the result that I see.  If it can't,
it's of no value.

 I'm arguing that the reference manual reads too much like a specification.
 E.g. look at 5.2.4. List displays and tell me whether you consider that
 it adequately /explains/ list displays to someone wishing to use them.

It doesn't adequately specify them either.  That section is just poorly
written.

 I note that the reference manual contains very few examples. For a
 specification, this would be quite normal, as examples can serve to
 undermine precision. For a reference manual, precision has to be traded
 for clarity, which may mean using examples where appropriate.

I disagree with both claims.  Examples cannot undermine precision: if
the normative text is correct then an example can only demonstrate an
application of the specified rules.  If the normative text is wrong then
the specification is broken and needs fixing.

But the same applies to a reference.  Either it supplies enough detail
to answer every question about how programs behave or it's broken:
precision is essential here, but is not -- and cannot -- be compromised
by adding examples.

 OTOH, a tutorial often contains little more than a sequence of examples
 along with informal explanations as to their structure and functioning. As
 a result, tutorials tend to lack precision; they provide specific cases
 which will work and some clues as to what else is likely to work.

Yes, I'm familiar with the `leave the reader to fill in the gaps in my
exposition for himself' approach to documentation -- and with the
unenjoyable task of fixing the reader's confused mental model
afterwards.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Allowing comments after the line continuation backslash

2010-11-07 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 Not surprising, since the above list has become completely divorced from its 
 original purpose. Anybody remember what that was? It was supposed to be used 
 in a loop, as follows:

 for \
 Description, Attr, ColorList \
 in \
 (
 (normal, image, MainWindow.ColorsNormalList),
 (highlighted, highlight, MainWindow.ColorsHighlightedList),
 (selected, select, MainWindow.ColorsSelectedList),
 ) \
 :
...
 #end for

 Does this make more sense now?

Ugh, no!

for descr, attr, colours in [
('normal',  'image','Normal'),
('highlighted', 'highlight','Highlighted'),
('selected','select',   'Selected')]:
  colourlist = getattr(MainWindow, 'Colors%sList' % colours)
  ## ...

To be honest, there's so much regularity in that table that I'd consider
generating it from a shorter list.  This would obviously involve
refactoring something else to eliminate the image/normal asymmetry.  I'd
also consider making the ColorsMumbleList attribute collection into a
dictionary.

Note that my columns are aligned to 8-column tab stops for easy
maintenance (although my editor has used physical spaces rather than
tabs).

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Compare source code

2010-11-06 Thread Mark Wooding
Rustom Mody rustompm...@gmail.com writes:

 As for tools' brokeness regarding spaces/tabs/indentation heres a
 thread on the emacs list wherein emacs dev Stefan Monnier admits to
 the fact that emacs' handling in this regard is not perfect.

 http://groups.google.com/group/gnu.emacs.help/browse_thread/thread/1bd0c33a3e755730/89cbd920ee651b5a?q=tabs+stefan+spaces+group:gnu.emacs.help#89cbd920ee651b5a

You've misunderstood.  That discussion is about configuring Emacs to not
do automatic indentation when the `tab' key is pressed or when
language-specific punctuation is entered.  It has very little to do with
tab characters in files.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: functions, list, default parameters

2010-11-06 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

 On Fri, 05 Nov 2010 12:17:00 +, Mark Wooding wrote:
  Right; so a half-decent compiler can notice this and optimize
  appropriately.  Result: negligible difference.

 Perhaps the biggest cost is that now your language has inconsistent 
 semantics: some function defaults are set on every call, and some are set 
 once, when the function is defined, and the choice between the two 
 happens via magic -- the compiler decides what to do, you don't.

The /semantics/ are indistinguishable.  The implementations are
different, and I'll grant that the performance model is more complex for
optimized DIC.

 I have mixed feelings about compiler optimizations. Things like constant 
 folding seems to be both harmless and useful, but other optimizations not 
 so much. It sets up a discrepancy between what the source code does and 
 what the compiled code does, and in the case of (say) floating point 
 code, can introduce *serious* bugs.

Oooh, careful now.  It's important not to muddle semantics-preserving
transformations (like memoizing constant immutable objects, as I'm
suggesting, or constant folding) and tolerated semantics-altering
transformations such as increasing precision of intermediate
floating-point values.  (`Tolerated' here means that some language
specifications grant specific permission for these optimizations despite
the fact that they don't preserve semantics.)

Semantics-altering optimizations are scary, to be approached only with
great trepidation.  Semantics-preserving optimizations are nearly free,
except for the potentially complicated performance model.

  _missing = ['missing']

 A curious choice for the sentinel value. We're not using Python 1.5 any 
 longer :)

Two reasons.  Firstly, this comes from my Lisp background: making a list
is the obvious way of producing an unforgeable object.  Secondly, if you
see an objects that prints as ['missing'], you have a chance of working
out where it came from; for a loose object() that's kind of hard without
a wabbit hunter.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: functions, list, default parameters

2010-11-06 Thread Mark Wooding
Dennis Lee Bieber wlfr...@ix.netcom.com writes:

 On Sat, 06 Nov 2010 12:37:42 +, m...@distorted.org.uk (Mark Wooding)
 declaimed the following in gmane.comp.python.general:

  
  Two reasons.  Firstly, this comes from my Lisp background: making a
  list is the obvious way of producing an unforgeable object.
  Secondly, if you see an objects that prints as ['missing'], you have
  a chance of working out where it came from; for a loose object()
  that's kind of hard without a wabbit hunter.
 
   I think the Python form is to create a basic class instance, a la

  class Sentinal(object):
 ...   pass
 ... 
  _missing = Sentinal()
  print _missing
 __main__.Sentinal object at 0x011F01B0

No, that doesn't tell me where it came from at all.  Given a thingy that
prints like that, I still need a wabbit hunter to tell me what /this/
particular sentinel value means.

   Or, if one wants to get fancier (maybe stuff the class definition
 into some common package)


  class Sentinal(object):
 ...   def __init__(self, text):
 ...   self.text = text
 ...   def __str__(self):
 ...   return %s : %s % (repr(self), self.text)
 ... 
  _missing = Sentinal(Missing Items)
  print _missing
 __main__.Sentinal object at 0x0120D070 : Missing Items

And the advantage of all of this typing over ['missing'] is what,
precisely?  If I want to write Java, I know where to look; I don't.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to test if a module exists?

2010-11-06 Thread Mark Wooding
Chris Rebert c...@rebertia.com writes:

 if err.message != No module named extension_magic_module:

Ugh!  Surely this can break if you use Python with different locale
settings!

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: How to test if a module exists?

2010-11-06 Thread Mark Wooding
Chris Rebert c...@rebertia.com writes:

 Since when does Python have translated error messages?

It doesn't yet.  How much are you willing to bet that it never will? ;-)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Silly newbie question - Carrot character (^)

2010-11-06 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

 If you want to argue that the Python reference manual is aimed at the
 wrong level of sophistication, specifically that the BNF syntax stuff
 should be ripped out into another document, then I might agree with
 you.  But to argue that it's entirely the wrong kind of thing is, in
 my opinion, unjustified.

I certainly wouldn't agree with that.  The language's syntax is
essential part of the language, and must be described clearly and
unambiguously.  Formal grammars aren't especially hard to understand,
and they're pretty much everywhere, so learning how to read them is an
essential skill anyway.

To be honest, I reckon the Python language reference is too friendly and
fluffy.  The manual for F#, say, is a harder read.  The Standard ML
language reference is a book full of mathematical notation (inference
rules for operational semantics, mainly) and little else.  The Scheme
language used to be described by a page or so of equations giving a
translation into lambda calculus (but now that's operational semantics
too) -- oh, there are prose descriptions too, but they're not easy going
either in places, and the formal semantics are necessary to clear up
some of the details.

You Python people have it easy.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: functions, list, default parameters

2010-11-05 Thread Mark Wooding
Steven D'Aprano st...@remove-this-cybersource.com.au writes:

 defaults initialise on function definition (DID)
 defaults initialise on function call (DIC)

 I claim that when designing a general purpose language, DID (Python's 
 existing behaviour) is better than DIC:

 #1 Most default values are things like True, False, None, integer or 
 string literals. Since they're literals, they will never change, so you 
 only need to set them once.

Right; so a half-decent compiler can notice this and optimize
appropriately.  Result: negligible difference.

 #2 It's easy to get default values to initialise on function call in a 
 language that uses initialisation on function definition semantics: just 
 move the initialisation into the function body. Python has a particularly 
 short and simple idiom for it:

 def f(x=None):
 if x is None:
 x = some_expression()

That's actually rather clumsy.  Also, it's using in-band signalling:
you've taken None and used it as a magic marker meaning `not supplied'.
Suppose you want to distinguish /any/ supplied value from a missing
argument: how do you do this /correctly/?

The approaches I see are (a) to invent some unforgeable token or (b)
emulate the argument processing by rifling through * and ** arguments.

Solution (a) looks like this:

_missing = ['missing']
def foo(arg = _missing):
  if arg is _missing: arg = ...
  ...

But now _missing is kicking around in the module's namespace.  Fixing
that is rather messy.  (No, you can't just `del' it.)  Maybe this can be
improved:

def _magic():
  _missing = ['missing']
  def foo(arg = _missing):
if arg is _missing: arg = ...
...
  return foo
foo = _magic()
del foo

Solution (b) is just too grim.

 But if the situations were reversed, it's hard to get the DID semantics:

 def f(x=None):
 if x is None:
 global _f_default_arg
 try:
 x = _f_default_arg
 except NameError:
 _f_default_arg = x = default_calculation()

Ugh.  This is artificially awful and doesn't correspond to existing
Python DID semantics.

  * Python evaluates the default argument expression at function
definition time.  You've implemented delayed evaluation for no
obvious reason.

  * Python evaluates the default argument expression in the enclosing
environment.  You've evaluated the expression in the function, again
for no obvious reason.

I'm interested to know why you did this.  You know Python well enough
that it's probably not just a misunderstanding, and you have enough
integrity that it's probably not a dishonest debating tactic.

A more faithful implementation of the actual semantics is considerably
simpler.

_default_arg = ...
def func(arg = _default_arg):
  ...

This is always correct, and actually simpler than even the standard but
incorrect simulation of DIC.

 #3 Re-initialising default values is wasteful for many functions, perhaps 
 the majority of them. (Of course, if you *need* DIC semantics, it isn't 
 wasteful, but I'm talking about the situations where you don't care 
 either way.) In current Python, nobody would write code like this:

 def f(x=None, y=None, z=None):
 if x is None: x = 1
 if y is None: y = 2
 if z is None: z = 3

 but that's what the DIC semantics effectively does. When you need it, 
 it's useful, but most of the time it's just a performance hit for no good 
 reason. A smart compiler would factor out the assignment to a constant 
 and do it once, when the function were defined -- which is just what DID 
 semantics are.

Python's compiler is already clever enough to notice a constant
expression when it sees one, and memoizing the default argument values
is straightforward enough.  There's therefore nothing to choose between
the two on constant expressions.

 If you're unconvinced about this being a potential performance hit, 
 consider:

No, I can see that clearly, thanks.  That comes up much less frequently
than the case where a default argument value should be a fresh list or
dictionary, in my experience.

 What would you prefer, the default value to be calculated once, or every 
 time you called f()?

This situation is rare enough that I'd put up with manual memoization.

 #4 Just as DID leads to surprising behaviour with mutable defaults, so 
 DIC can lead to surprising behaviour:

 def f(x=expression):
 do_something_with(x)

 If expression is anything except a literal, it could be changed after f 
 is defined but before it is called. If so, then f() will change it's 
 behaviour.

Yes.  Most usefully, the expression may refer to other argument values
(to its left, only, presumably).  This is frequently handy, not least in
object constructors.

This is an enormous sidetrack on what I'd hoped would be a parenthetical
remark left unremarked.  I'm not sure that further discussion will be
especially interesting, 

Re: Compare source code

2010-11-04 Thread Mark Wooding
Seebs usenet-nos...@seebs.net writes:

 Python's the only language I use where an obvious flaw, which is
 repeatedly observed by everyone I know who uses the language, is
 militantly and stridently defended by dismissing, insulting, and
 attacking the character and motives of anyone who suggests that it
 might be a bit of a nuisance.

So you've not tried Lisp, then?  Dissing Lisp's parentheses tends to get
a pretty similar reaction.

My observations on this general discussion.

  * Python is far from unique in its use of significant whitespace.
Miranda was inferring program structure from indentation in 1985.
Haskell and F# are more modern examples.

  * I don't have many problems with tools trashing whitespace in Python
programs, though I have seen web forum software mangling
indentation; since this makes nontrivial chunks of almost any
programming language illegible, I'm more than willing to blame the
forum software for this.  I haven't personally seen indentation
trashed by email software, for example (though I steer well clear of
people who try to send me HTML mail).

  * I /do/ have a significant problem with cutting and pasting code in
Python.  In most languages, I can haul a chunk of code about, hit
C-M-q, and Emacs magically indents the result properly.  This is,
unfortunately, impossible with Python.  It has caused me real bugs,
and I have to be extra careful to fix the indentation up.

  * I've just noticed that Emacs's Python mode has a magic keystroke
which appears to do the right thing for cut-and-pasted code.  This
is symptomatic of a bigger problem: simply by being different from
the mainstream, Python requires that one work with it differently.
It requires different tools, and different techniques.  Many
languages use some kind of brackets to mark substructure, so tools
have become good at handling bracketed substructure, whether for
automatic indentation or navigation.  Python marks (some)
substructure differently, so users need to learn new techniques or
tools for working with it.

I /like/ Python.  I use it frequently.  I /don't/ want to change its
structure marked by indentation.  I'm /willing/ to put up with some
inconvenience because Python makes up for it in other ways.  But there
/is/ inconvenience, and it does need putting up with.  I think the
benefits are worth the costs; others may disagree.

-- [mdw], a smug Lisp weenie at heart.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Compare source code

2010-11-04 Thread Mark Wooding
Tim Harig user...@ilthio.net writes:

 Python is the only language that I know that *needs* to specify tabs
 versus spaces since it is the only language I know of which uses
 whitespace formating as part of its syntax and structure.

You need to get out more.  Miranda, Gofer, Haskell, F#, make(1), and
many others, all use indentation to indicate structure; YAML isn't a
programming language, but it also uses indentation to indicate
structure, as do a number of wiki markup languages; there are also
representations of Lisp S-expressions which use indentation instead of
parentheses.

 Mixed usage may be annoying in other languages; but, it breaks Python.

I disagree.  The Haskell '98 report specifies (correctly) that tabs are
every eight columns, and a tab moves to the next tab stop.  Python makes
the same specification; it's just the users who actually want to stamp
out tabs.

Flamebait: it's not the tabs that cause the problem: it's that some
people are under the mistaken impression that the position of tab stops
in text files is a matter for local preference.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Allow multiline conditions and the like

2010-11-04 Thread Mark Wooding
Chris Rebert c...@rebertia.com writes:

 Or, if possible, refactor the conditional into a function (call) so
 it's no longer multiline in the first place.

No!  This /increases/ cognitive load for readers, because they have to
deal with the indirection through the name.  If you actually use the
function multiple times, the mental overhead of forming the abstraction
and associating it with the function name is shared across the various
call sites and it's probably worth it.  If it's only called once, leave
it inline.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Compare source code

2010-11-04 Thread Mark Wooding
Tim Harig user...@ilthio.net writes:

 So, your telling me that mixing tabs and spaces is considered a good
 practice in Haskell?

It doesn't seem to be a matter which is discussed much.  I think Haskell
programmers are used to worrying their brains with far more complicated
things like wobbly[1] types.

 I would argue that text files do not have tab stops -- text editors
 do.  So long as you use tabs for all of your indenting, it is quite
 safe to set the editors tab stops however one likes since the editor's
 tab stop doesn't effect the output of the file.

This is wishful thinking.  Firstly, code written with a narrow
indentation offset (e.g., two spaces) can take up an uncomfortable width
when viewed with a wider offset.

Secondly, if you want other parts (e.g., per-line comments) of lines
with different indentations to align, then you'll have to take into
account the tab width.  Technically, you could arrange that between any
pair of alignment points of any pair of lines there are the same number
of tab characters; but this is also doomed to uncomfortably wide lines;
it also suffers because it imposes an /a priori/ upper bound on the
indentation level.

[1] Proper technical term.  I kid you not.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Man pages and info pages

2010-11-04 Thread Mark Wooding
Tim Harig user...@ilthio.net writes:

 When the GNU folk decided to clone *nix they decided that they knew
 better and simply decided to create their own interfaces.

This isn't the case.  Actually Info has a long history prior to GNU: it
was the way that the documentation was presented at the MIT AI lab.  In
fact, Info was used rather like a modern wiki.  The operating system
they used, called ITS, didn't have a concept of file permissions, and
users were encouraged to improve documentation (and programs).  The
original Info viewer was implemented in Emacs (which also originated in
ITS, years before GNU).

Texinfo was a GNU innovation: the idea that you could build both the
Info document and a nice printable manual from a single source was
novel, as was the application to Unix.  But, since Stallman was
documenting large software systems like Emacs and GCC, it doesn't seem
unreasonable to provide manuals which are somewhat more discursive and
leisurely than traditional Unix manpages.  I have a printed copy of the
GNU Emacs 18 manual (from 1987): it's almost 300 pages long.  The modern
manual for Emacs 23 is several /times/ larger than this.  Man pages
don't scale that well.

I do agree it's annoying that the official coreutils documentation is in
Texinfo.

 Actually, the left arrow key does not work at all intuitively.  One
 would expect that it should go back to the previous page as it would
 in lynx, etc.  It does not.

It moves the cursor so you can hit links.  The l key takes you back
through your recent viewing history -- and has done for thirty years.

 By tradition 'n' and 'p' are broken for scrolling in a page.  'b' is
 often used in place of p but that seems to take one back to the top of
 the page.

Space and backspace are an older tradition.

 The s key for a search is another example that has already been
 discussed.

I find C-s more useful in Info, because it searches interactively.  I
frequently get muddled when I try to search in `modern' programs like
web browsers, because they've gratuitously made C-s try to save the page
(something one hardly ever wants to do) rather than search.  (Finding is
different: finding is what happens at the end of a /successful/ search.
So C-f is poorly chosen.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Ways of accessing this mailing list?

2010-11-04 Thread Mark Wooding
John Bond li...@asd-group.com writes:

 Hope this isn't too O/T - I was just wondering how people read/send to
 this mailing list, eg. normal email client, gmane, some other software
 or online service?

 My normal inbox is getting unmanageable, and I think I need to find a
 new way of following this and other lists.

I read and post to it as comp.lang.python.  I maintain a local NNTP
server, which interacts with my ISP's news server.  I read and post news
(and mail) using GNU Emacs and Gnus.

(Interestingly, if enormous folders are your problem, Gnus can apply
news-like expiry rules to email folders.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Compare source code

2010-11-04 Thread Mark Wooding
Tim Harig user...@ilthio.net writes:

 I use simple comments that are not effected by white space.  I don't
 waste my time trying to make comments look artistic.  They are there
 to convey information; not to look pretty.  I really detest having to
 edit other peoples comment formatting where you have to re-align
 everything if the length of any of comment lines change.

I view source code as primarily a means of communication with human
readers, and only secondarily as being machine readable.  I therefore
think it's worth the effort to make source code readily legible, for
example by making effective use of horizontal and vertical whitespace.
A long time ago, I spent a little while studying graphic design, so I
try to keep an eye on this sort of thing.

I'm interested in line length for two reasons: firstly, because I
believe that there's an optimum line length for easy and rapid reading,
which is probably a bit less than 80 columns; and secondly because I
find that I make more effective use of the available space on my screen
if I have several narrow columns rather than a few wide ones -- since
most lines in source files are short, a wide column ends up being mostly
empty on the right hand side, which is wasteful.

It's true that a source file is not the same as a typeset document: the
most obvious difference is that source files are modified over time,
sometimes by many hands, and that therefore some of the tradeoffs are
different.  I dislike `pretty' boxes around large comments, for example,
because maintaining the right hand edge is unnecessarily tedious.  But
sometimes careful alignment can help a reader spot a symmetry or find
his way through a repetitive section such a table more easily.

(Unfortunately, I appear to have strange ideas about what `legible'
means...)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: functions, list, default parameters

2010-11-04 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 In message 20101021235138.609fe...@geekmail.invalid, Andreas
 Waldenburger wrote:
  While not very commonly needed, why should a shared default argument be
  forbidden?

 Because it’s safer to disallow it than to allow it.

Scissors with rounded ends are safer than scissors without.  Chopsticks
and plastic sporks are safer than metal cutlery.  We have sharp things
because they're /useful/.  Similarly, having mutable objects as argument
defaults can be useful.

(Based on experience with other languages, I suspect that evaluating the
default expression afresh for each call where it's needed would be more
useful; but it's way too late to change that now.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: functions, list, default parameters

2010-11-04 Thread Mark Wooding
Lawrence D'Oliveiro l...@geek-central.gen.new_zealand writes:

 Mediocre programmers with a hankering towards cleverness latch onto it
 as an ingenious way of maintaing persistent context in-between calls
 to a function, completely overlooking the fact that Python offers much
 more straightforward, comprehensible, flexible, and above all
 maintainable ways of doing that sort of thing.

It does nowadays.  Once upon a time, Python didn't have proper closures,
and argument defaults, evaluated at function-definition time, were the
only way of capturing data from the surrounding environment.  You may be
confusing `mediocre' with `old-fashioned', and `a hankering towards
cleverness' with `wanting to run code on old Python interpreters'.  This
last may be because the relevant code was written back when those `old'
interpreters were shiny and new.

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Man pages and info pages

2010-11-04 Thread Mark Wooding
Tim Harig user...@ilthio.net writes:

 Right, and in info with the default key bindings, backspace takes me
 to the command help.  I would have expected it to either scroll up the
 page or take me to the previously visited node.

Sounds like your terminal is misconfigured.  Backspace should produce
^?, not ^H.  (Delete should produce some awful escape sequence.)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: [OFF] sed equivalent of something easy in python

2010-10-30 Thread Mark Wooding
Jussi Piitulainen jpiit...@ling.helsinki.fi writes:

 Daniel Fetchinson writes:

  The pattern is that the first line is deleted, then 2 lines are
  kept, 3 lines are deleted, 2 lines are kept, 3 lines are deleted,
  etc, etc.

 So, is there some simple expression in Python for this?

(item for i, item in enumerate(input) if (i + 4)%5  2)

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Strong typing vs. strong testing [OT]

2010-10-23 Thread Mark Wooding
Steven D'Aprano steve-remove-t...@cybersource.com.au writes:

 Well, what is the definition of pi? Is it:

 the ratio of the circumference of a circle to twice its radius;
 the ratio of the area of a circle to the square of its radius;
 4*arctan(1);
 the complex logarithm of -1 divided by the negative of the complex square 
 root of -1; 
 any one of many, many other formulae.

 None of these formulae are intuitively correct; the formula C = 2πr isn't 
 a definition in the same sense that 1+1=2 defines 2. The point that I was 
 trying to get across is that, until somebody proved the formula, it 
 wasn't clear that the ratio was constant.

There are several possible definitions of `2'.  You've given a common
one (presumably in terms of a purely algebraic definition of the
integers as being the smallest nontrivial ring with characteristic 0).
Another can be given in terms of Peano arithmetic, possibly using an
encoding of Peano arithmetic using only the Zermelo-- Fraenkel axioms of
set theory: at this point one has only a `successor' operation and must
define addition; the obvious definition of 1 and 2 are s(0) and s(s(0))
respectively, and one then has an obligation to prove that s(0) + s(0) =
s(s(0)), though this isn't very hard.

I think my preferred definition of `pi' goes like this (following Lang's
/Analysis I/).  Suppose that there exist real functions s and c, such
that s' = c and c' = -s, with s(0) = 0 and c(0) = 1.  One can prove that
a pair of such functions is unique, and periodic.  Define pi to be half
the (common) period of these functions.  (Now we notice that they factor
through the quotient ring R/(2 pi) and define `sin' and `cos' to be the
induced functions on the quotient ring.)

Would the world be a better place if we had a name for 2 pi rather than
pi itself?

-- [mdw]
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Lisp mentality vs. Python mentality

2009-04-25 Thread Mark Wooding
Carl Banks pavlovevide...@gmail.com writes:

 Graham, for his part, doesn't seem to appreciate that what he does is
 beyond hope for average people, and that sometimes reality requires
 average people to write programs.

I think he understands that perfectly well.  But I think he believes
that the sorts of tools which help average people write programs get in
the way of true wizards.

I think I agree.  

On the other hand, I don't think Python actually does get in the way
very much.

-- [mdw], Lisp hacker.
--
http://mail.python.org/mailman/listinfo/python-list


Re: python list handling and Lisp list handling

2009-04-25 Thread Mark Wooding
Mark Tarver dr.mtar...@ukonline.co.uk writes:

 But are Python lists also indistinguishable from conventional
 Lisplists for list processing. 

 For example, can I modify a Python list non-destructively?  

No.

 Are they equivalent to Lisp lists. Can CAR and CDR in Lisp be thought
 of as

 def car (x):
   return x[0]

 def cdr (x):
   return x[1:]

Not in the presence of side-effects, no.

The slice-extration operation on lists constructs a copy of the
original, and mutating the original doesn't affect the copy.  Here's a
simple example.

[Load your definitions...]

In [1]: def car (x): return x[0]
   ...:

In [2]: def cdr (x): return x[1:]
   ...:

[Python]   [Common Lisp]

In [3]: a = [1, 2, 3, 4]   CL-USER (setf a (list 1 2 3 4))
   (1 2 3 4)

In [4]: b = cdr(a) CL-USER (setf b (cdr a))
   (2 3 4)

In [5]: a[2] = 'banana'CL-USER (setf (third a) banana)
   banana

In [6]: a  CL-USER a
Out[6]: [1, 2, 'banana', 4](1 2 banana 4)

In [7]: b  CL-USER b
Out[7]: [2, 3, 4]! (2 banana 4)

Also, note:

In [8]: b is cdr(a)CL-USER (eq b (cdr a))
Out[8]: False! T

Your Python `cdr' operation conses.  Until you create it explicitly,
there is no Python value corresponding to `all but the first element of
this list'.

But, apart from the performance and sharing characteristics, they're the
same.  I think those are pretty big differences, though.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Definition of Pythonic?

2009-04-11 Thread Mark Wooding
John Yeung gallium.arsen...@gmail.com writes:

 A couple of others have already mentioned the Zen of Python, available
 at the Python command prompt.  I would agree with that, but also add
 the caveat that none of the principles expressed there are hard-and-
 fast rules.

Indeed, I'd suggest that the very lack of hard-and-fast rules is typical
of the Python approach.

 The fact is, it's impossible to satisfy every principle in every
 situation.  To me, Python distinguishes itself for how well it
 balances all of them.  Compromise is a word that comes up a lot when
 talking about the design of Python.  To some, that has a negative
 connotation; to me, it's an inevitable consequence of being practical.

Agreed.  Then again, all language design is a compromise, between
factors like runtime efficiency, simplicity of implementation,
tractability of semantics (for various classes of users), supportability
by tools, and expressive power.  Python inhabits what seems to me to be
a particularly sweet spot on this rather complex landscape.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: siple for in expression

2009-03-03 Thread Mark Wooding
Matko ivastipan...@inet.hr writes:

 Can someone help me to understand the following code:

 uv_face_mapping = [[0,0,0,0] for f in faces]

It constructs a fresh list, with the same number of elements as are in
the iterable object referred to by `faces', and where each element is a
distinct list of four zero-valued integer objects; it then makes
uv_face_mapping be a name for this list.

(This is therefore not the same as

uv_face_mapping = [[0, 0, 0, 0]] * len(faces)

which constructs a list, each of whose elements is (well, refers to) the
/same/ list of four zero-valued integers.)

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: why cannot assign to function call

2009-02-28 Thread Mark Wooding
Ethan Furman et...@stoneleaf.us writes:

 Mark Wooding wrote:
 Here's what I think is the defining property of pass-by-value [...]:

   The callee's parameters are /new variables/, initialized /as if by
   assignment/ from the values of caller's argument expressions.

 My soundbite definition for pass-by-reference is this:

   The callee's parameters are merely /new names/ for the caller's
   argument variables -- as far as that makes sense.

 Greetings, Mark!

You posted to the whole group -- probably using a wide-reply option
while reading the mailing list.  Still, I'll give an answer here in
order to help any other readers of the list or newsgroup.  However, as
far as I'm concerned, this discussion is basically at an end and I'm not
really interested in starting it up all over again.  To that end, I've
set followups to `poster'.  I shall continue reply to private email
which seems interested in a sensible discussion.

 I was hoping you might be able to clarify those last two sound bites
 for me -- I think I understand what you are saying, but I'm confused
 about how they relate to Python...

 Specifically, how is a new name (pbr) different, in Python, from a new
 name initialized as if by assignment (pbv)?  It seems to me than you
 end up with the same thing in either case (in Python, at least),
 making the distinction non-existent.

You've missed a level of indirection.  In particular, `names' aren't
things that you initialize.  They're things that you /bind/ to
variables.  The crucial difference is that, in pass-by-value, new
variables are created as an intrinsic part of the process, whereas in
pass-by-reference, new variables are not (usually) created, and instead
the formal parameter names are bound to the caller's pre-existing
argument variables.

It's worth noting that I use the terms `name' and `binding' in different
ways from most of the Python community.  This is unfortunate.  The
discrepancy is actually because the Python meanings of these words are
not the same as the meanings in the wider computer science and
mathematical communities.  For example, many Python users seem to use
`binding' to mean `assignment', which is a shame because it leaves the
concept that is usually called `binding' without a name.  So I'll stick
with the wider meanings.

A while ago, I posted an essay -- to this group -- which may help
explain the concepts:

Message-ID: 8763k14nc6.fsf@metalzone.distorted.org.uk
http://groups.google.com/group/comp.lang.python/msg/f6f1a321f819d02b

On with the question.

 def func(bar):
 bar.pop()

 Pass-by-reference:
   foo = ['Ethan','Furman']
   func(foo)   # bar = foo

 Pass-by-value:
   foo = ['Python','Rocks!']
   func(foo)   # bar is new name for foo
   # is this any different from above?

 If I have this right, in both cases foo will be reduced to a
 single-item list after func.  

You're correct.  So: we can conclude that the above test is not
sufficient to distinguish the two cases.

 Any further explanation you care to provide will be greatly
 appreciated!

This test is sufficient to distinguish:

def test(x):
  x = 'clobbered'

y = 'virgin'
test(y)
print y

If it prints `virgin' then you have call-by-value.  If it prints
`clobbered' then you have call-by-reference.

Let's examine the two cases, as I did in the essay I cited above.  I'll
do call-by-value first.  First, we define a function `test'.  Then, we
initialize `y'.  It's worth examining this process in detail.  The name
`y' is initially unbound. so it is implicitly bound to a fresh
variable.  Then, (a reference to) the string object 'virgin' is stored
in this variable.  We can show this diagrammatically as follows.

y (in global env.)    [VAR]  --- 'virgin'

(In the diagrams, === denotes a binding relationship, between names and
variables; and --- denotes a reference relationship, between variables
and values.)

Next, we call the `test' function.  Call-by-value says that we must
evaluate the argument expressions.  There's only one: `x'.  The value of
a name is obtained by (a) finding which variable is bound to the name,
and (b) extracting the value from this variable.  Well, the variable is
the one we just bound, and the value stored is (the reference to) the
string 'virgin'.  So the result of evaluating the argument expressions
is simply (the reference to) that string.

The function has one parameter, `y'.  A new environment is constructed
by extending the global environment.  In this new environment, the name
`y' is bound to a fresh variable -- distinct from all others, and
especially from the variable bound to `x' -- and in that variable we
store the value of the corresponding argument expression.  Result: the
function body is executed in an environment which is like the global
environment except that `y' is bound to a fresh variable containing
'virgin'.

y (in global env

Re: Using while loop and if statement to tell if a binary has an odd or even number of 1's.

2009-02-06 Thread Mark Wooding
Duncan Booth duncan.bo...@invalid.invalid writes:

 Mark Dickinson dicki...@gmail.com wrote:
[snip]
 while n:
 count += 1
 n = n-1
 return count
 
 is_even = count_set_bits(the_int) % 2 == 0
 
 ...but anyone submitting this as a homework
 solution had better be prepared to explain why
 it works.
 

 I remember a programming exercise when I was an undergraduate and anyone 
 who *didn't* use that trick got marked down for writing inefficient
 code.

Curious.  I don't see why

def parity(x):
  b = 2
  l = 1
  while True:
b = l
if x  b: break
l = 1
  while l:
b = l
x ^= x  l
x = b - 1
l = 1
  return x  1

is any less efficient.  Indeed, it seems more so to me.  The number of
top-level loop iterations is bounded by the logarithm of the total
number of bits in the input rather than the Hamming weight.  In terms of
single-precision operations (if we're dealing with bignums) the analysis
is more complicated; but the number of single-precision operations in
one of my loops is a linear function of l (assuming that the comparison
is done sensibly), and l increases and decreases geometrically, so I
have performance which is O(log x).  Assuming no special Hamming-weight
distribution on the input, the `efficient' version takes O(log^2 x)
single-precision operations.

Given an /a-priori/ upper bound on the length of the input, e.g., it
fits in a machine word, the above technique is still probably faster.
That is, assuming arithmetic and bitwise operations on integers take
constant time, my version runs in O(log log x) time whereas the
`efficient' version takes O(log x) time.

(My function returns the complement of the value requested.  Fixing it
is obviously trivial.)

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: is python Object oriented??

2009-02-04 Thread Mark Wooding
Russ P. russ.paie...@gmail.com writes:

 Imagine you own a company, and you decide to lease an office building.
 Would you expect the office doors to have locks on them? Oh, you
 would? Why? You mean you don't trust your co-workers? What are locks
 but enforced access restriction?

Huh?  The lock on the door isn't to keep the coworkers out.  It's to let
them /in/ while keeping everyone else out.  So I don't really see the
analogy.

Or are you talking about the individual offices?  If so, then I'd expect
the locks to be /used/ only under rather unusual circumstances.  If
someone in the office has something to hide, I think that's rather
suspicious, actually...

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: is python Object oriented??

2009-02-04 Thread Mark Wooding
Steven D'Aprano ste...@remove.this.cybersource.com.au writes:

 Now, that's a toy example. Languages like Ada make correctness proofs, 
 well, perhaps not easy, but merely difficult compared to impossible for 
 languages like Python.

Say `generally impractical' rather than `impossible' and I'll agree with
you.  But I'm not actually sure that the situation for Python with
respect to correctness proofs is significantly harder than it is for C.
Certainly Ada (or at least dialects of Ada) have features which make
proof-supporting tools easier; I'm not aware of such proof support for
other languages.

Actually, if you're starting from a formal specification in Z, say, and
implementing in Python, well, the Z checker will already have ensured
that your specification is well typed; your proof that the
implementation follows the specification will automatically contain a
well-typed-ness proof of your implementation regardless of whether the
compiler provides static verification.

 To bring it back to private/public attributes, side-effects make 
 correctness proofs difficult. Modifications of attributes are side-
 effects. When attributes are subject to being modified by arbitrary code, 
 it is harder to reason about the correctness of the code:

 class Inverter(object):
 def __init__(self, x):
 # Pre-condition: x is always a float
 if x:
 self.x = x
 else:
 raise ValueError(x must not be zero)
 # Post-condition: if self.x exists, it is a non-zero float
 def invert(self):
 return 1.0/self.x


 Is method invert correct?

I'd argue that it isn't, and in fact that the specification is wrong.
In particular, it ought to be a precondition that x is nonzero.  At this
point you can dump the explicit check at the cost of imposing a proof
obligation on the caller.

 No, it is not, because the invariant that self.x is non-zero may have 
 been broken by some arbitrary piece of code elsewhere. 

It's not stated as an invariant.  It's stated as a post-condition, which
is indeed true (almost[1]) regardless of the behaviour of other parts of
the program.

[1] A subclass may have already set self.x before invoking
Inverter.__init__.  If you explicitly `del self.x' before raising
the exception, the subclass can still defeat you by passing the
reference to the half-constructed object to another thread which
mutates the object at an inconvenient time.  I mention all of this
merely to avoid pedantry in follow-ups.

I'd also argue that maintaining the invariant about self.x is the
responsibility of code that messes with self.x, and therefore it is
/legitimate/ to modify self.x from external code which maintains the
invariant.

 Our ability to reason about the correctness of the code is weakened
 significantly.  Sticking an underscore in front of x does not help:
 there's nothing to stop some arbitrary function elsewhere changing _x
 to zero.

Dichotomy for you.

  * EITHER the other code is written to the same high standards, in
which case it will come with appropriate specifications,
preconditions, postconditions, invariants and proofs for whatever it
does, even -- especially -- if it involves grubbily messing about
with your module's innards (so everything is fine);

  * OR the other code doesn't meet your high standards, in which case
all bets are off anyway, from the point of view of formal-methods
types at any rate (so you can wash your hands of the whole affair).

 (1) Paranoia. Make the developer responsible for checking everything all 
 the time:
[...]
 (2) Hope the error never occurs, and if it does, let the caller deal with 
 it.
[...]
 There is a third strategy, sadly not available to Python programmers: 
 prevention by catching potential errors at compile-time.

Four: Describe your interface clearly, specify the behaviour of
functions and so on; and leave whoever messes with your module with the
task of proving -- to whatever level of formality is required by their
project -- that what they've done is sane and reasonable.

In fact, since whatever one does in a project should be held to this
standard, whether it involves grubbing about inside undocumented
internals or not, there's nothing particularly special about this case.
Good job, really, since Python doesn't distinguish either. ;-)

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Where how to deallocate resources in Python C extension

2009-02-04 Thread Mark Wooding
fredbasset1...@gmail.com writes:

 I've written a C extension, see code below, to provide a Python
 interface to a hardware watchdog timer.  As part of the initialization
 it makes some calls to mmap, I am wondering should I be making
 balanced calls to munmap in some kind of de-init function?

The kernel should remove the mapping when your process exits anyway --
otherwise the world would be left in an inconsistent state if your
process got killed by SIGKILL for example.

 Do Python extensions have d'tors?

No.  But you can cheat: stash some object whose tp_del slot does your
cleanup in your extension's module under some funny name.  (And woe
betide anyone who dels the funny name prematurely!)  I'm not sure I'd
bother.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: structs

2009-02-04 Thread Mark Wooding
Keith Thompson ks...@mib.org writes:

 Gary Herron gher...@islandtraining.com writes:
 Python *is* object-oriented

 I disagree. Care to provide proof of that statement?

AWOOGA!

The article I'm following up to (together with at least one other) is a
forgery, and the Followup-To header is set to comp.lang.c as part of an
effort to (a) disrupt that newsgroup, and (b) discredit Keith Thompson,
who is a respected and capable contributor to that group.

This is a request to other readers to take special care over responding
to controversial articles, and particularly to watch for strange
Followup-To headers.

Thanks for listening.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Date Comparison

2009-02-03 Thread Mark Wooding
mohana2...@gmail.com writes:

 I need to compare two dates and find the number of days between those
 two dates.This can be done with datetime module in python  as below,
 but this is not supported in Jython.

 example
 from datetime import date
 a=datetime.date(2009,2,1)
 b=datetime.date(2008,10,10)
 c= a-b
 c.days
 114

I don't understand your problem.

Jython 2.2.1 on java1.6.0_0
Type copyright, credits or license for more information.
 from datetime import date
 a=datetime.date(2009,2,1)
 b=datetime.date(2008,10,10)
 c = a - b
 c.days
114

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Number of bits/sizeof int

2009-02-02 Thread Mark Wooding
Jon Clements jon...@googlemail.com writes:

 The int() type gained a bit_length method that returns the number of
 bits necessary to represent its argument in binary:

 Any tips on how to get this in 2.5.2 as that's the production version
 I'm stuck with.

def nbits(x):

  ## Special cases.
  if x == 0: return 0
  elif x  0: x = -x

  ## Find upper bound of the form 2^(2^n) = x.
  n = 1
  while True:
y = x  n
if y == 0: break
x = y
n = 1

  ## Now binary search until we're done.
  a = n
  while n  0:
n = 1
y = x  n
if y  0:
  x = y
  a += n

  return a


-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Number of bits/sizeof int

2009-02-02 Thread Mark Wooding
John Machin sjmac...@lexicon.net writes:

 3 can be represented in 2 bits and at the same time -3 can be
 represented in 2 bits?? But 2 bits can support only 2 ** 2 == 4
 different possibilities, and -3 .. 3 is 7 different integers.

Yeah, I made some arbitrary choices about what to do with non-positive
inputs.  If you prefer other answers, use 'em.  My ones work well with
signed-magnitude representations where the sign is stored separately.

   ## Find upper bound of the form 2^(2^n) = x.

 Possibly you mean 2 ** ( 2 ** n) = x

I write maths in comments, not Python.  Feel lucky I didn't write it in
LaTeX.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: is python Object oriented??

2009-02-02 Thread Mark Wooding
Russ P. russ.paie...@gmail.com writes:

 I am not sure why people keep mentioning that Python is not Java.
 As a slogan, it is rather misleading. Python is not C++, Ada, or Scala
 either. All of those languages have enforced access restriction. Why
 only mention Java?

Because Java is a well-known member of a family of object-oriented
languages (or at least languages supporting object-oriented
programming).  `Python is not Java' is somewhat of a slogan, intended to
convey the message that Python, quite intentionally, does not behave in
the same way as other languages you may be familiar with.

Smalltalk's visibility features are very different from C++ and Java: a
method can mess with its own object's (i.e., the recipient of the
message which caused the method to be invoked) instance variables but no
others -- a restriction enforced syntactically, since there is simply no
way of referring to a different instance's variables.  There is no
restriction whatever on sending messages to other objects.  Self
abandons the concept of instance variable (and of class, for that
matter), and access controls with it.

The Common Lisp Object System provides no access control features
(though one could probably implement some using the MOP, were one
sufficiently motivated); however, CL's package system is better placed
for this job anyway.  Other object systems for Lisp-family languages
tend to be similar.  The Lisp Machine's Flavors -- the first object
system with multiple inheritance -- relied on the package system for
access control; CLOS-like systems for Scheme, which lacks packages, tend
not to bother at all.  (The package system controls the mapping from
tokens read from, say, files to symbols; packages can export some of
their symbols, so you can refer to, say, MDW:FOO if package MDW exports
symbol FOO, or you can `use' package MDW in your own package to make FOO
refer to MDW:FOO.  The package system tries to keep you honest rather
than acting as an enforcement mechanism: even if MDW doesn't export BAR,
you can still talk about MDW::BAR -- note the double-colon -- as much as
you like.  Working at the name-to-symbol level allows the package system
to operate uniformly on all the various namespaces in Lisp.)

Perl's object system provides no access controls.  Ruby does, following
Simula, though it uses C++-ish `private' for Simula's `hidden'.

 If that's the case, you have my sympathies, but let's not pretend that
 Java is the only popular OO language with enforced access
 restrictions.

No, but let's not pretend either that such features are essential to
object orientation, or that they are even typical of object systems
outside of a particular (admittedly popular) subfamily.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: How to get atexit hooks to run in the presence of execv?

2009-01-29 Thread Mark Wooding
ro...@panix.com (R. Bernstein) writes:

 Recently, I added remote debugging via TCP sockets. (Well, also FIFO's
 as well but closing sockets before restarting is what's of concern.)

 I noticed that execv in Python 2.5.2 doesn't arrange exit hooks to get
 called. Should it?

I'd consider that to be highly unusual.  Certainly, the C atexit(3)
function is called only in response to a call to exit(3) (possibly
implicitly by returning from main), and not by execve(2) or any of its
little friends.

Your specific problem is to do with file descriptors, so it's probably
best dealt with using the close-on-exec flag:

from fcntl import fcntl, F_GETFD, F_SETFD, F_CLOEXEC

sk = socket(...)
## ...
fcntl(sk.fileno(), F_SETFD,
  fcntl(sk.fileno(), F_GETFD) | FD_CLOEXEC)

Now the socket will be magically closed when you exec.. another program.

Finally, can I urge against TCP sockets in an application like this?
Certainly without adequate authentication, it will simply be insecure
even within a single multiuser host (e.g., using localhost only) -- and
assuming that even a home machine has only a single user is becoming
less realistic.  Unix-domain sockets live in the filesystem, and access
to them is limited using the standard filesystem mechanisms.

If you're expecting inter-host communications (e.g., remote debugging),
it's a good idea to protect the session using TLS or something (much as
I dislike the TLS certification/public-key- distribution model it's way
better than nothing at all).

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Doc for extended call syntax; was: Re: unzip array of arrays?

2009-01-27 Thread Mark Wooding
Bryan Olson fakeaddr...@nowhere.org writes:

 Mark Wooding wrote:
 There's a full description of it in 5.4.3 in the Language Reference, but
 apparently not indexed.

 So I guess this means I can duck out of writing up a lecture on my own
 understanding of Python's extended call syntax. Great.

 I think I grock the extended call syntax, and when the question came
 up I was surprised not to be able to find where I learned it. Mark,
 where exactly does one look to see this full description?

I typoed, sorry!  I should have written 5.3.4:

http://www.python.org/doc/2.5/ref/calls.html

The description of the fancy * and ** syntax starts with `If the syntax
``*expression'' appears in the function call...'.

-- [mdw]
--
http://mail.python.org/mailman/listinfo/python-list


  1   2   3   >