On Thu, 21 Jan 2010 22:51:34 +0100, Martin Drautzburg wrote: > Thanks for all the answers. Let me summarize > > (1) I fail to see the relevance of > >>> def move( direction ): > ... print( "move " + str( direction ) ) ... > >>> move( "up" ) > move up
I'm glad it's not just me then. > not only in the context of my question. And I don't see an abuse of the > language either. Maybe this could pass as a Zen Puzzle. > > (2) Using enum's was suggested. That is good to know, but again it is > just a way to define constants in the caller's namespace. I think this really is the correct solution for your problem. In Python, the standard place to have such public constants is at the module level, not the function or class. I think you're worrying unnecessarily about "namespace pollution" -- the module namespace is *exactly* the right place for them. If two functions both need UP, DOWN, etc symbols, then either: (1) they can just use the same symbols; or (2) if they can't, then they don't belong in the same module. An example from the standard library: the re module defines constants I, L, M, etc. representing flags that are passed to the re.compile. They are implemented as integers so they can easily be combined with &, but another implementation might use symbols. You will notice that they're not limited to the re.compile function itself. The caller may very well want to do something like this: # Get some flags for compile: flags = re.I & re.M # ... # much later on # x = re.compile(s, flags) You would force them to do this: # Get some flags for compile: flags = re.compile.I & re.compile.M # ... # much later on # x = re.compile(s, flags) which is, in my opinion, a needless level of indirection and possibly in violation of Demeter's Law. > (3) Then somone suggested to tie the constants to the function itself, > as in > def move(direction): > print "moving %s" % direction > > move.UP = 'up' > move.DOWN = 'down' > > This is quite nice. I would call it a horrible, horrible, horrible code smell. A stench in fact. In my opinion, such attributes tied to the function should be treated as internal to the function, and not the public interface. I wouldn't go quite so far as to say they should be treated as private, but having the caller use them should be rare and unusual. > Then again the "move." is just some object which > allows attributes, and which only happens to have the same name as the > function. Well in this case it IS the function, alright, but I could > just as well have used a Class as in > > class m: pass > m.UP = 'up' 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") Furthermore, the extra layer of indirection with the m.* doesn't give you anything useful. Think about using this: # choose a direction at random direction = random.choice([m.UP, m.DOWN, m.LEFT, m.RIGHT]) move(direction) What benefit is the extra layer of indirection? It just adds noise to the code. Surely this is better? UP, DOWN, LEFT, RIGHT = "up down left right".strip() direction = random.choice([UP, DOWN, LEFT, RIGHT]) move(direction) That's much clearer. In my opinion, if you want to prohibit users from passing a string (or integer) equal to your constants, so that move('up') does not work (in other words, they are forced to use the constants you provide) then Ben Finney's enum solution is probably the correct way to do it. But if you don't care, then the simplest solution is to define the constants you care about in the module, using either strings or ints, and then let the caller choose between using your named constants or not: move(UP) move('up') > (4) Finally someone mentioned DSLs. I guess thats absolutely correct. > This is what I am struggeling to achieve. I did a little googling ("how > to write DSLs in python"), but haven't found anything appealing yet. Any > pointers would be appreciated. That truly is using a bulldozer to crack a peanut. > (5) Here is something I came up with myself: > > def symbols(aDict): > aDict["foo"] = "bar" > > def someFunction(aFoo): > print aFoo > > symbols(locals()) > someFunction (foo) #Eh voila: foo is magically defined > prints: bar > > The call to symbols(locals()) is the "magic, magic" I supected would be > required in my original posting. If someFunction was a member of a > class, the symbols would be properly tied to that class (albeit not the > individual function), but still good enough. I disagree about it being "proper" to tie such public symbols to the class. But in any case, what you're trying to do is not supported by Python. If it works, that's a happy accident. "The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter." http://docs.python.org/library/functions.html#locals > I suppose I could wrap it > in a decorator, which would also do the "unmagic". > > In any case, getting the context right seems to be the biggest problem. > If I don't want to pollute my namespace, It's not pollution. The module namespace is the right place for such public constants. -- Steven -- http://mail.python.org/mailman/listinfo/python-list