Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #41826 > unrolled thread
| Started by | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| First post | 2013-03-25 12:29 -0700 |
| Last post | 2013-04-04 00:05 -0700 |
| Articles | 20 on this page of 44 — 8 participants |
Back to article view | Back to comp.lang.python
Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-25 12:29 -0700
Re: Help me pick an API design (OO vs functional) Kwpolska <kwpolska@gmail.com> - 2013-03-25 20:42 +0100
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-25 13:48 -0700
Re: Help me pick an API design (OO vs functional) Chris Angelico <rosuav@gmail.com> - 2013-03-26 08:08 +1100
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 01:53 -0700
Re: Help me pick an API design (OO vs functional) Chris Angelico <rosuav@gmail.com> - 2013-03-26 22:38 +1100
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 05:13 -0700
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 05:13 -0700
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-25 13:48 -0700
Re: Help me pick an API design (OO vs functional) Ethan Furman <ethan@stoneleaf.us> - 2013-03-25 16:11 -0700
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 02:06 -0700
Re: Help me pick an API design (OO vs functional) Dave Angel <davea@davea.name> - 2013-03-26 06:26 -0400
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 05:04 -0700
Re: Help me pick an API design (OO vs functional) Dave Angel <davea@davea.name> - 2013-03-26 08:42 -0400
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 07:33 -0700
Re: Help me pick an API design (OO vs functional) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-03-26 22:37 +0000
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-27 02:34 -0700
Re: Help me pick an API design (OO vs functional) Ethan Furman <ethan@stoneleaf.us> - 2013-03-27 09:45 -0700
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-28 03:54 -0700
Re: Help me pick an API design (OO vs functional) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-03-28 00:42 +0000
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-28 04:41 -0700
Re: Help me pick an API design (OO vs functional) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-03-26 12:59 +0000
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 07:26 -0700
Re: Help me pick an API design (OO vs functional) Mitya Sirenef <msirenef@lightbird.net> - 2013-03-25 19:40 -0400
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 02:38 -0700
Re: Help me pick an API design (OO vs functional) Chris Angelico <rosuav@gmail.com> - 2013-03-26 22:43 +1100
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 05:18 -0700
Re: Help me pick an API design (OO vs functional) Mitya Sirenef <msirenef@lightbird.net> - 2013-03-26 09:41 -0400
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 07:59 -0700
Re: Help me pick an API design (OO vs functional) Chris Angelico <rosuav@gmail.com> - 2013-03-27 02:16 +1100
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-27 01:45 -0700
Re: Help me pick an API design (OO vs functional) Mitya Sirenef <msirenef@lightbird.net> - 2013-03-26 18:01 -0400
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-27 02:10 -0700
Re: Help me pick an API design (OO vs functional) Mitya Sirenef <msirenef@lightbird.net> - 2013-03-27 09:56 -0400
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-28 03:52 -0700
Re: Help me pick an API design (OO vs functional) Neil Cerutti <neilc@norwich.edu> - 2013-03-26 14:13 +0000
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-26 07:40 -0700
Re: Help me pick an API design (OO vs functional) Dave Angel <davea@davea.name> - 2013-03-26 12:41 -0400
Re: Help me pick an API design (OO vs functional) Neil Cerutti <neilc@norwich.edu> - 2013-03-26 17:25 +0000
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-27 01:55 -0700
Re: Help me pick an API design (OO vs functional) Chris Angelico <rosuav@gmail.com> - 2013-03-27 22:44 +1100
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-27 05:23 -0700
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-03-27 05:23 -0700
Re: Help me pick an API design (OO vs functional) Michael Herrmann <michael.herrmann@getautoma.com> - 2013-04-04 00:05 -0700
Page 1 of 3 [1] 2 3 Next page →
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-25 12:29 -0700 |
| Subject | Help me pick an API design (OO vs functional) |
| Message-ID | <68da956e-ebe0-4f58-92cd-f7ffff0075b4@googlegroups.com> |
Hello everyone,
my name is Michael, I'm the lead developer of a Python GUI automation library for Windows called Automa: http://www.getautoma.com. We want to add some features to our library but are unsure how to best expose them via our API. It would be extremely helpful for us if you could let us know which API design feels "right" to you.
Our API already offers very simple commands for automating the GUI of a Windows computer. For example:
from automa.api import *
start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
click("Close")
When you execute this script, Automa starts Notepad and simulates key strokes, mouse movements and clicks to perform the required commands. At the moment, each action is performed in the currently active window.
We do not (yet) have a functionality that allows you to explicitly switch to a specific window. Such a functionality would for instance make it possible to open two Notepad windows using the start(...) command, and copy text between them.
One API design would be to have our start(...) function return a "Window" (say) object, whose methods allow you to do the same operations as the global functions write(...), press(...), click(...) etc., but in the respective window. In this design, the example of operating two Notepad windows could be written as
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.write("Hello World!")
notepad_1.press(CTRL + 'a', CTRL + 'c')
notepad_2.press(CTRL + 'v')
The problem with this design is that it effectively duplicates our API: We want to keep our "global" functions because they are so easy to read. If we add methods to a new "Window" class that do more or less the same, we feel that we are violating Python's principle that "There should be one - and preferably only one - obvious way to do it."
An alternative design would be to make the window switching an explicit action. One way of doing this would be to add a new global function, say "switch_to" or "activate", that takes a single parameter that identifies the window to be switched to. We could still have start(...) return a Window object, that could then be passed to our function:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')
Maybe our Window objects could also be used as context managers:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
with notepad_1:
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
with notepad_2:
press(CTRL + 'v')
As a final idea, switching could also be done as a method of the Window class:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')
It would be extremely helpful for us if you could let me know which way of using the API you would prefer. If you opt for an explicit version, how would you call the respective method? "activate" / "switch_to" / "focus" or something else?
Thank you so much!
Best wishes,
Michael
[toc] | [next] | [standalone]
| From | Kwpolska <kwpolska@gmail.com> |
|---|---|
| Date | 2013-03-25 20:42 +0100 |
| Message-ID | <mailman.3699.1364240574.2939.python-list@python.org> |
| In reply to | #41826 |
On Mon, Mar 25, 2013 at 8:29 PM, Michael Herrmann
<michael.herrmann@getautoma.com> wrote:
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> notepad_1.write("Hello World!")
> notepad_1.press(CTRL + 'a', CTRL + 'c')
> notepad_2.press(CTRL + 'v')
Explicit is better than implicit. Changing windows should be explicit
and not implified by your library.
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> switch_to(notepad_1)
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> switch_to(notepad_2)
> press(CTRL + 'v')
Much better.
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> with notepad_1:
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> with notepad_2:
> press(CTRL + 'v')
That’s ugly, and don’t forget that your users aren’t Pythonistas most
of the time.
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> notepad_1.activate()
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> notepad_2.activate()
> press(CTRL + 'v')
That is nice and makes sense, because a global function feels wrong,
at least for me.
> It would be extremely helpful for us if you could let me know which way of using the API you would prefer. If you opt for an explicit version, how would you call the respective method? "activate" / "switch_to" / "focus" or something else?
Window().focus() is the best IMO.
PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.
--
Kwpolska <http://kwpolska.tk> | GPG KEY: 5EAAEA16
stop html mail | always bottom-post
http://asciiribbon.org | http://caliburn.nl/topposting.html
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-25 13:48 -0700 |
| Message-ID | <4b2d2295-cffd-4965-8d75-ebd4f0b9da32@googlegroups.com> |
| In reply to | #41828 |
Hi Kwpolska,
thanks for your reply (as last time I posted here!).
On Monday, March 25, 2013 8:42:25 PM UTC+1, Kwpolska wrote:
> ...
>
> > notepad_1 = start("Notepad")
> > notepad_2 = start("Notepad")
> > with notepad_1:
> > write("Hello World!")
> > press(CTRL + 'a', CTRL + 'c')
> > with notepad_2:
> > press(CTRL + 'v')
>
> That’s ugly, and don’t forget that your users aren’t Pythonistas most
> of the time.
I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our target group though. Also, the "with" is not as explicit as it probably should be.
> ...
> PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.
We'd of course love to support other platforms but don't currently have the resources to do this. We actually just wrote a blog entry about this and some related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there!
It's very hard work building such an automation tool and also we have to live off something. Unfortunately, we can't make the price any lower.
P.S.: First-time bottom-posting!
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-03-26 08:08 +1100 |
| Message-ID | <mailman.3702.1364245741.2939.python-list@python.org> |
| In reply to | #41831 |
On Tue, Mar 26, 2013 at 7:48 AM, Michael Herrmann
<michael.herrmann@getautoma.com> wrote:
> On Monday, March 25, 2013 8:42:25 PM UTC+1, Kwpolska wrote:
>> ...
>>
>> > notepad_1 = start("Notepad")
>> > notepad_2 = start("Notepad")
>> > with notepad_1:
>> > write("Hello World!")
>> > press(CTRL + 'a', CTRL + 'c')
>> > with notepad_2:
>> > press(CTRL + 'v')
>>
>> That’s ugly, and don’t forget that your users aren’t Pythonistas most
>> of the time.
>
> I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our target group though. Also, the "with" is not as explicit as it probably should be.
What happens at the __exit__ of the context manager? What happens if
context managers are nested? I'd be inclined to the simpler option of
an explicit switch (since focus doesn't really "stack" and it'd feel
weird for focus to *sometimes* switch away when you're done working
with one window), though the context manager syntax does have its
advantages too.
>> PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.
>
> We'd of course love to support other platforms but don't currently have the resources to do this. We actually just wrote a blog entry about this and some related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there!
Make the API clean enough and someone else might well write a Linux
equivalent. Then it'll be as simple as a try/import/except/import at
the top and multiple platforms will work.
> P.S.: First-time bottom-posting!
Congrats! Feels good, doesn't it :)
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-26 01:53 -0700 |
| Message-ID | <cce95d1c-ddce-429b-a763-b99e45fb5940@googlegroups.com> |
| In reply to | #41833 |
On Monday, March 25, 2013 10:08:53 PM UTC+1, Chris Angelico wrote: > ... > > I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our target group though. Also, the "with" is not as explicit as it probably should be. > > What happens at the __exit__ of the context manager? What happens if > context managers are nested? I'd be inclined to the simpler option of > an explicit switch (since focus doesn't really "stack" and it'd feel > weird for focus to *sometimes* switch away when you're done working > with one window), though the context manager syntax does have its > advantages too. You are right, an __exit__ for a window doesn't really make sense and neither does stacking. There's also the problem that the focus window may change - for instance when closing it. What happens if you're still inside the "with ..." then? At first glance, I think the context manager solution looks nice syntactically, but maybe it isn't the way to go here. > ... > > > We'd of course love to support other platforms but don't currently have the resources to do this. We actually just wrote a blog entry about this and some related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there! > > > Make the API clean enough and someone else might well write a Linux > equivalent. Then it'll be as simple as a try/import/except/import at > the top and multiple platforms will work. Yes, that's a good point. A clean API is very important to us (hence my posting here). Thanks for your answer! Michael
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-03-26 22:38 +1100 |
| Message-ID | <mailman.3735.1364297923.2939.python-list@python.org> |
| In reply to | #41865 |
On Tue, Mar 26, 2013 at 7:53 PM, Michael Herrmann <michael.herrmann@getautoma.com> wrote: > On Monday, March 25, 2013 10:08:53 PM UTC+1, Chris Angelico wrote: >> ... >> > I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our target group though. Also, the "with" is not as explicit as it probably should be. >> >> What happens at the __exit__ of the context manager? What happens if >> context managers are nested? I'd be inclined to the simpler option of >> an explicit switch (since focus doesn't really "stack" and it'd feel >> weird for focus to *sometimes* switch away when you're done working >> with one window), though the context manager syntax does have its >> advantages too. > > You are right, an __exit__ for a window doesn't really make sense and neither does stacking. There's also the problem that the focus window may change - for instance when closing it. What happens if you're still inside the "with ..." then? At first glance, I think the context manager solution looks nice syntactically, but maybe it isn't the way to go here. Fundamental point: As I understand the API, it doesn't *actually* tie to a window. You don't locate the Notepad window and send it keys - you switch focus to Notepad and then send keys to the whole system. Is this correct? I'm basing my understanding on this paragraph from your original post: > We do not (yet) have a functionality that allows you to explicitly switch to a > specific window. Such a functionality would for instance make it possible to > open two Notepad windows using the start(...) command, and copy text > between them. If so, then all of the method-based options are effectively lying, because they imply a binding that's not there. The actual sequence of actions includes imperatives of "switch to some other window", so I think that's what the API should reflect. Otherwise, there's risk that something will get horribly horribly confused between the programmer's brain and the end result (which could happen on either side of your code). But if you can unambiguously identify a running instance of something and switch to it, then a method on the object that start() returns would be absolutely correct. So I'd be looking at either your second or fourth options from the original post. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-26 05:13 -0700 |
| Message-ID | <851c6626-6700-4759-b4ec-7334dbf35c54@googlegroups.com> |
| In reply to | #41881 |
On Tuesday, March 26, 2013 12:38:35 PM UTC+1, Chris Angelico wrote:
> ...
> Fundamental point: As I understand the API, it doesn't *actually* tie
> to a window. You don't locate the Notepad window and send it keys -
> you switch focus to Notepad and then send keys to the whole system. Is
> this correct? I'm basing my understanding on this paragraph from your
> original post:
>
> > We do not (yet) have a functionality that allows you to explicitly switch to a
> > specific window. Such a functionality would for instance make it possible to
> > open two Notepad windows using the start(...) command, and copy text
> > between them.
>
> If so, then all of the method-based options are effectively lying,
> because they imply a binding that's not there. The actual sequence of
> actions includes imperatives of "switch to some other window", so I
> think that's what the API should reflect. Otherwise, there's risk that
> something will get horribly horribly confused between the programmer's
> brain and the end result (which could happen on either side of your
> code).
As I just wrote in my reply to Dave, internally we know very well which window an action is to be performed in. This window is the window that'd be in the foreground after the previous action, if nothing interferes with the system while the script is being executed. A common exception is when you enter commands in the interactive interpreter: say you write
>>> start("Notepad")
The Notepad window opens, but for you to enter the next command, you have to switch back to the interpreter window. If you do that, and enter
>>> write("Hello World")
then we remember that you were previously working with the Notepad window and activate this window before performing the key strokes to type "Hello World".
> But if you can unambiguously identify a running instance of something
> and switch to it, then a method on the object that start() returns
> would be absolutely correct. So I'd be looking at either your second
> or fourth options from the original post.
Those are also my favorites at the moment :)
Michael
www.getautoma.com
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-26 05:13 -0700 |
| Message-ID | <mailman.3740.1364300577.2939.python-list@python.org> |
| In reply to | #41881 |
On Tuesday, March 26, 2013 12:38:35 PM UTC+1, Chris Angelico wrote:
> ...
> Fundamental point: As I understand the API, it doesn't *actually* tie
> to a window. You don't locate the Notepad window and send it keys -
> you switch focus to Notepad and then send keys to the whole system. Is
> this correct? I'm basing my understanding on this paragraph from your
> original post:
>
> > We do not (yet) have a functionality that allows you to explicitly switch to a
> > specific window. Such a functionality would for instance make it possible to
> > open two Notepad windows using the start(...) command, and copy text
> > between them.
>
> If so, then all of the method-based options are effectively lying,
> because they imply a binding that's not there. The actual sequence of
> actions includes imperatives of "switch to some other window", so I
> think that's what the API should reflect. Otherwise, there's risk that
> something will get horribly horribly confused between the programmer's
> brain and the end result (which could happen on either side of your
> code).
As I just wrote in my reply to Dave, internally we know very well which window an action is to be performed in. This window is the window that'd be in the foreground after the previous action, if nothing interferes with the system while the script is being executed. A common exception is when you enter commands in the interactive interpreter: say you write
>>> start("Notepad")
The Notepad window opens, but for you to enter the next command, you have to switch back to the interpreter window. If you do that, and enter
>>> write("Hello World")
then we remember that you were previously working with the Notepad window and activate this window before performing the key strokes to type "Hello World".
> But if you can unambiguously identify a running instance of something
> and switch to it, then a method on the object that start() returns
> would be absolutely correct. So I'd be looking at either your second
> or fourth options from the original post.
Those are also my favorites at the moment :)
Michael
www.getautoma.com
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-25 13:48 -0700 |
| Message-ID | <mailman.3701.1364244506.2939.python-list@python.org> |
| In reply to | #41828 |
Hi Kwpolska,
thanks for your reply (as last time I posted here!).
On Monday, March 25, 2013 8:42:25 PM UTC+1, Kwpolska wrote:
> ...
>
> > notepad_1 = start("Notepad")
> > notepad_2 = start("Notepad")
> > with notepad_1:
> > write("Hello World!")
> > press(CTRL + 'a', CTRL + 'c')
> > with notepad_2:
> > press(CTRL + 'v')
>
> That’s ugly, and don’t forget that your users aren’t Pythonistas most
> of the time.
I kind of like the context manager solution because the indentation makes it very obvious what happens in which window. You are right about our target group though. Also, the "with" is not as explicit as it probably should be.
> ...
> PS. do you plan a version for non-Windows OSes? Also, €99 is too expensive.
We'd of course love to support other platforms but don't currently have the resources to do this. We actually just wrote a blog entry about this and some related questions: http://www.getautoma.com/blog/automa-faq If we have something wrong, do let us know in the comments over there!
It's very hard work building such an automation tool and also we have to live off something. Unfortunately, we can't make the price any lower.
P.S.: First-time bottom-posting!
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2013-03-25 16:11 -0700 |
| Message-ID | <mailman.3704.1364253688.2939.python-list@python.org> |
| In reply to | #41826 |
On 03/25/2013 12:29 PM, Michael Herrmann wrote:
> Hello everyone,
>
> my name is Michael, I'm the lead developer of a Python GUI automation library for Windows called Automa: http://www.getautoma.com. We want to add some features to our library but are unsure how to best expose them via our API. It would be extremely helpful for us if you could let us know which API design feels "right" to you.
>
> Our API already offers very simple commands for automating the GUI of a Windows computer. For example:
>
> from automa.api import *
> start("Notepad")
> write("Hello World!")
> press(CTRL + 's')
> write("test.txt", into="File name")
> click("Save")
> click("Close")
>
> When you execute this script, Automa starts Notepad and simulates key strokes, mouse movements and clicks to perform the required commands. At the moment, each action is performed in the currently active window.
>
> We do not (yet) have a functionality that allows you to explicitly switch to a specific window. Such a functionality would for instance make it possible to open two Notepad windows using the start(...) command, and copy text between them.
>
> One API design would be to have our start(...) function return a "Window" (say) object, whose methods allow you to do the same operations as the global functions write(...), press(...), click(...) etc., but in the respective window. In this design, the example of operating two Notepad windows could be written as
>
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> notepad_1.write("Hello World!")
> notepad_1.press(CTRL + 'a', CTRL + 'c')
> notepad_2.press(CTRL + 'v')
This is the way to go. Just move your global functions into the Window object (or whatever you call it), break
backwards compatibility (major version number change, perhaps?), and call it good.
It makes much more sense to call methods of several different objects (which is explicit -- you always know which object
is being used) than having a magic function that changes the object in the background (plus you now have to search
backwards for the last magic invocation to know -- and what if a called function changes it?).
--
~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-26 02:06 -0700 |
| Message-ID | <80d9f8b5-64ad-4691-9489-c0d22c2c2b2d@googlegroups.com> |
| In reply to | #41835 |
On Tuesday, March 26, 2013 12:11:34 AM UTC+1, Ethan Furman wrote:
> On 03/25/2013 12:29 PM, Michael Herrmann wrote:
> ...
> >
> > notepad_1 = start("Notepad")
> > notepad_2 = start("Notepad")
> > notepad_1.write("Hello World!")
> > notepad_1.press(CTRL + 'a', CTRL + 'c')
> > notepad_2.press(CTRL + 'v')
>
> This is the way to go. Just move your global functions into the Window object (or whatever you call it), break
> backwards compatibility (major version number change, perhaps?), and call it good.
>
> It makes much more sense to call methods of several different objects (which is explicit -- you always know which object
> is being used) than having a magic function that changes the object in the background (plus you now have to search
> backwards for the last magic invocation to know -- and what if a called function changes it?).
Your points are valid and I cannot really say anything against them. The problem with moving all global functions into the Window object is that this adds a lot of syntactic baggage that isn't needed in 90% of the cases. We really prefer the simplicity of
start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
press(ALT + F4)
over
notepad = start("Notepad")
notepad.write("Hello World!")
notepad.press(CTRL + 's')
notepad.write("test.txt", into="File name")
notepad.click("Save")
notepad.press(ALT + F4).
Also, there's a problem here: The "Save" dialogue that opens in the above script is technically a different window so in theory you would have to introduce a new object to distinguish between the original window that lets you edit your text document from the "Save" window. This is very tedious and error-prone. You are right, though, that we have to do some logic in the background to remember the last window.
In light of this, could you live with something along the lines of design #4?
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.focus()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.focus()
press(CTRL + 'v')
Thanks,
Michael
[toc] | [prev] | [next] | [standalone]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2013-03-26 06:26 -0400 |
| Message-ID | <mailman.3729.1364293611.2939.python-list@python.org> |
| In reply to | #41867 |
On 03/26/2013 05:06 AM, Michael Herrmann wrote:
> On Tuesday, March 26, 2013 12:11:34 AM UTC+1, Ethan Furman wrote:
>> On 03/25/2013 12:29 PM, Michael Herrmann wrote:
>> ...
>>>
>>> notepad_1 = start("Notepad")
>>> notepad_2 = start("Notepad")
>>> notepad_1.write("Hello World!")
>>> notepad_1.press(CTRL + 'a', CTRL + 'c')
>>> notepad_2.press(CTRL + 'v')
>>
>> This is the way to go. Just move your global functions into the Window object (or whatever you call it), break
>> backwards compatibility (major version number change, perhaps?), and call it good.
>>
>> It makes much more sense to call methods of several different objects (which is explicit -- you always know which object
>> is being used) than having a magic function that changes the object in the background (plus you now have to search
>> backwards for the last magic invocation to know -- and what if a called function changes it?).
>
> Your points are valid and I cannot really say anything against them. The problem with moving all global functions into the Window object is that this adds a lot of syntactic baggage that isn't needed in 90% of the cases. We really prefer the simplicity of
>
> start("Notepad")
> write("Hello World!")
> press(CTRL + 's')
> write("test.txt", into="File name")
> click("Save")
> press(ALT + F4)
>
> over
>
> notepad = start("Notepad")
> notepad.write("Hello World!")
> notepad.press(CTRL + 's')
> notepad.write("test.txt", into="File name")
> notepad.click("Save")
> notepad.press(ALT + F4).
>
> Also, there's a problem here: The "Save" dialogue that opens in the above script is technically a different window so in theory you would have to introduce a new object to distinguish between the original window that lets you edit your text document from the "Save" window. This is very tedious and error-prone. You are right, though, that we have to do some logic in the background to remember the last window.
>
> In light of this, could you live with something along the lines of design #4?
>
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> notepad_1.focus()
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> notepad_2.focus()
> press(CTRL + 'v')
>
> Thanks,
> Michael
>
Seems to me that the official interface should all be methods. However,
you could have a new object which always represents the "focus" window.
Then the USER could define trivial functions:
def write(*args):
focused.write(*args)
Somewhere in this thread you mention that save() creates a new window,
so a method-oriented approach would require that the user get that
window object, and call its methods rather than the original window's.
I say that's a very good thing, since the things you send may very well
have very different meanings to the save dialog than they do in the
original one.
Another concern I'd have is what happens if the user changes focus with
his mouse? Does that change the meaning you had for focus() in the
above exchange? Do you want your press() method to apply to a different
window when the user changes to that window?
--
DaveA
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-26 05:04 -0700 |
| Message-ID | <ecc055cc-0126-4356-9458-278a630b102c@googlegroups.com> |
| In reply to | #41873 |
On Tuesday, March 26, 2013 11:26:30 AM UTC+1, Dave Angel wrote:
> ...
> Seems to me that the official interface should all be methods. However,
> you could have a new object which always represents the "focus" window.
> Then the USER could define trivial functions:
>
> def write(*args):
> focused.write(*args)
It's an interesting idea. But why not give this write(...) to them in the first place? Am I the only one who appreciates the simplicity of
start("Notepad")
write("Hello World!")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
press(ALT + F4)
over
notepad = start("Notepad")
notepad.write("Hello World!")
notepad.press(CTRL + 's')
notepad.write("test.txt", into="File name")
notepad.click("Save")
notepad.press(ALT + F4)?
> Somewhere in this thread you mention that save() creates a new window,
> so a method-oriented approach would require that the user get that
> window object, and call its methods rather than the original window's.
> I say that's a very good thing, since the things you send may very well
> have very different meanings to the save dialog than they do in the
> original one.
save() is not a function, but I assume you mean the action that opens the "Save" dialogue (I think that'd be `press(CTRL + 's')`). You are right that it's nice for it to be explicit. However, in 95% of cases, the window you want the next action to be performed in is the window that is currently active. I appreciate the explicitness, but to force it on the user for only 5% of cases seems a bit much.
> Another concern I'd have is what happens if the user changes focus with
> his mouse? Does that change the meaning you had for focus() in the
> above exchange? Do you want your press() method to apply to a different
> window when the user changes to that window?
No. Internally, we remember which window is the currently active window. If you just run a script without user-intervention, this will be the respective foreground window. If some other window is in the foreground - which most typically happens when the user is interactively entering commands one after the other, so the foreground window is the console window, we do switch to the window that's supposed to be the active one. It may sound like black magic, but it works very well in practice, and really is not too ambiguous. When you read a script like
start("Notepad")
write("Hello World")
press(CTRL + 's')
write("test.txt", into="File name")
click("Save")
click("Close")
I hold that you intuitively know what's going on, without even thinking about window switching.
Best,
Michael
www.getautoma.com
[toc] | [prev] | [next] | [standalone]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2013-03-26 08:42 -0400 |
| Message-ID | <mailman.3741.1364301768.2939.python-list@python.org> |
| In reply to | #41886 |
On 03/26/2013 08:04 AM, Michael Herrmann wrote:
> On Tuesday, March 26, 2013 11:26:30 AM UTC+1, Dave Angel wrote:
>> ...
>> Seems to me that the official interface should all be methods. However,
>> you could have a new object which always represents the "focus" window.
>> Then the USER could define trivial functions:
>>
>> def write(*args):
>> focused.write(*args)
>
> It's an interesting idea. But why not give this write(...) to them in the first place?
Just to be clear, I was avoiding the problem of having two ways of
accessing each function, since most of us prefer the methods, and you
have some users who prefer simple functions.
> Am I the only one who appreciates the simplicity of
>
> start("Notepad")
> write("Hello World!")
> press(CTRL + 's')
> write("test.txt", into="File name")
> click("Save")
> press(ALT + F4)
>
> over
>
> notepad = start("Notepad")
> notepad.write("Hello World!")
> notepad.press(CTRL + 's')
> notepad.write("test.txt", into="File name")
> notepad.click("Save")
> notepad.press(ALT + F4)?
>
>> Somewhere in this thread you mention that save() creates a new window,
>> so a method-oriented approach would require that the user get that
>> window object, and call its methods rather than the original window's.
>> I say that's a very good thing, since the things you send may very well
>> have very different meanings to the save dialog than they do in the
>> original one.
>
> save() is not a function, but I assume you mean the action that opens the "Save" dialogue (I think that'd be `press(CTRL + 's')`). You are right that it's nice for it to be explicit. However, in 95% of cases, the window you want the next action to be performed in is the window that is currently active. I appreciate the explicitness, but to force it on the user for only 5% of cases seems a bit much.
>
>> Another concern I'd have is what happens if the user changes focus with
>> his mouse? Does that change the meaning you had for focus() in the
>> above exchange? Do you want your press() method to apply to a different
>> window when the user changes to that window?
>
> No. Internally, we remember which window is the currently active window. If you just run a script without user-intervention, this will be the respective foreground window. If some other window is in the foreground - which most typically happens when the user is interactively entering commands one after the other, so the foreground window is the console window, we do switch to the window that's supposed to be the active one. It may sound like black magic, but it works very well in practice, and really is not too ambiguous. When you read a script like
>
> start("Notepad")
> write("Hello World")
> press(CTRL + 's')
> write("test.txt", into="File name")
> click("Save")
> click("Close")
>
> I hold that you intuitively know what's going on, without even thinking about window switching.
>
Until the program you're scripting makes some minor change in its
interface, or has something conditional on an attribute not intuitively
obvious.
Also, it seems that in this thread, we are using "window" both to refer
to a particular application instance (like Notepad1 and Notepad2), and
to refer to windows within a single application.
Anyway, if you're only automating a few specific apps, you're not likely
to run into the problems that methods were intended to address. After
all, Notepad's bugs haven't seemed to change for a couple of decades, so
why should they fix anything now?
Having a selected window be an implied object for those global functions
yields at least the same problems as any writable global.
Multithreading, unexpected side effects from certain functions,
callbacks, etc.
As long as you know the program is going to be simple, pile on the
globals. But as soon as it advances, each of them is a trap to fall into.
--
DaveA
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-26 07:33 -0700 |
| Message-ID | <bfee7444-091f-4413-a0fc-cfbd22f60e56@googlegroups.com> |
| In reply to | #41894 |
On Tuesday, March 26, 2013 1:42:26 PM UTC+1, Dave Angel wrote: > ... > > Also, it seems that in this thread, we are using "window" both to refer > to a particular application instance (like Notepad1 and Notepad2), and > to refer to windows within a single application. > > > > Anyway, if you're only automating a few specific apps, you're not likely > to run into the problems that methods were intended to address. After > all, Notepad's bugs haven't seemed to change for a couple of decades, so > why should they fix anything now? > > Having a selected window be an implied object for those global functions > yields at least the same problems as any writable global. > Multithreading, unexpected side effects from certain functions, > callbacks, etc. > > As long as you know the program is going to be simple, pile on the > globals. But as soon as it advances, each of them is a trap to fall into. You're right with everything you say. globals are bad and it may happen that this will bite me. I'm just not sure whether we should sacrifice the simpler syntax useful in say 80% of cases for something I'm not yet sure will ever become a real problem.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-03-26 22:37 +0000 |
| Message-ID | <51522323$0$29998$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #41906 |
On Tue, 26 Mar 2013 07:33:18 -0700, Michael Herrmann wrote: >> As long as you know the program is going to be simple, pile on the >> globals. But as soon as it advances, each of them is a trap to fall >> into. > > You're right with everything you say. globals are bad and it may happen > that this will bite me. Global *variables* are bad, not global functions. You have one global variable, "the current window". So long as your API makes it obvious when the current window changes, implicitly operating on the current window is no more dangerous than Python's implicit operations on the current namespace (e.g. "x = 2" binds 2 to x in the current namespace). I recommend you look at the random.py API. You have a Random class, that allows the user to generate as many independent random number generators as needed. And the module also initialises a private instance, and exposes the methods of that instance as top-level functions, to cover the 90% simple case where your application only cares about a single RNG. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-27 02:34 -0700 |
| Message-ID | <3e8c3737-1086-4962-bba7-ba346d593b7b@googlegroups.com> |
| In reply to | #41959 |
On Tuesday, March 26, 2013 11:37:23 PM UTC+1, Steven D'Aprano wrote:
>
> Global *variables* are bad, not global functions. You have one global
> variable, "the current window". So long as your API makes it obvious when
> the current window changes, implicitly operating on the current window is
> no more dangerous than Python's implicit operations on the current
> namespace (e.g. "x = 2" binds 2 to x in the current namespace).
I'm generally wary of everything global, but you're right as long as no (global) state is involved.
> I recommend you look at the random.py API. You have a Random class, that
> allows the user to generate as many independent random number generators
> as needed. And the module also initialises a private instance, and
> exposes the methods of that instance as top-level functions, to cover the
> 90% simple case where your application only cares about a single RNG.
I looked it up - I think this is a very good approach; to provide easy access to the functionality used in 90% of cases but still give users the flexibility to cover the edge cases.
After everybody's input, I think Design #2 or Design #4 would be the best fit for us:
Design #2:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
switch_to(notepad_1)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(notepad_2)
press(CTRL + 'v')
Design #4:
notepad_1 = start("Notepad")
notepad_2 = start("Notepad")
notepad_1.activate()
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
notepad_2.activate()
press(CTRL + 'v')
Normally, I'd go for Design #4, as it results in one less global, is better for autocompletion etc. The thing with our library is that it tries to make its scripts as similar as possible to giving instructions to someone looking over their shoulder at a screen. And in this situation you would just say
activate(notepad)
rather than
notepad.activate().
So the problem lies in a difference between Python's and English grammar. For beauty, I should go with #2. For pragmatism, I should go with #4. It hurts, but I'm leaning towards #4. I have to think about it a little.
Thank you so much to everybody for your inputs so far!
Best,
Michael
www.getautoma.com
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2013-03-27 09:45 -0700 |
| Message-ID | <mailman.3814.1364403159.2939.python-list@python.org> |
| In reply to | #41997 |
On 03/27/2013 02:34 AM, Michael Herrmann wrote:
> After everybody's input, I think Design #2 or Design #4 would be the best fit for us:
>
> Design #2:
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> switch_to(notepad_1)
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> switch_to(notepad_2)
> press(CTRL + 'v')
>
> Design #4:
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> notepad_1.activate()
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> notepad_2.activate()
> press(CTRL + 'v')
>
> Normally, I'd go for Design #4, as it results in one less global, is better for autocompletion etc. The thing with our library is that it tries to make its scripts as similar as possible to giving instructions to someone looking over their shoulder at a screen. And in this situation you would just say
>
> activate(notepad)
>
> rather than
>
> notepad.activate().
>
> So the problem lies in a difference between Python's and English grammar. For beauty, I should go with #2. For pragmatism, I should go with #4. It hurts, but I'm leaning towards #4. I have to think about it a little.
Go with #2. Not everything has to be a method. len(), for example, is not a method, even though it calls one.
The 'with' support would also be cool. __enter__ sets the new global window object whilst saving the old one, and then
__exit__ restores the old one.
--
~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Michael Herrmann <michael.herrmann@getautoma.com> |
|---|---|
| Date | 2013-03-28 03:54 -0700 |
| Message-ID | <dab4b804-14f0-4037-9c66-dba9bc0612c9@googlegroups.com> |
| In reply to | #42018 |
On Wednesday, March 27, 2013 5:45:49 PM UTC+1, Ethan Furman wrote:
> On 03/27/2013 02:34 AM, Michael Herrmann wrote:
> > Design #2:
> > notepad_1 = start("Notepad")
> > notepad_2 = start("Notepad")
> > switch_to(notepad_1)
> > write("Hello World!")
> > press(CTRL + 'a', CTRL + 'c')
> > switch_to(notepad_2)
> > press(CTRL + 'v')
> ...
>
> Go with #2. Not everything has to be a method. len(), for example, is not a method, even though it calls one.
That's a good point. I actually think #2 is the one we'll use.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-03-28 00:42 +0000 |
| Message-ID | <515391fa$0$29998$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #41997 |
On Wed, 27 Mar 2013 02:34:09 -0700, Michael Herrmann wrote:
> On Tuesday, March 26, 2013 11:37:23 PM UTC+1, Steven D'Aprano wrote:
>>
>> Global *variables* are bad, not global functions. You have one global
>> variable, "the current window". So long as your API makes it obvious
>> when the current window changes, implicitly operating on the current
>> window is no more dangerous than Python's implicit operations on the
>> current namespace (e.g. "x = 2" binds 2 to x in the current namespace).
>
> I'm generally wary of everything global, but you're right as long as no
> (global) state is involved.
That comment surprises me. Your preferred API:
switch_to(notepad)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
uses implied global state (the current window). Even if you avoid the use
of an actual global for (say) an instance attribute, it's still
semantically a global. Surely you realise that?
Not trying to be argumentative, I'm just surprised at your comment.
>> I recommend you look at the random.py API. You have a Random class,
>> that allows the user to generate as many independent random number
>> generators as needed. And the module also initialises a private
>> instance, and exposes the methods of that instance as top-level
>> functions, to cover the 90% simple case where your application only
>> cares about a single RNG.
>
> I looked it up - I think this is a very good approach; to provide easy
> access to the functionality used in 90% of cases but still give users
> the flexibility to cover the edge cases.
>
> After everybody's input, I think Design #2 or Design #4 would be the
> best fit for us:
>
> Design #2:
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> switch_to(notepad_1)
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> switch_to(notepad_2)
> press(CTRL + 'v')
This is nice syntax for trivial cases and beginners whose needs are not
demanding, but annoying for experts who have more complicated
requirements. If this is the only API, experts who need to simultaneously
operate in two windows will be forced to write unproductive boilerplate
code that does nothing but jump from window to window.
Well what do you know, even in the simple case above, you have
unproductive code that does nothing but jump from window to window :-)
I'm not against this API, I'm just against it as the *only* API.
> Design #4:
> notepad_1 = start("Notepad")
> notepad_2 = start("Notepad")
> notepad_1.activate()
> write("Hello World!")
> press(CTRL + 'a', CTRL + 'c')
> notepad_2.activate()
> press(CTRL + 'v')
This is actually no different from #2 above, except that it uses method
call syntax while #2 uses function call syntax. So it has the same
limitations as above: it's simple for simple uses, but annoying for
complex use.
Neither API supports advanced users with complicated needs. A hybrid
approach, where you have function call syntax that operates on the
implicit current window, plus method call syntax that operates on any
window, strikes me as the best of both worlds. With a little forethought
in your implementation, you don't have to duplicate code. E.g. something
like this:
class WindowOps:
def __init__(self, theWindow=None):
self.theWindow = None
def press(self, c):
win = self.getWindow()
send_keypress_to(win)
def getWindow(self):
if self.theWindow is None:
return gTheTopWindow
return self.theWindow
_implicit = WindowOps(None)
press = _implicit.press
# etc.
del _implicit
This gives you the best of both worlds, for free: a simple API using an
implicit top window for simple cases, and a slightly more complex API
with an explicit window for advanced users.
> Normally, I'd go for Design #4, as it results in one less global,
I don't see how this is possible. Both APIs use an implicit "top window".
What's the one less global you are referring to?
> is
> better for autocompletion etc. The thing with our library is that it
> tries to make its scripts as similar as possible to giving instructions
> to someone looking over their shoulder at a screen. And in this
> situation you would just say
>
> activate(notepad)
>
> rather than
>
> notepad.activate().
Depends like Yoda they talk whether or not.
Unless you go all the way to writing your own parser that accepts English-
like syntax, like Hypertalk:
select notepad
type hello world
I don't think it makes that much difference. Function call syntax is not
exactly English-like either. We don't generally speak like this:
write bracket quote hello world quote close bracket
My personal feeling is that people aren't going to be *too* confused by
method call syntax, especially not if they've seen or been introduced to
any programming at all. You say tom-a-to, I say tom-ar-to.
But I think it is useful to distinguish between the "basic API" using
function call syntax and an implied current window, and an "advanced API"
using method call syntax with an explicit window:
# Basic API is pure function calls, using an implicit window
switch_to(notepad)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
switch_to(calculator)
write('2+3=')
press(CTRL + 'a')
switch_to(notepad)
press(CTRL + 'v')
# Advanced API uses an explicit window and method calls:
notepad.write("Hello World!")
notepad.press(CTRL + 'a', CTRL + 'c')
calculator.write('2+3=')
calculator.press(CTRL + 'a')
notepad.press(CTRL + 'v')
# Of course you can mix usage:
switch_to(notepad)
write("Hello World!")
press(CTRL + 'a', CTRL + 'c')
calculator.write('2+3=')
calculator.press(CTRL + 'a')
press(CTRL + 'v')
You could avoid method call syntax altogether by giving your functions an
optional argument that points to the window to operate on:
write("Hello World!")
write("Hello World!", notepad)
but the difference is mere syntax.
There's little or no additional complexity of implementation to allow the
user to optionally specify an explicit window. I expect you have
something like this:
def write(string):
window = gTheCurrentWindow # use a global
send characters of string to window # magic goes here
This can trivially be changed to:
def write(string, window=None):
if window is None:
window = gTheCurrentWindow
send characters of string to window # magic goes here
See, for example, the decimal module. Most operations take an optional
"context" argument that specifies the number of decimal places, rounding
mode, etc. If not supplied, the global "current context" is used.
This gives the simplicity and convenience of a global, without the
disadvantages.
(Recent versions of decimal have also added "with context" syntax, for
even more power.)
--
Steven
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | comp.lang.python
csiph-web