For those interested in poring over CVS logs, I've added a new feature
to logmerge.py: a -b tag option that restricts the output to a
specific branch tag. Use -b HEAD to show only the CVS HEAD
(a.k.a. trunk). (The default is to show all revisions regardless of
the branch on which they occur, which isn't always so easy if you're
interested in a specific branch.)
--Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum <guido(a)python.org> writes:
> I'd like to release something called Python 2.2.2 in a few weeks (say,
> around Oct 8; I like Tuesday release dates).
One minor point of concern: I think Jack Jansen's on holiday. Perhaps
we should wait for him to get back...
There's an aura of unholy black magic about CLISP. It works, but
I have no idea how it does it. I suspect there's a goat involved
somewhere. -- Johann Hibschman, comp.lang.scheme
This is somewhat off-topic, but I'm hoping maybe someone can give a hint
why this only happens on Python 2.2.1.
Ok, here's the story:
I've had a bug report against our pyPgSQL database interface package that
retrieving Large Objects doesn't work with Python 2.2.1. The reproducible
traceback we get is:
Traceback (most recent call last):
File "p.py", line 20, in ?
res = cs.fetchone()
File "pyPgSQL/PgSQL.py", line 2672, in fetchone
File "pyPgSQL/PgSQL.py", line 2281, in __fetchOneRow
for _i in range(self.res.nfields):
AttributeError: 'str' object has no attribute '__bases__'
This traceback is quite obviously bogus, as self.res.nfields is a Python
int and no strings are involved here whatsoever. After some debugging, I
found that something very strange happens in a function call that
happens in this for loop. Inside the for loop, a function typecast is
called, which has this code within:
if isinstance(value, PgBytea) or type(value) is PgLargeObjectType:
This code is causing the problems which result in the bogus traceback
Now in my case, 'value' is of type PgLargeObjectType, which is a custom
type from our extension module. PgBytea is a Python class.
Now comes the first very strange observation: Swapping the checks, so
that the 'type(value) is PgLargeObjectType' check comes first makes the
problem go away. So my conclusion is that there's some problem with
isinstance and my custom extension type.
The second strange thing is that this only happens on Python 2.2.1
(Linux, FreeBSD, Windows), but _not_ on Python 2.1.3 or Python 2.3-CVS.
Oh, the problem isn't tied to isinstance(value, PgBytea). Any isinstance
check causes it later on.
Of course I'm suspecting that there's some problem with the extension
type. Looks like some internal interpreter data gets corrupted. No idea
how to debug that, too.
Does anybody have any tips where to look or how to debug this further?
I have an idea for an interface mechnism for Python, and I'd like to see if
anyone likes it before writing an actual PEP. The key features are:
- It's implementable in pure Python (I've already started working on it).
- The syntax to use it is fairly concise.
- Interfaces are inherited by default, but can be turned off.
- Classes are made to implement interfaces without altering the class
definition in any way.
- A class can support any number of interfaces, even multiple interfaces
that define methods with the same names.
- It's easily extensible to add new features in a backward-compatible way.
- It has support for design-by-contract idioms (this part is not essential
to the proposal, so I won't discuss it further here, but interfaces without
DBC seem kind of incomplete to me).
In actual practice it would look something like this: Suppose you have a
class like this:
def foo(...): ...
def bar(...): ...
def foo2(...): ...
In the simplest case, suppose you have an interface Foo that defines a
single method, foo. To declare that SomeClass implements foo, you'd say:
Now, suppose you have a function that requires an argument implemeting
interface Foo. You would probably code it like this:
foo_proxy = Foo(foo_arg)
x = foo_proxy.foo(...)
Two things are happening here. First, foo_arg is being checked to make sure
it implements Foo; if not, an InterfaceError will be raised. Then,
foo_proxy becomes a proxy for foo_arg, but it *only* supports calling the
method foo, since that's all the interface defines. (If foo_arg is already
a proxy object, the call the Foo will just return foo_arg.)
Defining an Interface
How is "Foo" defined? It could look something like this:
def doc_foo(self,...): "Docstring for foo method."
The "doc_" prefix on foo is not part of the method name; it is needed to
control how the interface treats the method. If the method has default
behavior, you could say this instead:
"Docstring for foo method."
print "Defaults can be handy."
In the version, unlike the first, classes implemeting Foo need not define
their own "foo" method is the defualt will suffice. Requiring some sort of
prefix attached to every name defined by the interface is a little ugly, but
it opens up a lot of possibilities for creating different behaviors with a
minimum of fuss--I have a lot of uses in mind for different prefixes that I
won't go into here.
Let's say we have a new interface, FooBar, defined like this:
def doc_foo(...): "Method foo."
def doc_bar(...): "Method quux."
And suppose we'd like to make SomeClass above implement FooBar, but we want
FooBar.foo to call SomeClass.foo2 instead of SomeClass.foo. It's easy!
FooBar[SomeClass].foo = "foo2" # Override default binding.
Now we can do really confusing stuff:
x = SomeClass()
Foo(x).foo() # Calls x.foo()
FooBar(x).foo() # Calls x.foo2()
Of course you probably wouldn't do something so confusing on purpose, but it
could be useful when an object must support two different interfaces
(written by different people) that happen to have method names in common, or
to connect a class to an interface where the class defines all the needed
functionality but the methods have the wrong names.
For the last trick, let's imagine you want to derive a subclass of
SomeClass. If you want the new class to inherit all the interfaces, do
nothing. To remove an inteface, just do something like this:
class AnotherClass(SomeClass): ...
And it's done!
Please let me know if you like this idea (or hate it). If I get a good
response I'll try to write a PEP this weekend and make the implementation
availble to try out.
Hi, Guido, and people.
It recurrently happens that newcomers on the Python mailing list are surprised
that list.sort() does not return the sorted list as value. I quite understand
and agree that this is a good thing, because sorting is done in place, and
Python programmers should stay aware and alert of this fact.
Yet, I often see myself writing things like:
keys = messages.keys()
for key in keys:
This is not difficult to write, only slightly annoying. Writing:
list = list[:]
with the goal of simplifying the first excerpt into:
for key in sorted(message.keys()):
it is not really worth for small programs. But in larger programs, where one
often loops over the sorted element of a list, it might become reasonable to
write this extra definition. My feeling is that the idiom is common enough to
be worth a list method, so the above could be written instead:
for key in message.keys().sorted():
I immediately see an advantage and an inconvenient. The inconvenient is that
users might confuse `.sort()' with `.sorted()', however we decide to spell
`sorted', so the existence of both may be some kind of trap. The advantage is
that the `.sorted()' method fits well within how Python has evolved recently,
offering more concise and legible writings for frequent idioms.
Tim invested a lot of courageous efforts so Python `sort' becomes speedier. A
`.sorted()' method requires separate space to hold the result, using the same
size as the original, and that guaranteed extra-space may eventually be put to
good use for speeding up the sorting even more. The constraint of a sort
being in-place has indeed a cost, and deep down, we agree that this constraint
is artificial in contexts where `.sorted()' is really what the user needs.
François Pinard http://www.iro.umontreal.ca/~pinard
As you might have noticed, I have wrapped several parts of the
GMP Multi-Precision (GMP) library in form of Python types
Since these are numbers, it would be convenient if there were
some way to create them in form of literals, much like 123L
creates longs instead of integers or u"abc" gives you Unicode
instead of an 8-bit string.
I was wondering whether it would be worth adding something
like a registry of literal modifiers to Python, so that
extensions can register new modifiers with the compiler,
return 'mx.Number.Integer(%s)' % literal_string
x = 123I * 456I
print x, 234I
CEO eGenix.com Software GmbH
eGenix.com -- Makers of the Python mx Extensions: mxDateTime,mxODBC,...
Python Consulting: http://www.egenix.com/
Python Software: http://www.egenix.com/files/python/
When implementing keyword argument support for Boost.Python, I noticed the
following. I'm sure it's not worth a lot of effort to change this behavior,
but I thought someone might like to know:
>>> class X:
... def foo(self, y): print y
>>> X.foo(y = 1, self = X())
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unbound method foo() must be called with X instance as first
argument (got nothing instead)
David Abrahams * Boost Consulting
dave(a)boost-consulting.com * http://www.boost-consulting.com
> > Its return value will replace the $x"..." combination in
> > the token stream, as a literal token.
> Why just one token, and why just literal. Returning an
> arbitrary sequence of tokens seems more natural. This
> would allow e.g. Tim Berners-Lee to have basically what
> he wants (and asked for in his talk at IPC10) in terms of
> extended syntax for graphs, just with some $x in front.
1. I wasn't sure how easy it would be to return an
arbitrary sequence of tokens.
2. I wasn't sure how appropriate it was to make users
understand the internals of the parser in that way.
Transforming a magic token into a literal Python object
is easy to understand. Transforming it into an arbitrary
sequence of tokens is more powerful but harder to
understand. (And harder to claim as analogous with
u"...", 123L, etc., though I'm not sure that matters.)
> I had a similar idea right after Tim's talk, but could not
> articulate it clearly enough in a chat with Guido right
> afterwards, and later I didn't follow through with it. It
> seems to me that your proposal is detailed and precise
> enough (while my idea was rather vague) and that, by
> returning an arbitrary sequence of tokens, it will let
> Tim embed whatever funky syntax it requires.
If we want to be able to generate arbitrary sequences
of tokens, I think I'd prefer a more flexible input
> This power is also the downside of the whole idea of
> course -- no guarantee that somebody can't use this
> mechanism to produce highly obfuscated programs.
> But I think that such a somebody could already
> obfuscate quite effectively in other ways, and the
> risk of abuse shouldn't stop this interesting proposal.
I am inclined to agree.
> > ... return Rational(numerator, denominator)
> Hmmm, how would this "return a literal token"? It returns
> an instance of Rational -- how does the parser treat this
> instance as a literal token?
> I thought this use would have to return the sequence of
> tokens for identifier 'Rational', open parenthesis, literal
> (value of) numerator, comma, literal (value of) denominator,
> closed parenthesis -- which in turn is why I thought of an
> arbitrary sequence of tokens. If a single instance of any
> arbitrary class may be returned and get treated as a
> literal token by the parser, then that's much better (maybe
> I don't know Python's parser well enough, but I don't
> clearly see how that would be done).
I don't know Python's parser well enough either :-).
However: it can accept NUMBER and STRING tokens.
As far as the grammar is concerned, they are exactly
the same (except that multiple STRING tokens are
implicitly concatenated). As far as everything else
is concerned, they are very nearly exactly the same.
We could have a LITERAL token, treated in the same
sort of way as NUMBER and STRING. That was what I was
intending; certainly not returning the token-sequence
<Rational>, <(>, <numerator>, <,>, <denominator>, <)> !
> > - Is this insane?
> Hope not, since I like it.
Hmm. The other proposal I know you and I both like is
the adaptation protocol. This is not necessarily a good
> > - Is "$" the best character?
> Among the few available ones, I think I slightly prefer "@"
> for this use, but there's little to choose IMHO.
Curiously, "@" was the first option I thought of for this.
I didn't have any very concrete reason for switching to "$".