Wiley.Mobile.Python.Rapid.prototyping.of.applications.on.the.mobile.platform.Dec.2007 (779889), страница 45
Текст из файла (страница 45)
Thus,your program can choose an appropriate action to take based on astring originating from the network or from the user, without an ifstatement.Introspection can be implemented in a straightforward manner usinga symbol table that is maintained by the Python interpreter. The symboltable contains a mapping from all names defined in the program code tothe corresponding objects. Actually, the symbol table can be thought ofas a special dictionary that contains everything related to the internals ofthe current module. In some sense, it is like an internal address book forfinding and executing code in a module.At any point of execution, the interpreter maintains two separatesymbol tables: one for the global scope and one for the local objectsin the current function.
Actually, the global keyword, which was firstmentioned in Chapter 3, just instructs the interpreter to place an objectin the global symbol table instead of the default local one.232EFFECTIVE PYTHON FOR S60In Python, functions are objects too and they can be found in thesymbol table just like any other named entity in your program. Becauseof this, it is possible to retrieve and call a function by its name at run-time.With this approach, you can use input data to decide which functionsto call on the fly, without having to hard-code all possible cases in yourprogram beforehand.In practice, this is the most important direct use of the symbol table ina normal application.
Many other tricks on the symbol table are generallyconsidered unnecessarily ugly and unsafe.Let’s start with a simple example that calls a function based on theuser’s input.Example 105: Symbol tableimport appuifwdef bark():appuifw.note(u"Ruff ruff!")def sing():appuifw.note(u"Tralala")func_name = appuifw.query(u"What shall I do?", "text")func = globals()[func_name]print globals()func()The program gets the string func name from the user through a querydialog. This string is used as a key to the current global symbol table thatis returned by the function globals().
If the key cannot be found inthe symbol table, an exception is raised and the execution terminates. Ifthe key is found, the corresponding function is called: try to type either‘bark’ or ‘sing’ in the example above and see what happens.After this, the symbol table is printed out to give you some idea whatit actually contains. The exact output depends on what you typed in thedialog but it looks roughly like this:{'__builtins__’: <module '__builtin__’ (built-in)>,'name__’: '__main__’,'bark’: <function bark at 0xb7db1e64>,'sing’: <function sing at 0xb7db2e65>,'func’: <function bark at 0xb7db1e64>,'func_name’: 'bark’,'__doc__’: None}Here, the user told the program to bark, so from the symbol table youcan see that the variable func name is assigned the string "bark".
Bydefault, the table contains some special entries such as 'builtins ’, which refers to the module containing Python’s built-inINTROSPECTION233functions, ' name ’, which is always ' main ’ for the module that started the process and ' document ’, which contains thedocumentation string for this module.You can see that the functions bark() and sing() have entries inthe table which point at the corresponding function objects.
Since theuser told us to bark, we retrieved the bark() function from the symboltable, using func name as the key and assigned the retrieved functionobject to the variable func. We could have called the function barkdirectly without creating the new func variable, but it was included hereto illustrate operation of the symbol table.On the last line of Example 105, we finally call the function func.Depending on the input, either the bark() or sing() function is called.The main benefit of this approach is that we do not need a long list of ifstatements to decide what to do.
Also, if we add a new function to theprogram, for instance yodel(), we could just implement the functionwithout needing to change or add anything in the control logic. If afunction corresponding to the string does not exist in the symbol table,an exception is thrown. Any real program should include a try–exceptclause to handle cases like this.Using these ideas, we can re-write the phone-as-a-server examplefrom Section 8.7. The original version has a separate if clause for everyresource in the server. If we increase the number of resources shared bythe server, the list of choices would soon become difficult to maintain.In contrast, we can use the global symbol table and call each functiondirectly by the resource name.Example 106: Introspective web serviceimport e32, json, camera, graphics, sysinfo, urllibURL = "http://192.168.0.2:9000"imei = sysinfo.imei()def json_request(req):enc = json.write(req)return json.read(urllib.urlopen(URL, enc).read())def RSC_screenshot_jpg():img = graphics.screenshot()img.save("c:\\python\\temp.jpg")data = file("c:\\python\\temp.jpg").read()return ("image/jpeg", data)def RSC_battery():txt = "Current battery level is %d" % sysinfo.battery()return ("text/plain", txt)def RSC_exit():global go_ongo_on = False234EFFECTIVE PYTHON FOR S60go_on = Truemsg = {}while go_on:ret = {}for path in json_request(msg):rsc = "RSC_%s" % path[1:].replace(".", "_")if rsc in globals():ret[path] = globals()[rsc]()else:ret[path] = ("text/plain", "unknown resource")msg = rete32.ao_sleep(5)Here we use the same symbol table technique to call a function.However, we do not use the input string as such to define the functionto call.
Instead, we have prefixed the name of each function that definesa valid resource with "RSC ". This is to ensure that the user cannot callany function in the program, such as the function json request()that is meant only for internal use.This is an extremely important security precaution. An untrusted outsider should be allowed to call only a restricted set of functions. If weused any user input to access the symbol table directly, as we did in thefirst example, the user could easily crash the program by accessing anunintended entry in the table. In the worst case, a malicious user might beable to destroy important data by controlling the program as she wishes.By prefixing all resource requests with "RSC ", we make sure that theuser can access only the functions that are serving valid resources.10.3Custom Modules and Automatic UpdatingIn this section, we explain how you can make modules by yourself forPyS60.
The process in itself is almost trivial. However, custom modulesare an extremely powerful feature of PyS60, with remarkably interestingimplications. Not only can you structure your code more efficiently, butyou can also make totally new kinds of programs, thanks to the dynamicnature of PyS60.To demonstrate this, we show how to update your PyS60 applications automatically from the web and how to create a simple plug-inmechanism for your program.10.3.1 Custom ModulesThere is nothing really special in custom modules. You just create a sourcecode file, put some custom functions in it and copy it to a certain locationCUSTOM MODULES AND AUTOMATIC UPDATING235on your mobile phone. After this, you can import the new module intoyour programs, in the same way as any standard PyS60 module.Let’s go through this process step by step.
First, let’s make a file thatcontains a simple function and the import statement that imports themodules needed by the function, as usual. Here, we use the askword()function from Example 10:import appuifwdef askword():d = appuifw.query(u"Type your name", "text")appuifw.note(u"Hi " + str(word))Save these five lines to a file called mymodule.py on your PC. Next,we need to upload this file to your phone. However, to be usable as amodule, the file has to be copied to a special directory, E:\Python\lib,on your phone.
If this directory does not exist, you have to create it first.This process is exactly the same as with the custom JSON module thatwe installed in Section 8.2.2.After you have uploaded the file successfully to your phone, wecan make another file that uses the custom module.
Alternatively, youcould test it using the Bluetooth console (see Appendix B). We can useExample 107 to test the new module.Example 107: Importing a custom moduleimport mymodule, appuifwappuifw.note(u"This is the main program")mymodule.askword()As you can see, we import the new module mymodule just like thestandard module appuifw. As you could guess, the module’s name isderived from the file name. After the module has been imported, you canuse its functions in the usual way – just remember to prefix any functioncall with the module name, as in mymodule.askword() above.When you execute the example, you first see a note saying ‘This is themain program’ and then you are asked to ‘Type your name’ when theexecution proceeds to the mymodule.askword() function.As you can see, making custom modules is really straightforward inPyS60. However, there is one important thing to remember: the globalkeyword that makes a variable accessible to many functions affects onlyone module.