Symbols as parameters?
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Fri Jan 22 07:35:40 EST 2010
On Fri, 22 Jan 2010 09:12:46 +0100, Martin Drautzburg wrote:
> Defining those symbols at the module level is absolutely fine with me.
> The namespace pollution is indeed my biggest worry. You see, I want to
> be able to type in lots of lines with little effort. Preferably I would
> want to type
>
> move up
>
> I could still live with
>
> move(up)
>
> But then I need to import "from Movements import directions" or
> something like that.
That's one line. It's hardly any cost, and it makes the code
understandable: the reader can see exactly where directions comes from.
This is a Good Thing.
> If another module defines "up" in some different
> way, I am in trouble.
Only if you do this:
from movements import up, down, left, right
from wossnames import up, down, left, right
The solution to this problem is simple: don't do it.
Honestly, you're over-thinking this problem. Such names clashes can't
happen by accident. They can happen through carelessness, but that's no
different from this:
x = 42
# ... much later on ...
x = 23
# ... and later ...
assert x == 42
The only time such name clashes can happen by accident is if you do
from movements import *
which is precisely why that form of import is not recommended.
> To circumvent this I would have to "import
> Movements", but then I's have to write
>
> move(directions.up)
You'd have to say "import directions" to write "move(directions.up)".
Another solution:
import directions
up = directions.up
move(up)
> This is so noisy, I'd rather write
>
> move ("up")
>
> I don't like the quotes. I don't mind that "up" is a string (as someone
> suspected), what I dislike is that "up" was created ad-hoc by the
> caller. Could it be move("UP") as well? You could not tell without
> looking at the code of move().
Or the documentation.
This is an API design decision the designer has to make. Should the move
function use strings or integers or something else to specify the
direction? If strings, should they be case-sensitive or insensitive?
There's no right or wrong answer, all of these things have arguments in
favour and against.
[...]
>> Either way, when you go to *use* the direction, you're still passing a
>> string. There's no difference between:
>>
>> move(m.UP)
>>
>> and just
>>
>> move("up")
>
> The difference is that move(m.UPx) would automatically raise an
> attribute error
and move(UPx) would raise NameError, and move(U P) would raise
SyntaxError. What's your point?
> wheras move("upx") requires extra code in move() to
> raise an exception.
What extra code? Surely move already validates its input? Surely it looks
something like this?
def move(direction):
if direction == 'up':
foo
elif direction == 'down':
bar
elif direction == 'left':
baz
elif direction == 'right':
foobar
else:
raise ValueError("invalid direction")
(or any variation that does the same sort of thing). The point is, you
have to validate that direction is a valid direction anyway -- you can't
trust that the user will only pass valid directions. There's nothing
stopping the caller from saying move([42, 23]) or move(None), so you have
to validate the argument inside the function anyway.
> move("up") just looks sematically wrong to me, in
> contrast len("up") is correct, because it really is an operation on
> Strings. When the caller writes move(up) should should not (need to)
> know what "up" really is behind the scenes.
Again, I point you to Ben Finney's enum module, which I think is exactly
what you want.
--
Steven
More information about the Python-list
mailing list