Symbols as parameters?

A

Alf P. Steinbach

* Diez B. Roggisch:
Am 21.01.10 19:48, schrieb Alf P. Steinbach:
* Diez B. Roggisch:
Am 21.01.10 12:58, schrieb Alf P. Steinbach:
* Stefan Behnel:
Alf P. Steinbach, 21.01.2010 11:38:
* Carl Banks:
On Jan 20, 11:43 pm, Martin Drautzburg <[email protected]>
[snip]
What I am really looking for is a way

- to be able to call move(up)
- having the "up" symbol only in the context of the function
call
Short answer is, you can't do it.

On the contrary, it's not difficult to do.

I provided an example in my answer to the OP (first reply in the
thread).

Erm, no, you didn't. You showed a) how to pass a string constant
into a
function and b) how to pass a value from a bound variable. None of
that is
helpful to the OP's problem.

Perhaps look again at that example. It demonstrates exactly what the OP
asks for.

Perhaps look again at the requirements:

"""
- the parameter IS REALLY NOT A STRING, but a direction
"""

So?

Oh please. You claim you provided exactly what the OP asked for. But in
the body of move, all you can do is to compare the direction parameter
tco "up", not to UP. So no, you provided *something*, but not what the
OP asked for.

Pardon me for not taking you seriously or not getting the joke, if that's what
it's meant as.


Cheers,

- Alf
 
D

Diez B. Roggisch

Am 21.01.10 20:01, schrieb Alf P. Steinbach:
* Diez B. Roggisch:
Am 21.01.10 19:48, schrieb Alf P. Steinbach:
* Diez B. Roggisch:
Am 21.01.10 12:58, schrieb Alf P. Steinbach:
* Stefan Behnel:
Alf P. Steinbach, 21.01.2010 11:38:
* Carl Banks:
On Jan 20, 11:43 pm, Martin Drautzburg <[email protected]>
[snip]
What I am really looking for is a way

- to be able to call move(up)
- having the "up" symbol only in the context of the function
call
Short answer is, you can't do it.

On the contrary, it's not difficult to do.

I provided an example in my answer to the OP (first reply in the
thread).

Erm, no, you didn't. You showed a) how to pass a string constant
into a
function and b) how to pass a value from a bound variable. None of
that is
helpful to the OP's problem.

Perhaps look again at that example. It demonstrates exactly what
the OP
asks for.

Perhaps look again at the requirements:

"""
- the parameter IS REALLY NOT A STRING, but a direction
"""

So?

Oh please. You claim you provided exactly what the OP asked for. But
in the body of move, all you can do is to compare the direction
parameter tco "up", not to UP. So no, you provided *something*, but
not what the OP asked for.

Pardon me for not taking you seriously or not getting the joke, if
that's what it's meant as.

No joking, unless you started it somewhere earlier. The OP didn't want
to compare to a string, yet your "example" forces him to exactly do
that. If not, would you care to show us the fulfillment of "the
parameter IS REALLY NOT A STRING, but a direction" in your example? Thanks.

You see, it seems that you agreeing to be wrong is something your are so
adamantly refusing to acknowledge that I'm inclined to believe that in
the event of this really happen one day, a great rift in the very fabric
of space and time would appear, and the world would end. If this
conversation was in my native language and not in yours, I'd might give
it a shot, just to see what really happens. But as it isn't, and I guess
everybody else except you knows that your wrong - I wont.

HTH,

Diez
 
A

Alf P. Steinbach

* Diez B. Roggisch:
Am 21.01.10 20:01, schrieb Alf P. Steinbach:
* Diez B. Roggisch:
Am 21.01.10 19:48, schrieb Alf P. Steinbach:
* Diez B. Roggisch:
Am 21.01.10 12:58, schrieb Alf P. Steinbach:
* Stefan Behnel:
Alf P. Steinbach, 21.01.2010 11:38:
* Carl Banks:
On Jan 20, 11:43 pm, Martin Drautzburg <[email protected]>
[snip]
What I am really looking for is a way

- to be able to call move(up)
- having the "up" symbol only in the context of the function
call
Short answer is, you can't do it.

