This is a guide to learn how to program with python on org-babel.
To start on the right foot, advanced coders can take a look at
python.el (Python’s flying circus support for Emacs), which provides
python-mode, and relies on comint. Beginners can also read the
official tutorial and the guide. https://docs.python.org/3/usinghttps://docs.python.org/3/tutorial
This guide features some of the interactions org-babel provides over
code source blocks. It was initially written with Emacs 26.3 and
Org-mode 9.3.6 running on Debian 9 (stretch).
Note that the file isn’t intended to be read on github (or briefly) as their render of org-mode is incomplete (the following results for instance). You can read it in online in different formats on 7d.nz.
Present configuration is :
Typing C-c C-c (which means keeping Control pressed while typing c
twice) on the lines above will call and execute the code blocks
declared below. It also works when the cursor is on the code blocks.
(org-version)(emacs-version)uname -aEmacs will ask: evaluate this (elisp or python) code block on your system ?
Depending on your symbol definition, you’ll have to type “yes” or “no”, “y” or “n” the two latter comes by changing the following predicate
(fset 'yes-or-no-p 'y-or-n-p) ; y/n instead of yes/no
We will be running Python source blocks,
that is, blocks starting with #+begin_src python.
For this we need to instruct org-babel about what
languages can be evaluated in the buffer,
and in what mode and/or languages.
You can run the code block below, or set the variable : (customize-variable ‘org-babel-load-languages)
(org-babel-do-load-languages'org-babel-load-languages
'((python .t)))
(defundo-org-confirm-babel-evaluations (langbody)
(not
(or
(string= lang "python")
(string= lang "calc"))))
(setq org-confirm-babel-evaluate 'do-org-confirm-babel-evaluations)The other function in the block above
will instruct babel to skip the confirmation
when running python or calc in org-babel source blocks.
More radical : (setq org-confirm-babel-evaluate nil) see (customize-variable ‘org-confirm-babel-evaluate)
Python is distributed with every Linux system.
Many bash and perl programs, parts of the operating system,
have been rewritten with it.
(setq python-shell-interpreter "python3")
Now you can check your python system interpreter
importsysreturnsys.versionIf the answer is 2.7, you’ll have to make one more customization tweak. The official Python distribution is now Python 3. The 2.7 interpreter is still around for historical reasons, but will be dropped from now on.
(customize-variable 'org-babel-python-command)
to python3, and now we are set.
While for proper shell to start interactively outside of org-babel, the variable will be
(customize-variable 'python-shell-interpreter)
type M-x : run-python
(where M stands for Meta, which is Alt)
and the shell (the CPython shell) starts.
If somehow, somewhere the interpreter already started —
typically when a session code block gets evaluated, then the
shell is already open in a buffer named *Python*.
Notice it tells you python.el completion is loaded. You
should have basic syntax coloring and completion by pressing
tab. M-n and M-p loops through the history of commands.
Another python interpreter you should be aware of
is ipython which provides some extra features :
a zsh prompt on the very same command line and
automodule reloading, but we’ll save that for later.
Python is often said to be an interpreted programming
language, but a language is not “interpreted” or “compiled”
as such. A specific implementation can be an interpreter or
a compiler. Over-simplification, but still: when a program
is run, every line of code feeds, in sequence, the
interpreter/compiler which translates the program into
byte-code. The last step generates files, landing in the
__pycache__ folder which in turn contains .pyc files extensions
named after your program. You can completely ignore that folder,
the interpreter will manage it.
Instructions comes in two forms : definitions, that don’t return anything and statements, that do return something.
x=1
defines a variable x holding the value 1
As you can see in the interpreter
this definition does not return any value,
while the statement
x
does return the value of the variable
>>> x=1 >>> x 1 >>>
In the same way a function definition when declared doesn’t return anything : do not confuse with the return statement of the function, but with the return value of an expression given to the interpreter.
>>> def f(): return 256
Asking for the value of f
will return a string representation
of that function as its type, name and memory address.
>>> f <function f at 0x7fbdaace2e18>
And of course actually calling that function
is expressed with f().
Python variables are dynamically typed. Any variable can hold any type from any variable, and — along with its value — the type it holds can change during the execution of the program. We talk about binding variables.
Asking for an undefined variable raise an error :
NameError: name 'y' is not defined
We can initialize y with “text”
and ask for it’s length :
>>> y="text" >>> len(y)
then give the same variable another value of a different type and ask again for it’s length. For instance :
>>> y=2 >>> len(2)
This time we would get a type error, with the explanation :
TypeError: object of type 'int' has no len()
The type of a variable is implicit and stricly related to the value it holds.
The type of a variable can be returned by the type function.
>>> x=2.1 >>> type(x) <class 'float'>
which is the same as asking the type of the corresponding value (since a variable returns its value).
>>> type(2.1) <class 'float'>
And what is the type of that? Well it’s a type again,
denoted through a class which is a reserved keyword,
and which indicates the nature of the type construct:
this is object oriented design.
>>> type(type(x)) <class 'type'>
Any variable, function, declared in the interpreter can be
queried, modifed, or manipulated, even built-in functions, so
good care is advised to not inadvertently change the
semantics of the program in its course (say, with an
embarassing type=x for instance).
Due to the local scoping however, if a parameter takes
the name of an existing function
(a commonplace beeing file), then it exists only
for the scope it was defined.
defproceeed():
defopen(file):
print("opening %s"%file)Yes, it’s possible to define functions inside of functions
(so you can call functions while calling functions…).
Here open and file already exists as built-ins,
but the definition of file designates the parameter
only inside the open function, while this definition
of open only exists in proceed. Out of that scope,
both open and file keep refering to their original definitions.
The function help() will spit out the help text
of a function or a module.
help(type)Wich is defined à la lisp, with a string as first statement in a function definition.
Here I’m skipping forward a bit assuming you know about function definitions, scopes and indentations. Otherwise, here it is, in the official tutorial. https://docs.python.org/3.6/tutorial/controlflow.html#defining-functions
defgreetings(name):
""" Here we can describe what the function does """print ("Hello %s"%name)
greetings('Vincent')
help(greetings)Every code block is an independent program
x=0x+=1unless we enter session mode.
Session mode in org-python is slightly different from non-session mode, because in session mode you are talking to a single “interactive” python session. In python’s interactive mode, blank lines are special: they indicate the end of an indented block. So you have to write your org-mode python code a little different when using session mode. Besides, the return type is implicit, it is the last expression, as in an interactive shell.
[2020-12-19 sam. 17:35] I don’t know if this holds anymore since org 9.3
xx+=1xThe above program can be run repeatdly (with C-c)
and the result will keep increasing.
returnn*2<<callthat>>returnnEvery block is considered as a function with its own scope and variable namespace
<<callthat>>returnnx=12returnxreturnint(y)+1nfrommathimportsqrtprint(n)
n+=i
(n+sqrt(5))/2When babel doesn’t provide
the expected output, the error might be silenced,
— which isn’t much in the spirit of python —
or displayed in the *Org-Babel Error Output* buffer.
In the first block, changing the variable to n=”3”
will raise an error in the second block,
which in turn won’t provide any result.
The error appears in the *Python* buffer,
but it’s not the best place to investigate.
Changing the :results from value to output
will make the situation explicit.
For debugging at least : if the intent is
to use that result to feed another function,
then output won’t provide the computed golden
ratio, but the print statement output, which
is the integer 3 in this example.
Babel provides an extra layer to organize the code, so in the end it’s only a matter of opening the proper channels to direct the results in the proper buffers.
importsyssys.stdout.write("1..")
sys.stdout.write("2")
sys.stdout.flush()importrandomdogs="Max Charlie Cooper Buddy Jack Rocky Oliver Bear Duke".split()
head= ["Name", "str", "agi", "int"]
fmt1="{0:8s}| {1:3s} | {2:3s} | {3:3s}"fmt2="{0:8s}| {1:3d} | {2:3d} | {3:3d}"return [[ fmt1.format(*head)],
*([ fmt2.format(*([name]+random.sample( range(0,20), 3)))]
fornameindogs )]print(' {4:2s} {0:5s} {1:7s}{2:4s} {3:10s}'.format('x','x^2','~ko','x^3','n'))
forninrange(0, 11):
x=2<<nprint('{4:2d} {0:5d} {1:7d} {2:4d}{3:12d}'.format(x,x**2,int(x**2/1024),x**3,n))
print('-'*33)
# right justify as string (through repr or str)forxinrange(1, 12):
print(repr(x).rjust(2), repr(x*x).rjust(3), end=' | ')
# Note use of 'end' on previous line, instead of '\n' by defaultprint(repr(x**3).rjust(4))
and adding a prologue header
A basic table output can be return by value
importrandomdogs="Max Charlie Cooper Buddy Jack Rocky Oliver Bear Duke".split()
head= ["Name", "str", "agi", "int"]
fmt1="{0:8s}| {1:3s} | {2:3s} | {3:3s}"fmt2="{0:8s}| {1:3d} | {2:3d} | {3:3d}"return [[ fmt1.format(*head)],
*([ fmt2.format(*([name]+random.sample( range(0,20), 3)))]
fornameindogs )]the :prologue attributes can be used to insert something before the
result; It requires however the result to be an output, an so it
needs a slight modification.
an other alternative is the :post attribute
echo"#+ATTR_LATEX: :center nil :align |p{5cm}|l|l|l|"echo"$data"Here the origin of the *this* should be investigated
importrandomdogs="Max Charlie Cooper Buddy Jack Rocky Oliver Bear Duke".split()
head="Name", "str", "agi", "int"fmt1="|{0:8s}| {1:3s} | {2:3s} | {3:3s}"fmt2="|{0:8s}| {1:3d} | {2:3d} | {3:3d}"print( fmt1.format(*head))
fornameindogs :
print ( fmt2.format(*([name]+random.sample( range(0,20), 3))))defg(n, f=lambdai:0):
return [f(i) foriinrange(1,n+1)]
g(10, f=lambdax:2**x), g(10, f=lambdax:3**x)f=open(file,'w+')
f.write(mark)
f.close ()Be careful with the file keyword though, as it’s already a bound function.
f1=open(file,'r+')
n=f1.read()
i=int(n)
i+=1f1.seek(0)
f1.write(str(i))
f1.close()
# woops error silencedf2=open(testfile,'w')
f2.write('')
f2.close()
f2=open(testfile, 'rb+')
f2.write(b'0123456789abcdef') #noticed the bYTE ?a=f2.seek(5) # Go to the 6th byte in the fileb=f2.read(1)
#5f2.seek(-3, 2) # Go to the 3rd byte before the endc=f2.read(1)
#df2.close()
# pour conclure correctement le test, vérifier simplement# les types de retour (je les ai gardé lisible pour mémo, on va s'en resservir)# et les octets attendusprint('\n'.join([str(i),str(a),str(b),str(c),str(f1),str(f2)]))deffib(n): # Write Fibonacci series up to n.""" Print a Fibonacci series up to n."""a, b=0, 1whilea<n:
print(a, end=' ')
a, b=b, a+bprint()
fib(100)frompprintimportpprintpprint(globals())Every object is backed up by a __dict__ object which acts as
a namespace for that object.
classaClass :
def__init__(self,v):
self.v=vdef__enter__(self):
print(__class__, "__enter__", self)
returnself.vdef__exit__(self, type, value, traceback):
print(__class__, '__exit__', value, traceback)
def__del__(self):
print(__class__, '__del__', self)
print('>')
withaClass(42) asvalue:
print ("\ninside of block 'with'", value)Note that self isn’t a keyword.
The following is still respectable python
classMyClass :
def__init__(λ,v):
λ.v=vdef__enter__(λ):
print(__class__,"__enter__")
returnλ.vdef__exit__(λ,type, value, traceback):
print(__class__,'__exit__',value,traceback)
def__del__(λ):
print(__class__,'__del__')
print('\r')
withMyClass(42) asvalue:
print ("in block 'with' and",value)The output of the execution order isn’t however guaranteed
The output of “ok” and True will follow that order,
but the call to __del__ may appear before “ok” :
the function gets a copy, yet the object is deleted.
classaClass :
def__init__(self,v):
self.v=vdef__enter__(self):
print(__class__,"__enter__")
returnself.vdef__exit__(self,type,value,traceback):
print(__class__,'__exit__',value,traceback)
def__del__(self):
print('__del__')
defp(self):
print("ok",self)
returnTruef=aClass(1).pprint(f())session output in
non-session output :
Java-like Polymorphism with decorators
fromfunctoolsimportsingledispatch@singledispatchdefF(arg):
return"default"@F.register(int)@F.register(float)def_(arg):
return"for a number"classC: pass@F.register(C)def_(arg):
return"for a an objet C"print( ( F("x"), F([]), F(1), F(C()) ) )
print(F.registry.keys())classStruct:
def__init__(_,rawdat) :
_.__dict__=rawdatfork,vinrawdat.items() :
ifisinstance(v,dict):
_.__dict__[k] =Struct(v)
ifisinstance(v,list):
ifall(type(x) isdictforxinv):
_.__dict__[k] = [Struct(i) foriinv]
else:
_.__dict__[k] =vinfo:org#Environment of a Code Block
| a |
|---|
| b |
| c |
return [[val+'*'forvalinrow] forrowintab]| a |
|---|
| b* |
| c* |
https://docs.python.org/3.4/glossary.html#term-global-interpreter-lock
frompickleimportdumps, loadclassA:
def__init__(self,v):
self.v=vF=testfile="/tmp/serialize.dump"a=A(15)
f=open(F,'wb')
f.write(dumps(a))
f.close()
f=open(F,'rb')
o=load(f)
f.close()
print (o.v)see magicmethods.org
classLog :
def__init__(_,_file):
_.a=open(_file, 'a')
_.ready=Truedefread():
_.r=open('r', file)
passdefwrite(event):
queue.put(event)
defstream(_):
# thread_safe. Non blocking# chronoms=0whilenotqueue.empty() and_.ready:
T=queue.get()
#atomicité de l'opération writenb+=_.a.write(T) # et en cas d'interruption ?# nb/msdefclose(_):
_.ready=false;
close(_.a)
close(_.r)
fromthreadingimportThreadL=Log("/tmp/a.log")
defwriteGibberish():
globalLprint('.',end="-")
foriinrange(16):
L.write(i)
L.stream()
foriinrange(128):
t=Thread(target=writeGibberish)
t.start()
print(i)
print('?')# http://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-pythonimportsysfromsubprocessimportPIPE, PopenfromthreadingimportThreadtry:
fromQueueimportQueue, EmptyexceptImportError:
fromqueueimportQueue, Empty# python 3.xON_POSIX='posix'insys.builtin_module_namesdefenqueue_output(out, queue):
forlineiniter(out.readline, b''):
queue.put(line)
out.close()
p=Popen(['./veryverbose'], stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
q=Queue()
t=Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon=True# thread dies with the programt.start()
# ... do other things here# read line without blockingtry: line=q.get_nowait() # or q.get(timeout=.1)exceptEmpty:
print('no output yet')
else: # got line# ... do something with lineprint('line')Note: Examples are based on datetime.datetime(2013, 9, 30, 7, 6, 5)
| Code | Meaning | Example |
| %a | Weekday as locale’s abbreviated name. | Mon |
| %A | Weekday as locale’s full name. | Monday |
| %w | Weekday as a decimal number, where 0 is Sunday and 6 is Saturday. | 1 |
| %d | Day of the month as a zero-padded decimal number. | 30 |
| %-d | Day of the month as a decimal number. (Platform specific) | 30 |
| %b | Month as locale’s abbreviated name. | Sep |
| %B | Month as locale’s full name. | September |
| %m | Month as a zero-padded decimal number. | 09 |
| %-m | Month as a decimal number. (Platform specific) | 9 |
| %y | Year without century as a zero-padded decimal number. | 13 |
| %Y | Year with century as a decimal number. | 2013 |
| %H | Hour (24-hour clock) as a zero-padded decimal number. | 07 |
| %-H | Hour (24-hour clock) as a decimal number. (Platform specific) | 7 |
| %I | Hour (12-hour clock) as a zero-padded decimal number. | 07 |
| %-I | Hour (12-hour clock) as a decimal number. (Platform specific) | 7 |
| %p | Locale’s equivalent of either AM or PM. | AM |
| %M | Minute as a zero-padded decimal number. | 06 |
| %-M | Minute as a decimal number. (Platform specific) | 6 |
| %S | Second as a zero-padded decimal number. | 05 |
| %-S | Second as a decimal number. (Platform specific) | 5 |
| %f | Microsecond as a decimal number, zero-padded on the left. | 000000 |
| %z | UTC offset in the form +HHMM or -HHMM | |
| (empty string if the the object is naive). | ||
| %Z | Time zone name (empty string if the object is naive). | |
| %j | Day of the year as a zero-padded decimal number. | 273 |
| %-j | Day of the year as a decimal number. (Platform specific) | 273 |
| %U | Week number of the year (Sunday as the first day of the week) | |
| as a zero padded decimal number. All days in a new year preceding | ||
| the first Sunday are considered to be in week 0. | 39 | |
| %W | Week number of the year (Monday as the first day of the week) | |
| as a decimal number. All days in a new year preceding the first | ||
| Monday are considered to be in week 0. | 39 | |
| %c | Locale’s appropriate date and time representation. | Mon Sep 30 07:06:05 2013 |
| %x | Locale’s appropriate date representation. | 09/30/13 |
| %X | Locale’s appropriate time representation. | 07:06:05 |
| %% | A literal ‘%’ character. | % |
fromdatetimeimportdatetimereturndatetime.now().strftime("%Y-%m-%d+%H:%M:%S")fromtimeimporttimet=time()
print(t)importtimedefcountdown(t):
whilet:
mins, secs=divmod(t, 60)
timeformat='{:02d}:{:02d}'.format(mins, secs)
print(timeformat, end='\r')
time.sleep(1)
t-=1print('Goodbye!\n\n\n\n\n')Timing code execution
fromtimeitimporttimeitdefrev(n,L):
forxinreversed(L):
n+=xreturn(n)
defrev1(n,L):
forxinL[::-1]:
n+=xreturn(n)
defrev2(n,L):
foriinrange(len(L)-1, 0, -1):
n+=L[i]
return(n)
defloop(f,x):
n=0x=f(n,L)
a=b=c=0L= [xforxinrange(300000)]
deftit(x):
returntimeit(x,number=100)
print(tit(lambda:loop(rev,a)))
print(tit(lambda:loop(rev1,b)))
print(tit(lambda:loop(rev2,c)))on iPython :
%alias_magicttimeitL= [xforxinrange(3000000)]
defrev(n,L):
forxinreversed(L):
n+=xreturn(n)
defrev1(n,L):
forxinL[::-1]:
n+=xreturn(n)
defrev2(n,L):
foriinrange(len(L)-1, 0, -1):
n+=L[i]
return(n)
defloop(f,x):
n=0x=f(n,L)
a=b=c=0%tloop(rev,a)
%tloop(rev1,b)
%tloop(rev2,c)Every objects has a __sizeof__() function.
10 biggest objects
importtracemalloctracemalloc.start()
#run the application...snapshot=tracemalloc.take_snapshot()
top_stats=snapshot.statistics('lineno')
[[str(t)] fortintop_stats[:10]]Memory leak search :
importtracemalloctracemalloc.start()
#run the application...snapshot2=tracemalloc.take_snapshot()
top_stats=snapshot.compare_to(snapshot,'lineno')
print("[ Top 10 différences ] ")
[[str(stat)] forstatintop_stats[:10]]'''enable autoreload of a library whenever a change occurs'''%load_extautoreload%autoreload2%aimportpyorgmode# set the locale for correct date handling (%a)importlocalelocale.setlocale(locale.LC_TIME, "")
# ^ you'll need it to properly handle# date format such as <2017-03-24 Fri> or <2017-03-24 ven.>frompyorgmodeimport*org=OrgDataStructure()
org.load_from_file("tests/orgs/test.org")
topnodes=org.toplevel_nodes()
headings= [T.headingforTintopnodes]
print(headings)
foritintopnodes :
print (it.level, it.todo, it.priority, it.heading, it.tags)In further versions of Python are introduced new language features. For instance as of 3.6 was introduced the matrix multiplication operator (@).
At the end of 2020, Python latest version is 3.9.1 Every release brings a significant amount or improvements.
https://www.python.org/doc/versions/
The following compilation options enable
- the creation and loading C shared library
- history in the shell
- PGO
- link time optimization
./configure --enable-shared --enable-loadable-sqlite-extensions --enable-optimizations --with-lto
https://www.python.org/https://www.python.org/downloads/release/python-391/https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgzhttps://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz.asc
;;; (add-hook 'python-mode-common-hook 'flycheck-mode);(require 'flymake-python-pyflakes);(add-hook 'python-mode-hook 'flymake-python-pyflakes-load); (global-flycheck-mode 1) ;; << will globally bind C-c !
(with-eval-after-load'flycheck
(add-hook'flycheck-mode-hook#'flycheck-pycheckers-setup))
(add-hook'before-save-hook'delete-trailing-whitespace)defkey(event):
print ("pressed", repr(event.keysym))
defEsc(event):
quit()
defmouseCallback(evt):
Log.put({'type':evt.type,'widget':evt.widget,'x':evt.x,'y':evt.y, 'btn':evt.num})
# x and y root left asidedefcallback(evt):
print (evt.type)
defignore(event):
# avoid this for toplevel as is will mute the eventreturn"break"defwindows_callback(evt):
# a <configure> event## evt 22 = configure (windows_event). peu utile comme évènement, niveau trace/debugLog.put(evt.type,{'width':evt.width,'height':evt.height,'x_root':evt.x_root,'y_root':evt.y_root})
# no ? filter event logging base on their type : better, pipe it to the tkinter filter# rem : not very pythonic# let's see later about dnd'defdefaultbindings(frame):
frame.bind("<Key>",key)
# The user pressed any key. The key is provided in the char member of the event object passed to the callback (this is an empty string for special keys).# a# The user typed an “a”. Most printable characters can be used as# is. The exceptions are space (<space>) and less than# (<less>). Note that 1 is a keyboard binding, while <1> is a# button binding.frame.bind("<Escape>",Esc)
frame.bind("<Button-1>", callback)
frame.bind("<Button-2>", callback)
# think about the Menu buttonframe.bind("<Button-2>", callback)
frame.bind("<Double-Button-1>", callback)
# Note that if you bind to both a single click (<Button-1>)# and a double click, both bindings will be called.frame.bind("<Enter>", callback)
# The mouse pointer entered the widget (this event doesn’t mean that# the user pressed the Enter key!).frame.bind("<Leave>", callback)
# The mouse pointer left the widget.frame.bind("<FocusIn>", callback)
# Keyboard focus was moved to this widget, or to a child of this widget.frame.bind("<FocusOut>", callback)
# Keyboard focus was moved from this widget to another widget.frame.bind("<Return>", callback)
# The user pressed the Enter key. You can bind to virtually all keys on the keyboard. For an ordinary 102-key PC-style keyboard, the special keys are Cancel (the Break key), BackSpace, Tab, Return(the Enter key), Shift_L (any Shift key), Control_L (any Control key), Alt_L (any Alt key), Pause, Caps_Lock, Escape, Prior (Page Up), Next (Page Down), End, Home, Left, Up, Right, Down, Print, Insert, Delete, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, Num_Lock, and Scroll_Lock.frame.bind("<Shift-Up>", callback)
# The user pressed the Up arrow, while holding the Shift key# pressed. You can use prefixes like Alt, Shift, and Control.frame.bind("<Configure>", windows_callback)
# The widget changed size (or location, on some platforms). The# new size is provided in the width and height attributes of the# event object passed to the callback."defaults bindings set"#from Tkinter import *fromtkinterimport*fromtkinterimportmessageboximportsysdefquit():
print("exiting now")
ifmessageBox.askokcancel("Quit", "Do you really wish to quit?"):
# make sure widget instances are deletedroot.destroy()
# event is automatically sent to the log#top.protocol("WM_DELETE_WINDOW", top.destroy)defXColorString(color) :
return'#%02x%02x%02x'%colorif__name__=='__main__':
root=Tk()
root.geometry("%dx%d+%d+%d"% (360,200,900,600))
root.protocol("WM_DELETE_WINDOW", quit)
root.bind('<Escape>', Esc)
#Log=LogBuffer('./test.log')#frame = Frame(root)grey=(180, 180, 0)
m=PanedWindow(master=root,orient=VERTICAL, background=XColorString(grey))
m.background=XColorString(grey)
m.pack(fill=BOTH, expand=1)
top=Label(m, text="top pane")
m.add(top)
bottom=Label(m, text="bottom pane")
m.add(bottom)
defaultbindings(root)
#defaultbindings(frame)#frame.pack()#top.protocol("WM_TAKE_FOCUS", top.takefocus)root.mainloop()
Truehow to gracefully extend that program so the selected color is tried and tested before it is applied? It sounds simple at first, but this where we would discover the importance of the design choices in the former module: is the color picker blocking ? Does it return a value only upon validation? Should the host program be modified to get the event ?
When you press down a mouse button over a widget, Tkinter will automatically “grab” the mouse pointer, and subsequent mouse events (e.g. Motion and Release events) will then be sent to the current widget as long as the mouse button is held down, even if the mouse is moved outside the current widget.
# Binary Tree Levelorder Traversal (visitor pattern)deftraverse_levelorder (tree_node):
queue.put(tree_node)
whilenotqueue.empty():
T=queue.get()
iftisnotNone:
visit(t)
queue.put(t.left)
queue.put(t.right)
queue.put(t)
queue.put(t)# moduile nameDEFAULT_MODULE='sdl2ogl'thismodule=DEFAULT_MODULE# loading itIGL=__import__(thismodule)
t=Thread(target=IGL.start)
t.start()
# r goes# and we can give it new values# read by the simulation"""OpenGL rendering"""importsysimportctypesfromOpenGLimportGL, GLUimportsdl2clearcolor=(0,0,0)
defjustdoit(): # call <module>.justdoit() from pyshellglobalclearcolorclearcolor=(0,1,0)
defrun():
ifsdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) !=0:
print(sdl2.SDL_GetError())
return-1window=sdl2.SDL_CreateWindow(b"OpenGL demo",
sdl2.SDL_WINDOWPOS_UNDEFINED,
sdl2.SDL_WINDOWPOS_UNDEFINED, 800, 600,
sdl2.SDL_WINDOW_OPENGL)
ifnotwindow:
print(sdl2.SDL_GetError())
return-1context=sdl2.SDL_GL_CreateContext(window)
GL.glMatrixMode(GL.GL_PROJECTION|GL.GL_MODELVIEW)
GL.glLoadIdentity()
GL.glOrtho(-400, 400, 300, -300, 0, 1)
x=0.0y=30.0event=sdl2.SDL_Event()
running=Truewhilerunning:
whilesdl2.SDL_PollEvent(ctypes.byref(event)) !=0:
ifevent.type==sdl2.SDL_KEYDOWN :
ifevent.key.keysym.sym==sdl2.SDLK_F2:
print ('>now what ?\n')
running=Falseifevent.key.keysym.sym==sdl2.SDLK_ESCAPE:
running=Falseifevent.type==sdl2.SDL_QUIT:
running=FalseGL.glClearColor(clearcolor[0], clearcolor[1], clearcolor[2], 1)
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
GL.glRotatef(10.0, 0.0, 0.0, 1.0)
GL.glBegin(GL.GL_TRIANGLES)
GL.glColor3f(1.0, 0.0, 0.0)
GL.glVertex2f(x, y+90.0)
GL.glColor3f(0.0, 1.0, 0.0)
GL.glVertex2f(x+90.0, y-90.0)
GL.glColor3f(0.0, 0.0, 1.0)
GL.glVertex2f(x-90.0, y-90.0)
GL.glEnd()
sdl2.SDL_GL_SwapWindow(window)
sdl2.SDL_Delay(10)
sdl2.SDL_GL_DeleteContext(context)
sdl2.SDL_DestroyWindow(window)
sdl2.SDL_Quit()
return0# don't# if __name__ == "__main__":# sys.exit(run())defstart():
print ('starting\n')
sys.exit(run())
# here it's already out unless a root tk is still flying aroundSome details of what you must do may depend on what you want to do with IDLE’s Shell once you have it running. I would like to know more about that. But let us start simple and make the minimum changes to pyshell.main needed to make it run with other code.
Note that in 3.6, which I use below, PyShell.py is renamed pyshell.py. Also note that everything here amounts to using IDLE’s private internals and is ‘use at your own risk’.
I presume you want to run Shell in the same process (and thread) as your tkinter code. Change the signature to
def main(tkroot=None):
Change root creation (find # setup root) to You should be able to call pyshell.main whenever you want.
tkroot=Noneifnottkroot:
root=Tk(className="Idle")
root.withdraw()
else:
root=tkroot# In current 3.6, there are a couple more lines to be indented under if not tkroot:ifuse_subprocessandnottesting:
NoDefaultRoot()
# Guard mainloop and destroy (at the end) withifnottkroot:
whileflist.inversedict: # keep IDLE running while files are open.root.mainloop()
root.destroy()
# else leave mainloop and destroy to caller of main"""The above adds 'dependency injection' of a root window to thefunction. I might add it in 3.6 to make testing (an example of 'othercode') easier."""#The follow tkinter program now runs, displaying the both the root window and an IDLE shell.fromtkinterimportTkfromidlelibimportpyshellroot=Tk()
Label(root, text='Root id is '+str(id(root))).pack()
root.update()
deflater():
pyshell.main(tkroot=root)
Label(root, text='Use_subprocess = '+str(pyshell.use_subprocess)).pack()
root.after(0, later)
root.mainloop()dissassembling and timing two code variants
importsysdefget_datasets(observatoryGroup=None, instrumentType=None, observatory=None,
instrument=None,
startDate=None, stopDate=None, idPattern=None, labelPattern=None, notesPattern=None):
return [ f'{x}={y}'for (x,y) in [
("observatory",observatory),
("observatoryGroup",observatoryGroup),
("instrumentType",instrumentType),
("instrument",instrument),
("startDate",startDate),
("stopDate", stopDate ),
("idPattern", idPattern ),
("labelPattern", labelPattern ),
("notesPattern", notesPattern )
] ifyisnotNone]
# get_datasets(observatoryGroup=False)defdistest() :
importdisdis.dis("""args = [ f'{x}={y}' for (x,y) in [ ('observatory',observatory), ('observatoryGroup',observatoryGroup), ('instrumentType',instrumentType), ('instrument',instrument), ('startDate',startDate), ('stopDate', stopDate ), ('idPattern', idPattern ), ('labelPattern', labelPattern ), ('notesPattern', notesPattern ) ] if y is not None]""" )
print("-----------")
dis.dis("""args = [] if observatory is not None: args.append(f'observatory={observatory}') if observatoryGroup is not None: args.append(f'observatoryGroup={observatoryGroup}') if instrumentType is not None: args.append(f'instrumentType={instrumentType}') if instrument is not None: args.append(f'instrument={instrument}') if startDate is not None: args.append(f'startDate={startDate}') if stopDate is not None: args.append(f'stopDate={stopDate}') if idPattern is not None: args.append(f'idPattern={idPattern}') if labelPattern is not None: args.append(f'labelPattern={labelPattern}') if notesPattern is not None: args.append(f'notesPattern={notesPattern}') """
)
defget_datasets0(observatoryGroup=None, instrumentType=None, observatory=None,
instrument=None,
startDate=None, stopDate=None, idPattern=None, labelPattern=None, notesPattern=None):
args= []
ifobservatoryisnotNone:
args.append(f'observatory={observatory}')
ifobservatoryGroupisnotNone:
args.append(f'observatoryGroup={observatoryGroup}')
ifinstrumentTypeisnotNone:
args.append(f'instrumentType={instrumentType}')
ifinstrumentisnotNone:
args.append(f'instrument={instrument}')
ifstartDateisnotNone:
args.append(f'startDate={startDate}')
ifstopDateisnotNone:
args.append(f'stopDate={stopDate}')
ifidPatternisnotNone:
args.append(f'idPattern={idPattern}')
iflabelPatternisnotNone:
args.append(f'labelPattern={labelPattern}')
ifnotesPatternisnotNone:
args.append(f'notesPattern={notesPattern}')
returnargsimporttimeitprint(timeit.timeit(lambda:get_datasets(observatoryGroup=1, instrumentType=2, observatory=3)))
print(timeit.timeit(lambda:get_datasets0(observatoryGroup=1, instrumentType=2, observatory=3)))
print(timeit.timeit(lambda:get_datasets(idPattern=1, labelPattern=2, notesPattern=3)))
print(timeit.timeit(lambda:get_datasets0(idPattern=1, labelPattern=2, notesPattern=3)))yield from can be used to delegate iteration
defcountdown(n):
whilen>0:
yieldnn-=1defcountup(stop):
n=1whilen<stop:
yieldnn+=1defup_and_down(n):
yieldfromcountup(n)
yieldfromcountdown(n)
forxinup_and_down(3) :
print(x)https://yewtu.be/watch?v=zrOIQEN3Wkk
importre,operators="(+(2*3)+((8)/4))+1"defscan(f, state, it):
forxinit: state=f(state, x)
yieldstatereturnmax(list(scan(operator.add, 0, [(1ifx=="("else-1) forxinre.findall("[()]",s)])))