On Fri, 27 Apr 2012 17:03:19 +0200, Kiuhnm wrote:
> On 4/27/2012 16:09, Steven D'Aprano wrote:
>> On Fri, 27 Apr 2012 13:24:35 +0200, Kiuhnm wrote:
>>> I'd like to change the syntax of my module 'codeblocks' to make it
>>> more pythonic.
>>> Current Syntax:
>>> with res << func(arg1) << 'x, y':
>>> print(x, y)
>>> with res << func(arg1) << block_name << 'x, y':
>>> print(x, y)
>> I'm sorry, I don't see how this is a code block. Where is the code in
>> the block, and how can you pass it to another object to execute it?
> Maybe if you read the entire post...
No, I read the entire post. It made no sense to me. Let me give one example. You state:
The full form is equivalent to
def anon_func(x, y):
print(x, y)
res = func(arg1, block_name = anon_func)
but this doesn't mean anything to me. What's func? Where does it come from? What's arg1? Why does something called block_NAME have a default value of a function instead of a NAME?
How about you give an actual working example of what you mean by a code block and how you use it?
> On Fri, 27 Apr 2012 17:03:19 +0200, Kiuhnm wrote:
>> On 4/27/2012 16:09, Steven D'Aprano wrote:
>>> On Fri, 27 Apr 2012 13:24:35 +0200, Kiuhnm wrote:
>>>> I'd like to change the syntax of my module 'codeblocks' to make it
>>>> more pythonic.
>>>> Current Syntax:
>>>> with res<< func(arg1)<< 'x, y':
>>>> print(x, y)
>>>> with res<< func(arg1)<< block_name<< 'x, y':
>>>> print(x, y)
>>> I'm sorry, I don't see how this is a code block. Where is the code in
>>> the block, and how can you pass it to another object to execute it?
>> Maybe if you read the entire post...
> No, I read the entire post. It made no sense to me. Let me give one
> example. You state:
> The full form is equivalent to
> def anon_func(x, y):
> print(x, y)
> res = func(arg1, block_name = anon_func)
> but this doesn't mean anything to me. What's func? Where does it come
> from? What's arg1? Why does something called block_NAME have a default
> value of a function instead of a NAME?
> How about you give an actual working example of what you mean by a code
> block and how you use it?
The rewriting rules are the following, where X ---> Y means that X is rewritten as Y on the fly:
1)
with res << func(args) << 'x, y':
<code>
--->
def anon_func(x, y):
<code>
res = func(args, anon_func)
2)
with res << func(args) << block_name << 'x, y':
<code>
--->
def anon_func(x, y):
<code>
res = func(args, block_name = anon_func)
That's all.
func is some function which takes a function as a positional argument or as a keyword parameter neamed block_name.
Some examples:
1)
text = "Anyone should be able to read this message!"
with ris << re.sub(r'(\w)(\w+)(\w)', string = text) << repl << 'm':
inner_word = list(m.group(2))
random.shuffle(inner_word)
_return (m.group(1) + "".join(inner_word) + m.group(3))
print(ris)
which prints (something like):
Aynnoe shluod be albe to read tihs msgseae!
2)
numbers = [random.randint(1, 100) for i in range(30)]
with sorted1 << sorted(numbers) << key << 'x':
if x <= 50:
_return(-x)
else:
_return(x)
On Fri, 27 Apr 2012 13:24:35 +0200, Kiuhnm <kiuhnm03.4t.yahoo.it> wrote:
> I'd like to change the syntax of my module 'codeblocks' to make it more > pythonic.
> Current Syntax:
> with res << func(arg1) << 'x, y':
> print(x, y)
> with res << func(arg1) << block_name << 'x, y':
> print(x, y)
> New Syntax:
> with res == func(arg1) .taking_block (x, y):
> print(x, y)
> with res == func(arg1) .taking_block (x, y) as block_name:
> print(x, y)
[snip]
Hey, guys, am I the only one here who can't even guess what
this code does? When did Python become so obscure?
-- To email me, substitute nowhere->spamcop, invalid->net.
Peter Pearson <ppear...@nowhere.invalid> writes:
> On Fri, 27 Apr 2012 13:24:35 +0200, Kiuhnm <kiuhnm03.4t.yahoo.it> wrote:
> > I'd like to change the syntax of my module 'codeblocks' to make it
> > more pythonic.
The “chained callable” style isn't very Pythonic, IMO. Even worse is the
penchant for ‘foo .bar()’, the space obscures the fact that this is
attribute access.
Far from Pythonic, this seems to be an attempt to write some other
language in Python code.
(there were a lot more in the original program where those came from.) Another take-away might be don't use boilerplate, but in the situation I didn't see a simple way to avoid it.
> (there were a lot more in the original program where those came from.) Another take-away
> might be don't use boilerplate, but in the situation I didn't see a simple way to avoid it.
>> (there were a lot more in the original program where those came from.)
>> Another take-away
>> might be don't use boilerplate, but in the situation I didn't see a
>> simple way to avoid it.
> On second thought, BignumPtrType is probably the right name.
(Way off the original topic, aren't we?) I haven't looked inside ctypes, and don't know what kind of thing ctypes.POINTER actually constructs. I was worried about falling into a [[a]]*3 kind of error -- unwittingly sharing a mutable object. I guess I really should look.
>> On second thought, BignumPtrType is probably the right name.
> (Way off the original topic, aren't we?) I haven't looked inside ctypes,
> and don't know what kind of thing ctypes.POINTER actually constructs. I was
> worried about falling into a [[a]]*3 kind of error -- unwittingly sharing a
> mutable object. I guess I really should look.
Better off topic than uninterestingly in topic, IMHO.
Regarding ctypes, try this to convince yourself that there's no problem in reusing BignumPtrType:
from ctypes import POINTER, c_int
assert POINTER(c_int) is POINTER(c_int)
Kiuhnm wrote:
> Regarding ctypes, try this to convince yourself that there's no problem
> in reusing BignumPtrType:
> from ctypes import POINTER, c_int
> assert POINTER(c_int) is POINTER(c_int)
print ('POINTERs are shareable:', ctypes.POINTER (BignumType) is ctypes.POINTER (BignumType))
[ ... ]
('POINTERs are shareable:', True)
> On Apr 30, 2:05 am, Peter Pearson<ppear...@nowhere.invalid> wrote:
>> Hey, guys, am I the only one here who can't even guess what
>> this code does? When did Python become so obscure?
> Thankfully it hasn't. The most Pythonic way to pass around a code
> block is still to use a function.
"Most Pythonic" doesn't mean better, unfortunately.
For instance, assume that you want to write a function that accepts a dictionary of callbacks:
func(some_args, callbacks)
with func(some_args) << ':dict':
with when_odd as 'n':
pass
with when_prime as 'n':
pass
with before_check as '':
pass
with after_check as '':
pass
with func(some_args) << ':dict':
with when_prime as 'n':
pass
with when_perfect as 'n':
pass
with before_reduction as '':
pass
with after_reduction as '':
pass
> with func(some_args) << ':dict':
> with when_odd as 'n':
> pass
> with when_prime as 'n':
> pass
If you actually try that, you will see that it cannot work. You get:
SyntaxError: can't assign to literal
Have you actually tried to use these code blocks of yours? I asked you for a *working* example earlier, and you replied with examples that failed with multiple NameErrors and no hint as to how to fix them. And now you give an example that fails with SyntaxError. I'm reluctantly coming to the conclusion that these "code blocks" of yours simply do not work.
> with before_check as '':
> pass
> with after_check as '':
> pass
You have a bug in one or more of those callbacks.
Of course you do -- all non-trivial software has bugs. The question is, how are you going to find it? You can't unit-test the individual callbacks, because they don't exist in a form that can be tested.
So in this case, even though Python is slightly more verbose, and forces you to have the discipline of writing named functions ahead of time, this is actually a *good* thing because it encourages you to test them.
If the callbacks are trivial functions, the Pythonic way is to use lambdas:
although I would discourage that unless they are *really* trivial. But for callbacks of any complexity, they will need to be tested, otherwise how do you know they do what you want them to do?
Your code blocks make unit testing of the callbacks impossible, and for that reason the Pythonic way is better.
>> with func(some_args)<< ':dict':
>> with when_odd as 'n':
>> pass
>> with when_prime as 'n':
>> pass
> If you actually try that, you will see that it cannot work. You get:
> SyntaxError: can't assign to literal
If you had read the module's docstring you would know that the public version uses
with when_odd << 'n':
pass
> Have you actually tried to use these code blocks of yours? I asked you
> for a *working* example earlier, and you replied with examples that
> failed with multiple NameErrors and no hint as to how to fix them. And
> now you give an example that fails with SyntaxError.
The examples I gave you work perfectly. It's clear that you don't even have the vaguest idea of how my module works or, otherwise, you'd know what you're doing wrong. Again, the module's docstring is your friend.
> You have a bug in one or more of those callbacks.
> Of course you do -- all non-trivial software has bugs. The question is,
> how are you going to find it? You can't unit-test the individual
> callbacks, because they don't exist in a form that can be tested.
It's easy to come up with a solution, in fact those functions /do/ exist. You would know that if you had read the documentation or even my reply to a post of yours.
> So in this case, even though Python is slightly more verbose, and forces
> you to have the discipline of writing named functions ahead of time, this
> is actually a *good* thing because it encourages you to test them.
> If the callbacks are trivial functions, the Pythonic way is to use
> lambdas:
> although I would discourage that unless they are *really* trivial. But
> for callbacks of any complexity, they will need to be tested, otherwise
> how do you know they do what you want them to do?
> Your code blocks make unit testing of the callbacks impossible, and for
> that reason the Pythonic way is better.
Talking with you is a real pain. You're always partial in your opinions and this urge of yours to criticize other's work makes you look dumb or hopefully just lazy.
I can't stand people like you who don't even have the decency of taking the time to read the documentation of a project and just run their mouth without any concern for facts.
What I can't stand is that if I won't reply to your posts other lazy people will believe the nonsense you say, but I'll have to live with that because I've wasted enough time with you.
On Tue, 01 May 2012 19:07:58 +0200, Kiuhnm wrote:
> On 5/1/2012 17:11, Steven D'Aprano wrote:
>>> My way
>>> ------
>>> with func(some_args)<< ':dict':
>>> with when_odd as 'n':
>>> pass
>>> with when_prime as 'n':
>>> pass
>> If you actually try that, you will see that it cannot work. You get:
>> SyntaxError: can't assign to literal
> If you had read the module's docstring
What module?
> you would know that the public version uses
> with when_odd << 'n':
> pass
Then why didn't you write that instead of something that gives SyntaxError? Not once, but EIGHT times.
>> Have you actually tried to use these code blocks of yours? I asked you
>> for a *working* example earlier, and you replied with examples that
>> failed with multiple NameErrors and no hint as to how to fix them. And
>> now you give an example that fails with SyntaxError.
> The examples I gave you work perfectly.
Except they don't.
Look, this isn't difficult. I asked for *working* examples, you gave examples that give NameError. Some of those errors are easy to fix, e.g. by importing the random and re modules. Some of them aren't. What are "ris", "repl", "_return", "sorted1", "key"? Where do they come from? What value should I give them to make your code work?
Code doesn't magically start to work because you declare that it does. Anyone who takes the time to copy and paste your examples into a fresh Python interactive session will see that they don't.
Here's one of your earlier examples. I've removed the unnecessary indentation and made the obvious import, so all it takes to run it is to copy it and paste into the Python prompt:
import random
numbers = [random.randint(1, 100) for i in range(30)]
with sorted1 << sorted(numbers) << key << 'x':
if x <= 50:
_return(-x)
else:
_return(x)
print(sorted1)
If you try it, you get
NameError: name 'sorted1' is not defined
Fix that (how?) and you'll get another NameError, for 'key', and then a third, for '_return'.
The syntax isn't very clear. If I had to guess what it does, I'd predict that maybe it sorts the random list and negates everything <= 50, e.g. given input [5, 99, 34, 88, 70, 2] it returns [-2, -5, -34, 70, 88, 99]. Obviously that's wrong. You say it should return [34, 5, 2, 70, 88, 99].
The Pythonic way to get that result is:
import random
numbers = [random.randint(1, 100) for i in range(30)]
sorted(numbers, key=lambda x: -x if x <= 50 else x)
which is much more straightforward and obvious than yours, and presumably much faster. So even if I could get your example working, it would not be very persuasive.
> It's clear that you don't even
> have the vaguest idea of how my module works or, otherwise, you'd know
> what you're doing wrong.
Well duh. What module? Where do I find it? How am I supposed to know what this module is when you haven't mentioned it?
Believe it or not, the world does not revolve around you. We cannot see what is in your head. If we ask for a WORKING EXAMPLE, you need to give an example that includes EVERYTHING necessary to make it work.
[...]
> Talking with you is a real pain. You're always partial in your opinions
> and this urge of yours to criticize other's work makes you look dumb or
> hopefully just lazy.
> I can't stand people like you who don't even have the decency of taking
> the time to read the documentation of a project and just run their mouth
> without any concern for facts.
What project? You're the one who doesn't tell us what project we're supposed to use, and yet *I'm* the dumb one.
This is comedy gold.
> What I can't stand is that if I won't reply to your posts other lazy
> people will believe the nonsense you say, but I'll have to live with
> that because I've wasted enough time with you.
Whatever man. It's no skin off my nose. I've tried really hard to give your proposal a fair go, but my care factor is rapidly running out if you can't even be bothered to ensure your examples use legal Python syntax.
Steven D'Aprano <steve+comp.lang.pyt...@pearwood.info> writes:
> On Tue, 01 May 2012 19:07:58 +0200, Kiuhnm wrote:
> > [entitled demands]
> Believe it or not, the world does not revolve around you. We cannot
> see what is in your head. If we ask for a WORKING EXAMPLE, you need to
> give an example that includes EVERYTHING necessary to make it work.
To forestall the next obvious but wrong response: no, this is not asking
to see a massive complicated module dumped on us to pore over.
The term missing from Steven's request is “minimal”. When presenting
code for examination by others, we request that you present a complete,
minimal, working example.
Complete, so that we can take what you present and use it without
guessing (likely incorrect guesses) what extra bits you did.
Minimal, so that it contains *only* what is needed to demonstrate what
you're trying to communicate. Yes, this probably means writing an
example specifically to present to us; tough, the job falls to you if
you want us to spend time on your issue.
Working example: so that it actually does what you say it does, and we
can verify that directly instead of speculating.
> [...]
> > Talking with you is a real pain. You're always partial in your
> > opinions and this urge of yours to criticize other's work makes you
> > look dumb or hopefully just lazy.
Sometimes one side of a disagreement is just incorrect, and in those
cases it's good to be partial in one's opinions and to criticise on the
facts.
You have entered may people's kill files, including mine, because of
this inability to take criticism and this tendency to insult others
baselessly.
When would you _ever_ define a function like this? Why are you passing
in _named_ callbacks? Are you calling them by name? Then declare them
in the function signature and rely on scoping. Does func() branch on
existent keys? Then don't write code like that.
At the very _least_, you could change the function call to:
func(some_args, locals())
But as you're _passing them in by name_ why not just make it
func(some_args) and pick them up out of the scope.
_No one_ writes Python code like this. Presenting bad code as
"pythonic" is a bit of a straw man.
> My way
> ------
> with func(some_args) << ':dict':
> with when_odd as 'n':
> pass
> with when_prime as 'n':
> pass
> with before_check as '':
> pass
> with after_check as '':
> pass
This is unintuitive, to say the least. You're effectively replacing
the common form of function definition with "with when_odd as 'n'",
then using the surrounding context manager to limit the scope.
More importantly, _you're naming your "anonymous" code blocks_, I'm
guessing so that func() can choose which ones to use. But if you're
naming them, why not just use a function?
I'm not entirely sure what your 'solution' offers over something like:
class FOO(object):
def __init__(self, fn):
self.fn = fn
with FOO(func) as f:
def before_check(x):
pass
def after_check(x):
pass
def when_odd(x):
pass
def when_prime(x):
pass
f(1)
I called the context manager FOO because I couldn't think of a more
appropriate name (contextscope?)...which is fair, as I can't think of
a use for it either. If you want to automate the function call at the
context manager exit, use something like this instead:
I'm sorry, when would you _ever_ do this? Why are you naming the
functions twice? If you're passing in a dynamic set of functions,
you'd _never know the names_, so my guess is you'd be iterating across
it. If you _do_ know the names, why aren't you accessing them directly
from the surrounding scope? Why aren't you including them in the
function signature?
Presenting bad examples as the Pythonic approach is a bit of a straw
man.
> My way
> ------
> with func(some_args) << ':dict':
> with when_odd as 'n':
> pass
> with when_prime as 'n':
> pass
> with before_check as '':
> pass
> with after_check as '':
> pass
I'm not sure what value your code blocks really provide.
1. You're effectively making "with when_odd as 'n'" mean "def
when_odd(n)"
2. The 'with code_block_name as arguments' syntax is unintuitive, to
say the least.
Personally, I don't see what value it provides over something more
explicit and standard:
I couldn't think of a name for the context manager...but I can't
really think of a use for it either, so that seems fair.
Actually, here's an even simpler example. In this case, the context
manager doesn't have to interrogate the surrounding stack, but the
function call itself is then explicit.
class FOO(object):
def __init__(self, fn):
self.fn = fn
> When would you _ever_ define a function like this? Why are you passing
> in _named_ callbacks? Are you calling them by name? Then declare them
> in the function signature and rely on scoping. Does func() branch on
> existent keys? Then don't write code like that.
> At the very _least_, you could change the function call to:
> func(some_args, locals())
I think that's very bad. It wouldn't be safe either. What about name clashing and how would you pass only some selected functions?
A second call would also need some cleaning up leading to some serious bugs.
> But as you're _passing them in by name_ why not just make it
> func(some_args) and pick them up out of the scope.
Because that's not clean and maintainable. It's not different from using global variables.
> _No one_ writes Python code like this. Presenting bad code as
> "pythonic" is a bit of a straw man.
How can I present good code where there's no good way of doing that without my module or something equivalent?
That was my point.
>> with func(some_args)<< ':dict':
>> with when_odd as 'n':
>> pass
>> with when_prime as 'n':
>> pass
>> with before_check as '':
>> pass
>> with after_check as '':
>> pass
> This is unintuitive, to say the least. You're effectively replacing
> the common form of function definition with "with when_odd as 'n'",
> then using the surrounding context manager to limit the scope.
What's so unintuitive about it? It's just "different".
> More importantly, _you're naming your "anonymous" code blocks_, I'm
> guessing so that func() can choose which ones to use. But if you're
> naming them, why not just use a function?
I'm creating a dictionary, not naming my blocks just for the sake of it.
If you use a function, you end up with the solution that you called 'bad' and non-pythonic.
The problem is always the same. Those functions are defined at the module level so name clashing and many other problems are possible.
I remember a post on this ng when one would create a list of commands and then use that list as a switch table. My module let you do that very easily. The syntax is:
with func() << ':list':
with 'arg':
cmd_code
with 'arg':
cmd_code
with '':
cmd_code
On May 2, 8:52 pm, Kiuhnm <kiuhnm03.4t.yahoo.it> wrote:
>> func(some_args, locals())
> I think that's very bad. It wouldn't be safe either. What about name
> clashing
locals() is a dict. It's not injecting anything into func's scope
other than a dict so there's not going to be any name clashes. If you
don't want any of its content in your function's scope, just don't use
that content.
> and how would you pass only some selected functions?
You wouldn't. You would just refer to the required functions in the
dict _in the same way you would in both your "bad python" and code
block versions.
> > But as you're _passing them in by name_ why not just make it
> > func(some_args) and pick them up out of the scope.
> Because that's not clean and maintainable. It's not different from using
> global variables.
...I'm beginning to suspect we're not engaging in the same
conversation.
This is very common in Python:
from module1 import func1
def func2(args): pass
def main():
# do something with func1 and func2
And I've never had problems maintaining code like this. I know
_exactly_ the scope that the functions exist within because I added
them to it. They're not _global_ because they're restricted to that
specific scope.
> > _No one_ writes Python code like this. Presenting bad code as
> > "pythonic" is a bit of a straw man.
> How can I present good code where there's no good way of doing that
> without my module or something equivalent?
> That was my point.
You haven't presented *any* good code or use cases.
> > This is unintuitive, to say the least. You're effectively replacing
> > the common form of function definition with "with when_odd as 'n'",
> > then using the surrounding context manager to limit the scope.
> What's so unintuitive about it? It's just "different".
Because under no circumstance does "with function_name as
string_signature" _read_ in an understandable way. It's tortuous
grammar that makes no sense as a context manager. You're asking people
to be constantly aware that there are two completely separate meanings
to 'with x as y'.
> > More importantly, _you're naming your "anonymous" code blocks_, I'm
> > guessing so that func() can choose which ones to use. But if you're
> > naming them, why not just use a function?
> I'm creating a dictionary, not naming my blocks just for the sake of it.
> If you use a function, you end up with the solution that you called
> 'bad' and non-pythonic.
What I considered 'bad' was having a _single_ function that takes
_multiple differing collections_ of named functions. Now you've moved
the onus onto the caller to ensure that the function is provided what
it needs in a specific context to do its thing. Rather than overload
one single function and push the complexity out to the caller, why not
have multiple functions with obvious names about what they do that
only take the data they need to act on?
Then again, it's _really difficult_ to tell if something named
'func()' could have a real use like this.
> The problem is always the same. Those functions are defined at the
> module level so name clashing and many other problems are possible.
So define & use a different scope! Thankfully module level isn't the
only one to play with.
> I remember a post on this ng when one would create a list of commands
> and then use that list as a switch table. My module let you do that very
> easily. The syntax is:
> with func() << ':list':
> with 'arg':
> cmd_code
> with 'arg':
> cmd_code
> with '':
> cmd_code
I'm sorry but it is still clear-as-mud what you're trying to show
here. Can you show _one_ practical, real-world, non-toy example that
solves a real problem in a way that Python cannot?