On the contrary, it's not difficult to do.

I provided an example in my answer to the OP (first reply in the
thread).

Erm, no, you didn't. You showed a) how to pass a string constant
into a
function and b) how to pass a value from a bound variable. None of
that is
helpful to the OP's problem.

Perhaps look again at that example. It demonstrates exactly what
the OP
asks for.

Perhaps look again at the requirements:

"""
- the parameter IS REALLY NOT A STRING, but a direction
"""

So?

Oh please. You claim you provided exactly what the OP asked for. But
in the body of move, all you can do is to compare the direction
parameter tco "up", not to UP. So no, you provided *something*, but
not what the OP asked for.

Pardon me for not taking you seriously or not getting the joke, if
that's what it's meant as.

No joking, unless you started it somewhere earlier. The OP didn't want
to compare to a string, yet your "example" forces him to exactly do
that. If not, would you care to show us the fulfillment of "the
parameter IS REALLY NOT A STRING, but a direction" in your example? Thanks.

Just use a "direction" instead of a number (if you didn't like the number).

I'm sorry that I couldn't believe that you didn't understand that.

But OK, you didn't.

The OP gave no definition of his "direction" though, so you'll have to use your
good sense about possibilities for what it could be.

From the context and later comments (especially about "import") my guess us
that he's talking about numbers denoting directions, but you'd have to ask him.

You see, it seems that you agreeing to be wrong is something your are so
adamantly refusing to acknowledge that I'm inclined to believe that in
the event of this really happen one day, a great rift in the very fabric
of space and time would appear, and the world would end. If this
conversation was in my native language and not in yours, I'd might give
it a shot, just to see what really happens. But as it isn't, and I guess
everybody else except you knows that your wrong - I wont.

The above is a silly ad hominem attack, containing 1 lie, and trying to confuse
the issue: you're posting this in a different part of the thread as a response
to Carls Banks being proved wrong by my example. Incidentally, he also resorts
to ad hominem. Sadly it seems to be a common response pattern in this group.

Do you understand how bad that makes you look?


Cheers & hth.,

- Alf
 
C

Carl Banks

* Carl Banks:




* Carl Banks:
On Jan 20, 11:43 pm, Martin Drautzburg <[email protected]>
[snip]
What I am really looking for is a way
        - to be able to call move(up)
        - having the "up" symbol only in the context of the function call
Short answer is, you can't do it.
On the contrary, it's not difficult to do.
I provided an example in my answer to the OP (first reply in the thread).
Your example doesn't remotely do what the OP was asking for.  In fact
your example is so preposterous I question your sanity.

Your first sentence is incorrect, your second sentence is a silly attempt at
getting personal.
Usually people abuse the language to achieve something (ostensibly)
useful.  Your example is so useless I don't think I would even call it
abuse.

You are correct that it's useless. The OP asked for a construct to do a useless
thing. The presented construct does exactly what the OP asked for: useless.
As best as I can tell, what it is is you attempting to make yourself
look like some kind of badass by answering some absurdly literal
interpretation of the OP's question.

Hm, there are ways to do things, even the ad hominem thing. You just present
yourself as one using strong words when you're proven wrong. Myself I'm not
foreign to strong words :), but I wouldn't dream of applying them to a person.

The above is very, uh, primitive.

Besides, it's quite silly to get angry when you're proved to be wrong. :)
Except you haven't even done that:
class using_directions:
    up = 42
    move( up )
    print up # <- clearly not confined to context of function call

You know, I didn't think of that ingenious thing, that it would be possible to
*modify* the example so that it no longer fit the OP's literal description. Thx!

I'm not sure if you're trolling, insane, or just stupid; regardless,
I'm done with you.


Carl Banks
 
A

Alf P. Steinbach

