Re: python strings

Tim Peters (tim@ksr.com)
Thu, 21 Apr 94 22:46:17 -0400

Backticked expressions in triple-quoted strings (a la ABC) would be a
Good Thing, IMO, as it would make the most common cases the easiest to
write & read (most common == results of expressions as evaluated in the
current namespaces, and no special formatting desired).

Dan, I suspect that would meet your most common uses for Lisp-style
backticked expressions. Do you?

Guido points out that "this doesn't solve the formatting problem
(especially for numbers)", but _no_ single scheme is going to meet all
reasonable formatting desires. Python's current mechanisms are great for
some uses, backticks are great for others, Don's extensions to "%" look
great for still others -- and Steve's wish for a template-based facility
"that preserves the column alignment between the format string and the
output string" isn't addressed by any of them.

The point isn't to suggest that Steve's format suggestion be built into
the language too <yikes!>, it's that "but this specific suggestion X
doesn't meet all reasonable formatting desires" isn't a good objection,
because it's universally true.

> I'd hate to see things like
> print """The ` '%03d'%n ` numbers of `language` objects..."""

Well, everyone would hate to see that! But hard as it is after seeing
the kinds of things we post to this group, I'd like to think we can give
our fellow Python'ers _some_ credit for common sense <0.9 grin>.

> Also I'd hate to see the difference between Python's different quoting
> schemes grow --

On this one I disagree, cuz I no longer think of the triple-quote forms
as "quoting schemes" so much as "formatting schemes". It's fine if {',"}
have identical semantics, and fine too if {""",'''} have identical
semantics, but if they're used for different things they really ought to
have different behaviors where that's _useful_. Change the triple-quote
to "%%", and the illusion that these are primarily _quoting_ mechanisms
would go away (not suggesting you _do_ that, except mentally <wink>).

The bit about stripping leading whitespace in the triple-quoted forms is
a good one, cuz it's the very essence of a "multi-line string" to span
several lines <wink>, and you're really going to hate reading Python
programs if the text/formatting blocks are jammed against the left
margin.

Here's a small snatch of Real Perl (which does not strip leading
whitespace from "here" blocks); imagine what it would look like if you
didn't even have the curly braces to help you mentally reconstruct the
blocking structure:

foreach $name( @hits ) {
if ( defined($gval{$name}) ) {
local($origdef) = $gval{$name};
print OUT $origdef;
# if the original doesn't have the expected '.byte'
# etc pseudo-op followed by digits, or '.zero $size', use
# it anyway, but ask the user to confirm it's right
$match = ($origdef =~ /($asmop\s+-?\d+|\.zero\s+$size)\s*$/);
print <<PLEA unless $match;
for '$name', please eyeball the original defn following, to
make sure it's compatible with its deduced size $size:
$origdef
PLEA
} else {
print OUT "$name: $asmop 0\n";
}
print OUT <<DEFINE;
.def $name; .val $name; .scl 2; .endef
.globl $name
DEFINE
}
}

Then multiply by 10 <wink>.

> ...
> All this needs now would be a built-in function vars() that returns
> the locals. This would be a counterpart to dir() and accept a module
> as argument as well to return the module's variables. dir() could
> then be defined as the (sorted) keys() of the dictionary returned by
> vars().

Cool! Here's a variation you _might_ like better:

1) Instead have a new built-in, dict(*arg), along the lines of:

if len(arg):
if len(arg) == 1:
arg = arg[0]
else: # at least two args passed
raise TypeError, 'too many arguments'
else: # no args passed
return a snapshot of the local namespace as a dict

# one arg passed, and "arg" is it
if hasattr(arg, '__dict__'):
return arg.__dict__
elif type(arg) is type({}):
return arg
else:
raise ValueError, "no natural dictionary"

2) Redefine dir(*arg) as (equivalent to):

temp = apply(dict,arg).keys()
temp.sort()
return temp

The intent is that dict() return a "natural" dict associated with its
argument, and dir() the "natural" keys. This does what you want for
namespaces and modules, and gives Python a natural way to spell other
useful stuff too (like "show me a class instance's attributes and values
*as if* they were implemented via a dict, despite that it's the year 2014
and they haven't been implemented that way for 18 years" <precognitive
smile>).

> .. a format specifier that took ANY type of object and converted it
> to a string using str(). I can think of two options:
>
> 1) introduce %p (with the same options as %s) -- the mnemonic of
> course means "any Python object". (In ANSI C %p means pointer but
> this doesn't make sense in Python.)
>
> 2) change %s so that if its argument isn't a string it converts ot to
> one using str().

Another vote for #2, on the grounds of minimizing the number of
implementation hassles that show thru to the user level. But with the
warning that next you know, people will gripe unless %d also tries to
convert its argument to an int first <0.5 grin>.

> ...
> PS there's one problem that vars() doesn't solve: suppose some of the
> variables you want to print are locals and some are globals? There
> really should be an inexpensive method to compute the "union" of two
> dictionaries...

I hope you heard me screaming before that you'd be happier leaving all
this out of the base language <snicker>.

> ... [lots of good points by all] ...

> [more guido]
> There are a few cases where I wouldn't want the automatic
> conversion to integers (e.g. floats -- imagine the surprise if
> range(10)[3.14] returns 3 instead of raising a TypeError)

Speaking as a Bona Fide Floating Point Expert:

1) Most floating-point users would disagree with you on this.

2) But you're absolutely right anyway. I shudder to think of all the
"compiler errors" I've tracked down to a user getting bit by the
common Fortran extension of silently truncating a float when it's in
an integer context, and due to fp rounding errors getting "the wrong"
int. Never again!

> [dan, talking about lisp backtick facilities]
> ...
> But I would use it for constructing HTML text as the result of CGI
> scripts. I am using Perl for that now, but I have to preevaluate
> expressions and store the results in variables. Not so serious, but it
> feels like doing without anonymous functions.

If you're writing the HTML text directly to a file, you may be able to
use Perl's "format" and "write" facilities instead. E.g.,

format = # establish a format for 'write' to STDOUT
@>>> is @##.##% of @<<<
$x, $x/$y*100, $y
.

($x, $y) = (20, 20); write;
$x /= 5; write;
$y *= 23; write;

That prints

20 is 100.00% of 20
4 is 20.00% of 20
4 is 0.87% of 460

I.e., you can have arbitrary expressions inside the format, and they're
re-evaluated each time you "write". It's also a concrete example of a
"template" formatting facility, such as Steve was asking about (the
"picture" lines-- those containing a "@" --draw a picture of how you
want the output to look, and whether you want stuff left-justified,
right-justified, centered, or aligned by decimal-point within each "@"
field).

> I'd be delighted if I could implement a backquote-like facility in
> Python. I wouldn't expect it to be built-in.

What do you think now? If Guido implements a way (vars/dict/whatever) to
capture the local NS as a dict, we could pass that dict to a "backtick
handling" function, and evaluate the backticked expressions ourselves via
passing the NS dict in turn on to eval. _Seems_ to me that should work
out OK.

OTOH, it sounds like Guido is almost willing to be badgered into doing it
the ABC way. If you haven't used ABC, you should post some examples of
the behavior you'd like in the end, so we can guess whether ABC-style
backticks would suffice (I _suspect_ they would, but they're not as
elaborate as the Lisp facilities -- but then macros have very tricky
problems to solve, and I'm betting you don't need all that hair).

left-justified-ly y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp