This set of slides gives a short introduction into the world of Python, with a special focus on Python for S60 (PyS60). For smaller projects and prototypes, Python is often the better choice compared to native development in C++, as it's a higher level language that leads to results in a faster and more direct way. Assuming that you already have development experience in Java or C++, these slides jointly introduce basic concepts of Python (variable scope, lists, tuples, classes, ...) as well as their applicance in PyS60.
Contents:
* The Python programming language
* Modules, variables, lists, tuples, dictionaries, loops
* Basic UI elements: notes, query dialogs, lists
* Functions, arguments, variable scope
* Classes, exception handling
* Application structure, event based development
* String manipulation
4. PyS60 – Examples NiiMe Andreas Jakl, 2009 4 Controlling Super Mario by movements (jumping, walking, ...) Playing drums Controlling flight / racinggames with tilting http://www.niime.com/
5. PyS60 – Examples Andreas Jakl, 2009 5 Time-lapse Photographyhttp://blog.foozia.com/blog/2007/jan/21/python-s60-time-lapse-photography-using-nokia-n80/ aspyplayerLast.fm-Player for PyS60http://code.google.com/p/aspyplayer/ PyEDEdit Python source code on the phonehttp://sourceforge.net/projects/pyed/ pyPoziomicaUse your phone as a level toolhttp://www.symbian-freak.com/news/007/12/pypoziomica_freeware_level_tool.htm
7. Python Older than you might think: 1989 – 1991 by Guido van Rossum (National Research Institute for Mathematics and Computer Science, Netherlands) Named after Monty Python’s Flying Circus Today: Microcontrollers Mobile Phones Web servers 7 Andreas Jakl, 2009
8. Scalable Modular architecture Easy code reuse Huge Python standard library Extension with own C/C++ modules Andreas Jakl, 2009 8 Shell scripts Huge projects
10. Fast Rapid Application Prototyping Easy to learn – can you read this code? What would this be like in C++ or Java ME? ... Andreas Jakl, 2009 10 import inbox, audio box = inbox.Inbox() msg_id = box.sms_messages()[0] msg_txt = u"Message: " + box.content(msg_id) audio.say(msg_txt)
11. Symbian OS + Runtimes Andreas Jakl, 2009 11 Java ME Python .net Basic Perl Apache / PHP / MySQL Flash Lite Silverlight (soon) Widgets (Web Runtime) Ruby S60(C++) Symbian OS
12. UI Platforms: S60 Unified UI platform based on S60 Official UI platform of Symbian Foundation Former name: Series 60 Touchscreen support with S60 5th Edition Andreas Jakl, 2009 12 Nokia N97
13. UI Platforms: S60 Andreas Jakl, 2009 www.s60.com Business High-End Multimedia Mass Market Nokia N96 Nokia E66 Samsung Omnia HD Nokia 6121 Classic Nokia 5800XPressMusic Nokia E71 Nokia 5500 Sport Samsung INNOV8 Nokia E90 13 Nokia N85 SE Idou Nokia 6210 Navigator
14. PyS60 Python port to S60 Allows easy access to: Accelerometer Camera Text-to-speech Location Web services Messaging Bluetooth UI Andreas Jakl, 2009 14 Web Flash Python Managed code Java Ease of development P.I.P.S.OpenC Symbian C++ Native code Functionality and performance
15. Setup – Phone Install the latest Nokia PC Suite:http://europe.nokia.com/A4144903 Download and install PyS60: 1.4.x: http://sourceforge.net/projects/pys60/ 1.9.x+: https://garage.maemo.org/projects/pys60/ Phone: Phone software: PythonForS60_1_x_x_3rdEd.SIS Phone script shell: PythonScriptShell_1_x_x_3rdEd.SIS Andreas Jakl, 2009 15 PyS60 1.4.x: based on Python 2.3 PyS60 1.9.2+: based on Python 2.5.1, supports new sensor framework of S60 3rd Ed., FP2+
16.
17. IDEs IDLE – comes with Python SDK C:rogram Filesythonibdlelibdle.bat PythonWin + Win32 Extensions http://sourceforge.net/projects/pywin32/ PyDev Eclipse/Carbide.c++ Plug-in http://pydev.sf.net/ SPE http://pythonide.stani.be/ Andreas Jakl, 2009 17
18. Hello World Create a file hello.py: Connect your phone to the PC (“PC Suite” connection mode) Transfer the script to E:ython(memory card) using the Nokia PC suite file manager Run the script: Andreas Jakl, 2009 18 hello.py print “Hello World”
19. Hello World – Emulator Copy hello.py to:<epocroot>inscwythonello.py Start the emulator from:<epocroot>eleaseinscwdebpoc.exe Andreas Jakl, 2009 19
20. PyDev + Emulator Either create the project / workspace directly in the python-dir of the emulator Or link the project files to source files in the dir: Andreas Jakl, 2009 20
21. PyS60 – User Interface Starting with the UI Andreas Jakl, 2009 21
22. Module Collection of related functions and data grouped together Has to be imported at the beginning:import appuifw Addressing a function of the module:appuifw.query(label, name) Import multiple modules in a single statement:import appuifw, e32 Andreas Jakl, 2009 22 Python Basics
23. Query Syntax: appuifw.query(label, type[, initial value]) Andreas Jakl, 2009 23 importappuifw appuifw.query(u"Type a word:", "text", u"Hello") appuifw.query(u"Type a number:", "number", 7) appuifw.query(u"Type a date:", "date") appuifw.query(u"Type a time:", "time") appuifw.query(u"Type a password:", "code") appuifw.query(u"Do you like PyS60?", "query") number /float text time date code query
24. Note Dialog Syntax: appuifw.note(text[, type[, global] ] ) Andreas Jakl, 2009 24 importappuifw appuifw.note(u"Hello") appuifw.note(u"File not found", "error") appuifw.note(u"Upload finished", "conf") info / default error conf
26. Variables Variables not declared ahead of time Implicit typing Automated memory management Reference counting, garbage collection Variable names can be “recycled” delstatement allows explicit de-allocation Andreas Jakl, 2009 26 Python Basics
27. Variables – Example Andreas Jakl, 2009 27 Python Basics age = 5 name = u"Andreas" # u in front of the string: unicode name += age# Doesn't work, the type isn’t converted automatically name += str(age) # name == Andreas5 name = age # name now points to the same object as age; name == 5 foo = "xyz" bar = foo# bar points to the same object as foo foo = 123 # a new object is created for foo, bar still points to "xyz“ foo “xyz” bar foo “xyz” 123 bar
28. Multi-Query Dialog Syntax: appuifw.multi_query(label1, label2) Andreas Jakl, 2009 28 importappuifw pwd = u"secret" info = appuifw.multi_query(u"Username:", u"Password:") if info: // returns a tuple with the info login_id, login_pwd = info iflogin_pwd == pwd: appuifw.note(u"Login successful", "conf") else: appuifw.note(u"Wrong password", "error") else: // returns None – special type appuifw.note(u"Cancelled")
29. if-statement Works like in other languages Blocks are defined by indentation – avoids dangling else ifexpression1:expr1_true_suiteelifexpression2:expr2_true_suiteelse:none_of_the_above_suite Andreas Jakl, 2009 29 Python Basics
30. Lists, Tuples and Dictionaries Generic “arrays” for arbitrary number of arbitrary objects Ordered and accessed via index offsets List – created using [ ] Andreas Jakl, 2009 30 Python Basics myList = [1, 2, 3, 4] # [1, 2, 3, 4] printmyList[0] # 1 # Subsets: sequence[starting_index:ending_index] printmyList[1:3] # [2, 3] printmyList[2:] # [3, 4] printmyList[:3] # [1, 2, 3] myList[1] = 5 # [1, 5, 3, 4] myList[2] = ["bla", (-2.3+4j)] # [1, 5, ["bla", (-2.3+4j)], 4] printmyList[2][1] # -2.3+4j print 4 inmyList# True
31. Lists, Tuples and Dictionaries Tuple – created using ( ) Immutable – can therefore be used as dictionary keys Also useful when you don’t want a function to be able to change your data Andreas Jakl, 2009 31 Python Basics myTuple1 = ('python', 's60', 27) print myTuple1[0] # python myTuple[1] = 'no'# tuples are immutable – exception! myTuple2 = ('symbian', 'uiq') myTuple3 = myTuple1 + myTuple2 print myTuple3 # ('python', 's60', 27, 'symbian', 'uiq')
32. Lists, Tuples and Dictionaries Dictionary – created using { } Mapping type – like associative arrays or hashes in Perl Key-value pairs Keys: almost any Python type, usually numbers or stings Values: arbitrary Python object Andreas Jakl, 2009 32 Python Basics myDict = {'planet': 'earth'} myDict['port'] = 80 print myDict# {'planet': 'earth', 'port': 80} print myDict.keys() # ['planet', 'port'] print myDict['planet']# earth for key inmyDict: print"key=%s, value=%s" % (key, myDict[key]) # key=planet, value=earth # key=port, value=80
33. Popup Menu Syntax: appuifw.popup_menu(list[, label ]) Andreas Jakl, 2009 33 importappuifw items = [u"The Journey", u"RealReplay", u"ShakerRacer"] index = appuifw.popup_menu(items, u"Buy:") if index == 0: appuifw.note(u"Great choice") elif index == 1: appuifw.note(u"Cool") elif index == 2: appuifw.note(u"I like that") elif index == None: appuifw.note(u"Purchase cancelled")
34. Selection List Syntax: appuifw.selection_list(choices[, search_field=0]) Andreas Jakl, 2009 34 Search field appears after pressing a letter key importappuifw names = [u"Michael", u"Devon", u"Bonnie", u"April", u"RC3"] index = appuifw.selection_list(names, 1) if index == 2: print "I love you!" else: print "You're great!"
35. Multi-Selection List Syntax: appuifw.multi_selection_list(choices[, style=‘checkbox’, search_field=0]) Andreas Jakl, 2009 35 importappuifw names = [u"Michael", u"Devon", u"Bonnie", u"April", u"RC3"] selections = appuifw.multi_selection_list(names, 'checkbox', 1) print selections Style: checkmarkSelect multiple items with the pen keyNot really important
37. for Loop – Examples Andreas Jakl, 2009 37 Python Basics current letter: T current letter: e current letter: x current letter: t # Iterating over a string foreachLetterin"Text": print "current letter:", eachLetter # Iterating by sequence item nameList = ["Mike", "Sarah", "Charles"] foreachNamein sorted(nameList): printeachName # Iterating by sequence index fornameIndexin range(len(nameList)): print nameList[nameIndex] # Iterate over a range foreachValin range(3): print"value: ", eachVal # Extended syntax: # range(start, end, step = 1) foreachValin range(2, 10, 3): print"value: ", eachVal Charles Mike Sarah Mike Sarah Charles value: 0 value: 1 value: 2 value: 2 value: 5 value: 8
38. while loop whileexpression:suite_to_repeat Nice addition: else is executed if loop was not abandoned by break Andreas Jakl, 2009 38 Python Basics defshowMaxFactor(num): count = num / 2 while count > 1: if num % count == 0: print"Largest factor of %d is %d" % (num, count) break count -= 1 else: print num, "is prime" foreachNumin range(10, 21): showMaxFactor(eachNum)
39. Example – System Info SMS Andreas Jakl, 2009 39 importappuifw, messaging, sysinfo # You could use a dictionary as well, but here this is more straightforward later on infoNames = [u"Profile", u"Battery", u"Signal DBM"] infoCalls = ["sysinfo.active_profile()", "sysinfo.battery()", "sysinfo.signal_dbm()"] # Let the user choose the information he wants to send choices = appuifw.multi_selection_list(infoNames, "checkbox", 0) infoSms = "" foridxin choices: # Execute the statement(s) stored in the infoCalls-list through the eval-statement, # convert the result to a string and append it to the sms text infoSms += infoNames[idx] + ": " + str(eval(infoCalls[idx])) + "; " # Query the telephone number smsNum = appuifw.query(u"Number:", "text", u"+15550135") ifsmsNum: # Send the SMS if the user didn’t cancel messaging.sms_send(smsNum, infoSms) appuifw.note(u"Info sent", "conf")
40. Python – Function and Classes Procedural and Object Oriented Development Andreas Jakl, 2009 40
41. Functions – Basics deffunction_name(arguments): [“function_documentation_string”]function_body_suite Supports: Default arguments Variable length arguments Multiple return values Inner functions ... Andreas Jakl, 2009 41 Python Basics deffoo(): "foo() -- does't do anything special." print"in foo" # Execute the function foo() # Print the help text of the function printfoo.__doc__ # foo() -- does't do anything special.
43. Functions – Variable Length Arguments Variable length arguments (unknown number): Non-keyword variable arguments (tuple):deffunc([formal_args,] *vargs_tuple): Argument with * will hold all remaining arguments once all formal parameters have been exhausted Keyword variable arguments (dictionary):deffunc([formal_args,][*vargst,] **vargsd): Andreas Jakl, 2009 43 Python Basics tupleVarArgs('abc') # formal arg 1: abc # formal arg 2: defaultB tupleVarArgs('abc', 123, 'xyz', 123.456) # formal arg 1: abc # formal arg 2: 123 # another arg: xyz # another arg: 123.456 deftupleVarArgs(arg1, arg2='defaultB', *theRest): print"formal arg 1: ", arg1 print"formal arg 2: ", arg2 foreachXtraArgintheRest: print'another arg: ', eachXtraArg
44. Variable Scope Global scope Declared outside a function Lifespan lasts as long as script is running Local scope Live temporarily as long as function they are defined in is active Searching for identifiers First local, then global Possible to override global variables by creating a local one Andreas Jakl, 2009 44 Python Basics global_str = "foo" deffoo(): local_str = "bar" returnglobal_str + local_str printfoo() local scope
45. Variable Scope Writing to global variables in functions: Creates a new local variable(pushes global variable out of scope) globalstatement specifically references a named global variable Andreas Jakl, 2009 45 Python Basics deffoo(): bar = 200 print"in foo(), bar is", bar bar = 100 print"in __main__, bar is", bar foo() print"in __main__, bar still is", bar deffoo(): global bar bar = 200 print"in foo(), bar is", bar bar = 100 print"in __main__, bar is", bar foo() print"in __main__, bar is now", bar local scope local scope in __main__, bar is 100 in foo(), bar is 200 in __main__, bar still is 100 in __main__, bar is 100 in foo(), bar is 200 in __main__, bar is now 200
46. Classes classMyObject(bases): “Documentation text”class_suite New style classes should be derived from any other class or from object Simplest use: container object for instance attributes Not defined in class definition Only valid for this instance Andreas Jakl, 2009 46 Python Basics classMyData(object): pass # code is required syntactically, # but no operation is desired mathObj = MyData() mathObj.x = 4 mathObj.y = 5 printmathObj.x * mathObj.y# 20
47. Classes – Subclasses, Methods __init__ similar to constructor self-parameter Passes reference to current instance Not needed for static or class methods Python wants to be explicitly clear Andreas Jakl, 2009 47 Python Basics classLibraryEntry(object): def__init__(self, id, title): self.id = id self.title = title defupdateId(self, newId): self.id = newId classLibraryBook(LibraryEntry): def__init__(self, id, title, author): LibraryEntry.__init__(self, id, title) self.author = author defupdateAuthor(self, newAuthor): self.author = newAuthor libBook = LibraryBook(1, "PyS60", "Andreas Jakl") libBook.updateId(2) libBook.updateAuthor("Nokia")
48. Classes – Attributes Instance attributes are set “on-the-fly” by using them Constructor is the first place to set instance attributes Use default arguments for default instance setup Class variables / static data have to be defined Andreas Jakl, 2009 48 Python Basics Instance attributes Class variables / static data classC(object): foo = 100 # Static data print C.foo # 100 C.foo = C.foo + 1 print C.foo # 101 classLetter(object): def__init__(self, text, author="Andreas Jakl", category=“love"): self.text = text self.author = author self.category = category defprintLetter(self): printself.text, self.author, self.category loveLetter = Letter("I love you") print dir(loveLetter) # Print all methods & attributes of this class ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'author', 'category', 'printLetter', 'text']
49. PyS60 – Application Structure How to organize your application Andreas Jakl, 2009 49
51. UI App – Example Andreas Jakl, 2009 51 importappuifw, e32 defquit(): print"Exit key pressed" app_lock.signal() appuifw.app.exit_key_handler = quit appuifw.app.title = u"UI App" print"App is now running" app_lock = e32.Ao_lock() app_lock.wait() print"Application exits"
52. Callback Function No difference to normal functions Associating function with event: binding Use function name without () to get the function object Compare to function pointers in C Andreas Jakl, 2009 52 Python Basics defquit(): pass# function is empty (instead of {} in C++ / Java) appuifw.app.exit_key_handler = quit
53. Wait for the User Previously: app. exited after executing all lines Event based UI-app: wait for user input Andreas Jakl, 2009 53 ... app_lock = e32.Ao_lock() # Create an instance of an Ao_lock object app_lock.wait() Refer to the Symbian OS course for more information about Active Objects Waiting for events quit() call-back handler app_lock.signal()
54. Application Body Andreas Jakl, 2009 54 appuifw.app.screen = "full" appuifw.app.screen = “large" appuifw.app.screen = “normal"
55. Application Body You can assign several objects to the body Canvas: provides drawable screen area + support for handling raw key events Form: complex forms with various input fields Listbox: shows a list of items (single- or double-line-item) Text: free-form text input Andreas Jakl, 2009 55
56. Application Menu Defined using tuples: Text Call-back function Specify another tuple instead to define a submenu Andreas Jakl, 2009 56 importappuifw, e32 defplay(): print"Play file" defvolume_up(): print"Volume up" defvolume_down(): print"Volume down" defquit(): print"Exit key pressed" app_lock.signal() appuifw.app.exit_key_handler = quit appuifw.app.title = u"mp3 Player" appuifw.app.menu = [(u"Play", play), (u"Volume", ( (u"Up", volume_up), (u"Down", volume_down) ) )] print"App is now running" app_lock = e32.Ao_lock() app_lock.wait() submenu Example based on [1]
57. String Manipulation Andreas Jakl, 2009 57 Python Basics txt = "I like Python" print txt[2:6] printtxt.find("like") iftxt.find("love") == -1: print"What's wrong with you?" txt.replace("like", "love") printtxt.upper() print"Length", len(txt) txt2 = "" if txt2: print"txt2 contains characters" else: print"txt2 doesn't contain characters" url = " http://www.mopius.com " url = url.strip() ifurl.startswith("http://"): printurl, "is a valid URL" webServiceInput = " 1, 2, 3, 4" printwebServiceInput.replace(" ", "") txt = "one;two;three" printtxt.split(";") http://www.mopius.com is a valid URL 1,2,3,4 ['one', 'two', 'three'] like 2 What's wrong with you? I LIKE PYTHON Length 13 txt2 doesn't contain characters
58. String Formatting String slicing like for lists: [start:end] Assemble string based on other variables: Andreas Jakl, 2009 58 Python Basics print "Host: %sPort: %d" % ("Earth", 80) print "DD.MM.YYYY = %02d.%02d.%d" % (12, 3, 82) list = [3, 2, 1, "go"] # A list has to be converted to a tuple first print "Counting: %d, %d, %d, %s" % tuple(list) Host: EarthPort: 80 DD.MM.YYYY = 12.03.82 Counting: 3, 2, 1, go
59. Example – Inbox Search Andreas Jakl, 2009 59 import inbox, appuifw # Create an instance of the Inbox object box = inbox.Inbox() # Query search phrase query = appuifw.query(u"Search for:", "text").lower() hits = [] ids = [] # sms_messages() returns message IDs for all messages in the SMS inbox forsms_idinbox.sms_messages(): # Retrieve the full message text and convert it to lowercase msg_text = box.content(sms_id).lower() ifmsg_text.find(query) != -1: # If the text was found, store a preview hits.append(msg_text[:25]) ids.append(sms_id) # Display all results in a list index = appuifw.selection_list(hits, 1) if index >= 0: # Show the full text of the selected message appuifw.note(box.content(ids[index]))
60. Event Loop e32.Ao_lock waits for events, but stops execution Game: App. has to be active all the time But still needs respond to events (keys, ...) Andreas Jakl, 2009 60 Initialize event call-backs while <end condition>: Update game state Redraw screen Pause / yield Sleep (+ execute waiting active objects): e32.ao_sleep(interval) Yield (just execute ready active objects withhigher priority) e32.ao_yield()
62. Exceptions Example:Exception “NameError” raised by the interpreter: Andreas Jakl, 2009 62 >>> print foo Traceback (most recent call last): File “<stdin>", line 1, in <module> print foo NameError: name 'foo' is not defined
63. Exceptions try:try_suite # watch for exceptions hereexcept Exception[, reason]:except_suite # exception-handling code Different objects derived from Exception Exception arguments / reasons: May be passed along Not just a string, but contains more information Andreas Jakl, 2009 63
64. Exceptions – Information Andreas Jakl, 2009 64 try: f = file(u"c:pythontest.txt", "w+") print >> f, "Welcome to Python" f.seek(0) print"File contents:", f.read() f.close() exceptIOError, reason: print reason [Errno 2] No such file or directory: u'c:pythontest.txt' printreason.filename printreason.errno printreason.strerror c:ythonest.txt 2 No such file or directory
65. Multiple Exceptions Catching multiple exceptions: Multipleexcept-statements Multiple exceptions in one exceptstatement Catch the base class Exception(no good coding style – you might be silently dropping errors) Andreas Jakl, 2009 65
66. Code Examples Code snippets for: Camera Text to Speech Sound recording / playing Bluetooth Networking Graphics, UI 3D (Open GL ES) Sensor ... Andreas Jakl, 2009 66 http://www.mobilenin.com/pys60/menu.htm Additional modules: http://cyke64.googlepages.com/
67. Bonus – Acceleration Sensor (3rd Ed (FP1)) Andreas Jakl, 2009 67 import appuifw,e32,sensor defget_sensor_data(status): "Callback function for regular accelerometer status" print "x: %d, y: %d, z: %d" % (status['data_1'], status['data_2'], status['data_3']) defexit_key_handler(): # Disconnect from the sensor and exit acc_sensor.disconnect() app_lock.signal() appuifw.app.exit_key_handler = exit_key_handler # Retrieve the acceleration sensor sensor_type = sensor.sensors()['AccSensor'] # Create an acceleration sensor object acc_sensor = sensor.Sensor(sensor_type['id'],sensor_type['category']) # Connect to the sensor acc_sensor.connect(get_sensor_data) # Wait for sensor data and the exit event app_lock = e32.Ao_lock() app_lock.wait()
68. Bonus – Acceleration Sensor (3rd Ed FP2+) Andreas Jakl, 2009 68 from sensor import * import e32, time, appuifw classDemoApp(): def __init__(self): self.accelerometer = AccelerometerXYZAxisData(data_filter=LowPassFilter()) self.accelerometer.set_callback(data_callback=self.my_callback) self.counter = 0 defmy_callback(self): # For stream sensor data the callback is hit 35 times per sec (On 5800). # The device cannot handle resource hungry operations like print in the callback function # for such high frequencies. A workaround is to sample the data as demonstrated below. ifself.counter% 5 == 0: print "X:%s, Y:%s, Z:%s" % (self.accelerometer.x, self.accelerometer.y, self.accelerometer.z) self.counter = self.counter + 1 def run(self): self.accelerometer.start_listening() defexit_key_handler(): # Disconnect from the sensor and exit global d d.accelerometer.stop_listening() print "Exiting Accelorometer" app_lock.signal() if __name__ == '__main__': appuifw.app.exit_key_handler = exit_key_handler d = DemoApp() d.run() app_lock = e32.Ao_lock() app_lock.wait()
69. Literature – Recommended Andreas Jakl, 2009 Mobile Python JürgenScheible, Ville Tuulos Complete overview of Python development for PyS60, many small code samples.Status: Symbian OS 9, PyS60 1.4, 2007 Free code samples:http://www.mobilenin.com/pys60/menu.htm Core Python Programming (Second Edition) Wesley J. Chun Python for developers who already know other languages. Comprehensive short overview, in later chapters a detailed overview of the individual components.Status: 2007 69