* Carl Banks:
* Carl Banks:
* Carl Banks:
On Jan 20, 11:43 pm, Martin Drautzburg <[email protected]>
[snip]
What I am really looking for is a way
- to be able to call move(up)
- having the "up" symbol only in the context of the function call
Short answer is, you can't do it.
On the contrary, it's not difficult to do.
I provided an example in my answer to the OP (first reply in the thread).
Your example doesn't remotely do what the OP was asking for. In fact
your example is so preposterous I question your sanity.
Your first sentence is incorrect, your second sentence is a silly attempt at
getting personal.
However, it's IMHO an abuse of the language, not something that one should do.
Usually people abuse the language to achieve something (ostensibly)
useful. Your example is so useless I don't think I would even call it
abuse.
You are correct that it's useless. The OP asked for a construct to do a useless
thing. The presented construct does exactly what the OP asked for: useless.
As best as I can tell, what it is is you attempting to make yourself
look like some kind of badass by answering some absurdly literal
interpretation of the OP's question.
Hm, there are ways to do things, even the ad hominem thing. You just present
yourself as one using strong words when you're proven wrong. Myself I'm not
foreign to strong words :), but I wouldn't dream of applying them to a person.

The above is very, uh, primitive.

Besides, it's quite silly to get angry when you're proved to be wrong. :)
Except you haven't even done that:
class using_directions:
up = 42
move( up )
print up # <- clearly not confined to context of function call
You know, I didn't think of that ingenious thing, that it would be possible to
*modify* the example so that it no longer fit the OP's literal description. Thx!

I'm not sure if you're trolling, insane, or just stupid; regardless,
I'm done with you.

Piling more ad hominem attacks on top of your previous is pretty silly.

You were technically wrong, that's no big issue, everybody is wrong now and then.

But reacting to a polite notification of your error, by going all out with
various personal accusations, doesn't give anybody a positive impression of you.


Cheers & hth.,

- Alf
 
M

Martin Drautzburg

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

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.

