Favorite non-python language trick?

B

Bengt Richter

{}

The single line replacing
"""
with colour do begin
red := 0; blue := 255; green := 0;
end;
"""
follows:
which sets all the attributes: 0

Of course, I defined a class on the fly above, so I could have given it defaults
as class variables (using English spelling ;-) :
{}
Which don't show up in the instance dict, but do show up as attributes: 255

Then we can update the instance dict that holds its attributes:
And they show up, shadowing the class vars{'blue': 333, 'green': 222, 'red': 111}

You can do one attribute this way:{'blue': 333, 'green': 222, 'red': 'RED'}

though this is obviously more concise:
The class vars are still there, even though we don't have a local name binding for the class:
[0, 0, 255]

The instance is separate: {'blue': 333, 'green': 'GREEN', 'red': 'RED'}

We can clear those attributes from the instance dict:{}

And then they don't shadow the class vars, so getting attributes make the class vars show again:
[getattr(colour, c) for c in 'red green blue'.split()]
[0, 0, 255]

Or: [0, 0, 255]

Actually, you could make that a few characters shorter using a temporary short name to make
a kind of with inside a list comprehension:
>>> [[c.red, c.green, c.blue] for c in [colour]][0]
[0, 0, 255]

Though list comprehensions leak bindings: <__main__.Colour object at 0x02F8FFCC>

Which generator expressions don't:
>>> del c
>>> list(([c.red, c.green, c.blue] for c in [colour]))[0] [0, 0, 255]
>>> c
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'c' is not defined


Or we can get the pairs and build a dict:
[(c,getattr(colour, c)) for c in 'red green blue'.split()] [('red', 0), ('green', 0), ('blue', 255)]
dict([(c,getattr(colour, c)) for c in 'red green blue'.split()])
{'blue': 255, 'green': 0, 'red': 0}

Of course, rgb is usually ordered, so why not
(0, 255, 0)

class color: # americanized
red = 0
blue = 255
green = 0