(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. 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'


(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.

(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 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, those symbols need to be
defined in some context but undefined in others. AFAIK there are not
really "blocks" in python and lexical scoping is present primarily in
functions.
 
A

Alf P. Steinbach

* Martin Drautzburg:
Thanks for all the answers. Let me summarize

(1) I fail to see the relevance of
... print( "move " + str( direction ) )
...
move up

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.

Oh. You focused on the wrong details, then. Sorry for not providing a textual
explanation, but I thought anyone not understanding it would just ask (that's
normal in other Usenet groups that I'm familiar with).

So, explanation...

Here's your problem description, from the start of the thread:

<quote>
What I am really looking for is a way

- to be able to call move(up)
- having the "up" symbol only in the context of the function call

So it should look something like this

.... magic, magic ...
move(up)
.... unmagic, unmagic ...
print up

This should complain that "up" is not defined during the "print" call,
but not when move() is called. And of course there should be as little
magic as possible.
</quote>


The code corresponding to your first "magic, magic ..." is

class using_directions:
# Whatever statement (import?) defines symbolic directions goes here

Then comes your -- note the added indentation

move( up )

Your "... unmagic, unmagic" is simply to go back to the previous indent level.

So your example's following

print up

at this point complaints that "up" is not defined, as you require (no general
namespace pollution, although there is a slight but controllable pollution,
namely the class name).

Not that I recommend this technique. ;-) But it does exactly what you asked,
quoted above.

The best technique in my view is what you came up with yourself in the article
I'm responding to (but snipped by me), namely a class with the constants and the
function. It doesn't do what you required originally. But it's much better! :)


Cheers & hth.,

- Alf
 
M

Martin Drautzburg

Here is a complete expample using a decorator, still a bit noisy

def move(aDirection):
print "moving " + aDirection

#Here comes the decorator
def scope(aDict):
def save(locals):
"""Set symbols in locals and remember their original state"""
setSymbols={}
unsetSymbols=[]
for i in ("up", "down", "left", "right"):
if locals.has_key(i):
setSymbols = locals
else:
unsetSymbols.append(i)
# define the new symbols
locals = i

return setSymbols, unsetSymbols

def restore (locals, set, unset):
"""restore locals from set and unset"""
for i in set.keys():
locals = set
for i in unset:
del(locals)

def callFunc(f):
"""Main decorator"""
set, unset = save(aDict)
f()
restore(aDict, set, unset)
return callFunc


# --------------------------------------
# using it
# --------------------------------------
# a variable defined in the outer scope
up="outerScopeUp"

# magic, magic (still too noisy for my taste)
@scope (locals())
def _():
move(up)
move(down)
move(left)
move(right)

#verify the the outer scope variable hasn't changed
print "in the outer scope up is still:", up
print
print "this should fail:"
down

# --------------------------------------
# Output
# --------------------------------------

moving up
moving down
moving left
moving right
in the outer scope up is still: outerScopeUp

this should fail:
Traceback (most recent call last):
File "<stdin>", line 50, in <module>
NameError: name 'down' is not defined
 
D

Diez B. Roggisch

Am 21.01.10 22:51, schrieb Martin Drautzburg:
Thanks for all the answers. Let me summarize

(1) I fail to see the relevance of... print( "move " + str( direction ) )
...move up

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.

(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. 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'


(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.

(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

http://docs.python.org/library/functions.html#locals

If it works, it's more an accident than anything else, and can go away
without prior notice.


Diez
 
C

Carl Banks

Thanks for all the answers. Let me summarize [snip]
(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.

It'll at least corral the symbols you want.


[snip]
(4) Finally someone mentioned DSLs. I guess thats absolutely correct.
This is what I am struggeling to achieve.

I see. Well, Python is a poor choice for defining an internal DSL
(i.e., DSL using the general language's syntax), because it's
(deliberately) rigid in both grammar and semantics. Soon as you want
to do something a little different you're out of luck.

Python is somewhat better suited for external DSLs.
I did a little googling ("how
to write DSLs in python"), but haven't found anything appealing yet.
Any pointers would be appreciated.

Paul McGuire should be by to recommend PyParsing shortly.

It's not really hard to write a simple DSL if you know how. It is
pretty hard to learn how, though. Tools like PyParsing help a lot.

(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 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, those symbols need to be
defined in some context but undefined in others. AFAIK there are not
really "blocks" in python and lexical scoping is present primarily in
functions.

That's pretty much the issue.

BTW, I'm sorry that the thread got a little flamey there.


Carl Banks
 
S

Steven D'Aprano

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.
 
M

MRAB

Steven D'Aprano wrote:
[snip]
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
[snip]

That should be:

flags = re.I | re.M

of course. :)
 
S

Steven D'Aprano

Steven D'Aprano wrote:
[snip]
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
[snip]

That should be:

flags = re.I | re.M

of course. :)

Dammit! No wonder my regexes never work as I expect!!!


Thanks for the correction.
 
S

Stefan Behnel

Alf P. Steinbach, 21.01.2010 20:24:
Do you understand how bad that makes you look?

I think the right thing to say at this point is "don't feed the troll".

Stefan
 
M

Martin Drautzburg

Carl said:
I see. Well, Python is a poor choice for defining an internal DSL
(i.e., DSL using the general language's syntax), because it's
(deliberately) rigid in both grammar and semantics.

I had this impression too.
Paul McGuire should be by to recommend PyParsing shortly.

I looked it up and it seems to be about parsing strings. This is not
what I am looking for as it would create a separate world outside of
python. But I haven't looked deeply yet.
 
M

Martin Drautzburg

Steven said:
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:

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. If another module defines "up" in some different
way, I am in trouble. To circumvent this I would have to "import
Movements", but then I's have to write

move(directions.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(). Defining the symbols at module level
solves THIS problem, but it leaves the above other problems. Still I
like this best so far, because it is the standard way of doing this.
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.

So scoping should be at module level? That makes some sense.
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 wheras move("upx") requires extra code in move() to
raise an exception. 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.
That truly is using a bulldozer to crack a peanut.

Well I guess I am really trying to implement a DSL (its about music). I
just wasn't aware of that until someone mentioned DLSs here.
The "symbols" problem is one problem I could not come up with anything
delightful (the other one is getting rid of parenthesis).

(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."

Two posters stronly discouraged that solution. And even with a decorator
it does not look all that beautiful. I'll abandon this one.
 
A

Alf P. Steinbach

* Stefan Behnel:
Alf P. Steinbach, 21.01.2010 20:24:

I think the right thing to say at this point is "don't feed the troll".

I find it amazing that you continue this kind of ad hominem attack. You leave it
open who you regard as trolling, but when you do ad hominem you're essentially
saying "I'm technically wrong but I'll win in the personal attack domain".

Do you understand how bad that makes you look?


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Martin Drautzburg:
Here is a complete expample using a decorator, still a bit noisy

def move(aDirection):
print "moving " + aDirection

#Here comes the decorator
def scope(aDict):
def save(locals):
"""Set symbols in locals and remember their original state"""
setSymbols={}
unsetSymbols=[]
for i in ("up", "down", "left", "right"):
if locals.has_key(i):
setSymbols = locals
else:
unsetSymbols.append(i)
# define the new symbols
locals = i

return setSymbols, unsetSymbols

def restore (locals, set, unset):
"""restore locals from set and unset"""
for i in set.keys():
locals = set
for i in unset:
del(locals)

def callFunc(f):
"""Main decorator"""
set, unset = save(aDict)
f()
restore(aDict, set, unset)
return callFunc


# --------------------------------------
# using it
# --------------------------------------
# a variable defined in the outer scope
up="outerScopeUp"

# magic, magic (still too noisy for my taste)
@scope (locals())
def _():
move(up)
move(down)
move(left)
move(right)

#verify the the outer scope variable hasn't changed
print "in the outer scope up is still:", up
print
print "this should fail:"
down

# --------------------------------------
# Output
# --------------------------------------

moving up
moving down
moving left
moving right
in the outer scope up is still: outerScopeUp

this should fail:
Traceback (most recent call last):
File "<stdin>", line 50, in <module>
NameError: name 'down' is not defined


Uhm, interesting technique, technically.

But have you tested this within a function or class, which is what the use of
"locals" implies?

The reason that I ask is that in the documentation of locals() it says this:

Note
The contents of this dictionary should not be modified; changes may not
affect the values of local variables used by the interpreter.

(There's no such note for 'globals').

I have to admit that I was afraid to post this question since my experience in
[comp.lang.python] is that when some technical error is pointed out by me, then
most often the person starts a personal attack and credibility attack, injecting
all kinds of noise -- actually that happened yet again as I was writing this
response to you! But, I figure one shouldn't give up one humanity just because
of one group where that happens regularly. I'm sort of counting on you to prove
that there are, counting myself and one other, and perhaps now you, at least
three persons here who are happy for technical corrections from me.

Or, perhaps there's some aspect of locals(), e.g. in the context of decorators,
that I don't know about and can now learn. :)


Cheers & hth.,

- Alf
 
C

Carl Banks

I looked it up and it seems to be about parsing strings. This is not
what I am looking for as it would create a separate world outside of
python. But I haven't looked deeply yet.

Well, it's not necessarily a whole world outside Python, since an
external DSL can be tied to the underlying to some degree.

For example, a simple external DSL might input a string like this:

"move up"

parse it (such as with PyParsing), and output a string like this:

"move(direction.up)"

which can then be execed. It wouldn't be a whole new language, just
an altered syntax.

However, you are right in that, if you don't want to go creating your
own syntax, PyParsing will be of no help. You'll have to shoehorn
your DSL in a language not well suited for the task as best you can.


Carl Banks
 
J

Jean-Michel Pichavant

Steven said:
(3) Then somone suggested to tie the constants to the function itself,

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.
I don't think so, my solution is perfect :eek:)

Let me clarify, I wouldn't write this piece of code, but the OP seems to
really worry about the 'noise' around its direction definitions. That is
why I removed the constant class definition of DIRECTION, and add
directly those constants in the function itself, allowing to use them
without additional import statements. It is not usual but it is not
*that* smelling.

def move(direction):
"""Move to the given direction.

@param direction: one of the function constant move.UP or move.DOWN
"""
print "moving %s" % direction
move.UP = 'up'
move.DOWN = 'down'


As soon as it is properly documented, as a public interface should be,
it becomes an acceptable design, IMO. Not the design I would choose in
normal circonstances though.

Jean-Michel
 

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
474,001
Messages
2,570,254
Members
46,851
Latest member
CliftonCor

Latest Threads

Top