The problem is, you have made colour (returning to English spelling
instead of foreign) into a class. If you need two colour variables, you
have to duplicate the code for the class (perhaps only changing the
numeric constants. You can't even make instances from the class, because
they all share the same RGB values, which is pretty useless if they are
meant to represent different colours.

Less typing than pascal.

You have missed the point. I'm not comparing Python vs Pascal for
creating records representing RBG values. I'm talking about a Pascal
feature that reduced typing by allowing you to use an implicit record.
Here is one possible way you might use such a feature as a Python idiom,
letting "with" specify an implicit object. Instead of doing this:

# read a class attribute
print myobject.__class__.myattribute
# set an instance attribute
myobject.widget.datapoints[myobject.collector] \
= myobject.dispatcher(myobject.widget.current_value)

you might do this:

with myobject:
# read a class attribute
print .__class__.myattribute
# set an instance attribute
.widget.datapoints[.collector] = .dispatcher(.widget.current_value)

def mywith(o=myobject):
# read a class attribute
print o.__class__.myattribute
# set an instance attribute
o.widget.datapoints[o.collector] = o.dispatcher(o.widget.current_value)
mywith()

Or if we had a lambda-replacing anonymous def permitting full suites:
(def(o=myobject):
# read a class attribute
print o.__class__.myattribute
# set an instance attribute
o.widget.datapoints[o.collector] = o.dispatcher(o.widget.current_value)
)()

Is a one-character prefix to the dot objectionable?
Using := and = for assignment and equality is precisely as stupid as using
= and == for assignment and equality. Perhaps less stupid: why do we use
== for equals, but not ++ for plus and -- for minus?
I agree, but I think := would be nice in python for RE-binding an existing
binding, wherever it is seen from the local context. Thus you could
write

def foo(): x:=123

and
x = 456
def bar():
x = 789
foo() # finds and rebinds local x
print x
bar() # -> 123
print x # -> 456
foo() # finds and rebinds the global x
print x # -> 123

but
del x
foo() #-> NameError exception, can't find any x to rebind

hm, wandered a bit OT there, ;-/

Regards,
Bengt Richter
 
T

Terry Reedy

Mandus said:
Fri, 24 Jun 2005 16:31:08 +0100 skrev Tom Anderson:

u-huu... I wasn't aware of that. It is really a consensus on this; that
removing map, filter, reduce is a good thing? It will render a whole lot
of my software unusable :(

In his State of Python 2005 address, Guido estimated 1/2 +1, 1/4 +/-0,
1/4 -1 on this. So majority of those with opinion, not 'consensus'. Then
there is his vote...

Terry J. Reedy
 
S

Steven D'Aprano

Sat, 25 Jun 2005 16:06:57 GMT skrev Lee Harr:

but lambda is grammar, so probably not so easy to import?


"from __future__ import something" can change the compile-time behaviour
of Python, so it is possible.
 
J

James Stroud

The problem is, you have made colour (returning to English spelling
instead of foreign) into a class. If you need two colour variables, you
have to duplicate the code for the class (perhaps only changing the
numeric constants. You can't even make instances from the class, because
they all share the same RGB values, which is pretty useless if they are
meant to represent different colours.

py> class color:
.... pass
....
py> def with(classname, **kwargs):
.... classname.__dict__.update(kwargs)
....
py> with(color, red=0,
.... blue=255,
.... green=255)
py>
py> color.blue
255

Is this what you want to do?
Using := and = for assignment and equality is precisely as stupid as using
= and == for assignment and equality. Perhaps less stupid: why do we use
== for equals, but not ++ for plus and -- for minus?

The colons are to make it look more official or something. They are useless
and hence stupid. The two equals signs for comparison could be argued to be
redundant, but the colons are absolutely unecessary. I thought they were
pointless 18 years ago when I learned pascal in highschool and after 20
years, I still think they are still pointless.

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
S

Steven D'Aprano

With PEP343 (I guess in Python 2.5), you will be able to do something like:
with renamed(colour) as c:
c.red = 0; c.blue = 255; c.green = 0

I think however it is bad. Better solutions to me would be:

colour.setRgb(0, 255, 0)

But that is no help, because the setRgb method will be implemented as

def setRgb(r, g, b):
self.red = r; self.green = g; self.blue = b

which is exactly the usage case for a with statement:

def setRgb(r, g, b):
with self:
.red = r; .green = g; .blue = b
or

c = myVeryLongNameColour
c.red = 0; c.blue = 255; c.green = 0

Namespace pollution. It might not matter if c is a temporary variable
inside a function or method, but it does matter if your top-level code is
full of such constructs. Or for that matter, your interactive Python
session.
 
S

Steven D'Aprano

No. There is no hope of ever writing fast code when you do not actually
measure its performance.


Good grief! You've been spying on Mandus! How else could you possibly know
that he doesn't measure performance? Are you running a key-logger on his
machine? *wink*

For the record, perhaps now is a good time to mention that even Guido
recommended the use of map, filter and reduce in some circumstances:

"Try to use map(), filter() or reduce() to replace an explicit for loop,
but only if you can use a built-in function: map with a built-in function
beats for loop, but a for loop with in-line code beats map with a lambda
function!"

http://www.python.org/doc/essays/list2str.html

He specifically mentions that the reason map will often beat a for loop is
that it moves the work out of Python into the underlying C code.

That is also one of the reasons that ''.join(L) is faster than

s = ''
for item in L:
s = s + item

Do we really need to profile our code every single time to know this?
Isn't it reasonable to just say, "I use join because it is faster than
adding strings" without being abused for invalid optimization?
 
S

Steven D'Aprano

Of course, in a Python 3000 world, nothing stops anyone from using their
own extension module implementing map, filter, and reduce if they really
want to. TSBOOOWTDI in the language/stdlib, but it shouldn't stop anyone
from using other ways to do it that aren't in the stdlib if the
tradeoffs are right for them.

Now that's a good point. Since Guido has said that one of the major
motivations for removing the functional programming tools like map, filter
and reduce is that There Should Be Only One Obvious Way To Do It, and
Guido also seems to really like list comprehensions, is it fair to
assume that for-loops will be removed from Python 3000 too?

Or are they safe until Python 4000?

*wink*

Of course, I also know that Guido has said a foolish consistency
is the hobgoblin of little minds, and I would never accuse him of being a
little mind. But one of the things I like about Python is that it has
found a nice balance between There Is Always Another Way, and The Language
Is A Straight Jacket.

It is blindingly easy to refactor map and filter as in-line list comps,
and Guido's comments suggest to me that they are safe until list comps are
significantly faster. But reduce needs to be re-factored as a for loop,
with all the disadvantages that implies. I think that if people like
Mandus have good real-world usage cases for reduce, it can be saved, at
least as part of itertools.
 
S

Steven D'Aprano

Python is more about readability than raw speed, and I prefer a for-loop
over reduce() in that respect, too.

Fascinating. I prefer reduce for readability. "Reduce this list to one
value, using this known behaviour" seems to work for me better than:

"Oh look, here is a new name being defined. What is it for I wonder? Now
it is being used in a for loop. Ah, the loop appears to be implementing
the well-known reduce behaviour from Lisp. I bet that means that the name
is a temporary placeholder just being used to hold the intermediate
results of from the for loop. Yes, that seems to be the case."

Funny how people differ in what they find readable :)
 
S

Steven D'Aprano

py> class color:
... pass
...
py> def with(classname, **kwargs):
... classname.__dict__.update(kwargs)
...
py> with(color, red=0,
... blue=255,
... green=255)
py>
py> color.blue
255

Is this what you want to do?

No it isn't. That doesn't help at all if you want to do something
other than assigning to instance attributes.

For starters, it doesn't help me do this:

with colour:
print "Blue =", .blue
print "Green =", .green
print "Red =", .red

or anything more complex:

with my_directory_object:
L = .raw_paths
L.append("~/custom/")
# move the last directory looked to the front
# and the current directory to the end
.normalise(L, first=.last_dir, last=".")
.paths = L
try:
.currentpos += 1
except AttributeError:
.currentpos = 0

The point is that a hypothetical "with" block would have to allow
arbitrary access to dotted names: getting, setting, deletion, and method
calling, not just one very limited form of keyword assignment.


The colons are to make it look more official or something.

That is the most ridiculous thing I have ever heard about a programming
language.

Has it escaped your notice that every language has to distinguish in
some way between "x equals 1" in the sense of assignment and "x equals 1"
in the sense of comparisons? "x = 1" is ambiguous.

A language might use constructs like:

"SET x = 1" and "x = 1"

for assignment and comparison, or do what Python does:

"x = 1" and "x == 1"

or do what Pascal does:

"x := 1" and "x = 1"

Even if the compiler can always unfailing tell them apart from context,
for the sake of the human programmers who have to read and write the code,
it is important to have two different operators.

They are useless and hence stupid.

Useless huh? Just try leaving them out and see how useless they are.
The two equals signs for comparison could be argued to be
redundant,

No they aren't redundant, because assignment and equality testing are very
different. And in Python, you can even use them in the same place, so you
can't expect the compiler to tell them apart from context.

py> x = 2 # did I mean assignment or comparison?
but the colons are absolutely unecessary. I thought they were
pointless 18 years ago when I learned pascal in highschool and after 20
years, I still think they are still pointless.

You didn't learn Pascal very well then if you can't see the difference
between assignment and equality testing.
 
S

Steven D'Aprano

How do you like the following?
{}

The single line replacing
"""
with colour do begin
red := 0; blue := 255; green := 0;
end;
"""
follows:


The point is that a hypothetical "with" block would have to allow
arbitrary access to dotted names: getting, setting, deletion, and method
calling, not just one very limited form of keyword assignment.

I understand how to manipulate __dict__ as an more complicated (dare I say
obfuscated?) way of assigning to object attributes.


[snip]
We can clear those attributes from the instance dict:
{}

Which has the unfortunate side effect of also destroying any other
instance attributes.

you might do this:

with myobject:
# read a class attribute
print .__class__.myattribute
# set an instance attribute
.widget.datapoints[.collector] = .dispatcher(.widget.current_value)

def mywith(o=myobject):
# read a class attribute
print o.__class__.myattribute
# set an instance attribute
o.widget.datapoints[o.collector] = o.dispatcher(o.widget.current_value)
mywith()
[snip]

Is a one-character prefix to the dot objectionable?

That's a good workaround, subject to namespace pollution issues, and one
that I'm aware of. Although do you really want to be creating a unique
function definition every time you want to use the with idiom?

I'm not about to stop using Python because of the lack of Pascal-like
"with" blocks. It is a nice feature to have, but I'm aware that Guido
prefers explicit to implicit and "with" is extremely implicit.
 
S

Steven D'Aprano

I agree, but I think := would be nice in python for RE-binding an existing
binding, wherever it is seen from the local context. Thus you could
write

def foo(): x:=123

and
x = 456
def bar():
x = 789
foo() # finds and rebinds local x
print x
bar() # -> 123
print x # -> 456
foo() # finds and rebinds the global x
print x # -> 123

but
del x
foo() #-> NameError exception, can't find any x to rebind

hm, wandered a bit OT there, ;-/

Given how much the use of global variables are discouraged, is it a
good idea to allow even more inter-namespace interactions?
 
P

Peter Otten

Steven said:
Good grief! You've been spying on Mandus! How else could you possibly know
that he doesn't measure performance? Are you running a key-logger on his
machine? *wink*

His mentioning reduce() as a performance panacea was a strong indication
even without looking over his shoulders. He filled in some conditions in a
later post, but "sing reduce ... performs better [than a for-loop]" is
just wrong.
For the record, perhaps now is a good time to mention that even Guido
recommended the use of map, filter and reduce in some circumstances:

Personally I wouldn't rely on authority when I can measure without much
hassle. And the lesson I take from Guido's essay is rather how he got to
his conclusions than what his actual findings were. After all, Python may
have advanced a bit since he wrote the text.
Do we really need to profile our code every single time to know this?

No. Only if we care about the performance of a particular piece. And if we
do we are sometimes in for a surprise.
Isn't it reasonable to just say, "I use join because it is faster than
adding strings" without being abused for invalid optimization?

OK, I am making a guess: "".join(strings) is more often faster than
naive string addition than reduce() wins over a for-loop.

I don't think my pointed comment qualifies as "abuse", by the way.

Peter
 
K

Konstantin Veretennicov

If they go to itertools, they can simply be:

def map(f, *iterables):
return list(imap(f,*iterables))

def filter(f, seq):
return list(ifilter(f,seq))
from itertools import ifilter
def filter(f, seq): .... return list(ifilter(f,seq))
filter(str.isalpha, 'not quite!') ['n', 'o', 't', 'q', 'u', 'i', 't', 'e']
__builtins__.filter(str.isalpha, 'not quite!')
'notquite'

- kv
 
T

Terry Hancock

Using := and = for assignment and equality is precisely as stupid as using
= and == for assignment and equality. Perhaps less stupid: why do we use
== for equals, but not ++ for plus and -- for minus?

Probably the most pointless Python wart, I would think. The =/==
distinction makes sense in C, but since Python doesn't allow assignments
in expressions, I don't think there is any situation in which the distinction
is needed. Python could easily figure out whether you meant assignment
or equality from the context, just like the programmer does.

BASIC did it that way, IIRC. It always seemed like C was seriously twisted
for letting you get away with assignment in expressions in the first place.

I don't think Python's use of "==" has *ever* helped me find a bug, it
just creates them. I really think "=" ought to be accepted as well, and
"==" deprecated.

But, hey, nobody asked me, I guess. And it doesn't kill me to type the
extra "=". ;-)

Cheers,
Terry
 
T

Torsten Bronger

Hallöchen!

Terry Hancock said:
[...]

BASIC did it that way, IIRC.
Right.

[...]

I don't think Python's use of "==" has *ever* helped me find a
bug, it just creates them. I really think "=" ought to be
accepted as well, and "==" deprecated.

However, then you must forbid a=b=1 for assigning to two variables
at the same time.

Tschö,
Torsten.
 
T

Terry Hancock

Hallöchen!
However, then you must forbid a=b=1 for assigning to two variables
at the same time.

Why? It's already handled as an exception in the syntax.

In C, what you say makes sense, because "b=1" is an expression as
well as an assignment. But I don't think Python reads it that way -- it
just has code to recognize multiple assignment as a statement. I think
I remember reading that in the Language Reference or something.

Cheers,
Terry
 
R

Robert Kern

Terry said:
Why? It's already handled as an exception in the syntax.

In C, what you say makes sense, because "b=1" is an expression as
well as an assignment. But I don't think Python reads it that way -- it
just has code to recognize multiple assignment as a statement. I think
I remember reading that in the Language Reference or something.

You need to differentiate

a = b = 1

from

a = b == 1

--
Robert Kern
(e-mail address removed)

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
 
R

Roel Schroeven

Terry said:
Probably the most pointless Python wart, I would think. The =/==
distinction makes sense in C, but since Python doesn't allow assignments
in expressions, I don't think there is any situation in which the distinction
is needed. Python could easily figure out whether you meant assignment
or equality from the context, just like the programmer does.

There are situations where Python can't figure it out:
2 2 2
 
R

Roy Smith

Steven D'Aprano said:
Using := and = for assignment and equality is precisely as stupid as using
= and == for assignment and equality.

On the other hand, == is easier to type than := (two taps on the same key
vs two different keys, and at least on a US/English keyboard, no shift key
required). Not only that, but := is more likely to be turned into some
bizarre smiley face by brain-dead IM clients :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top