Program and Code Structure ========================== .. toctree:: :maxdepth: 1 Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. _section_heading-Program_Structure: Program Structure ----------------- * Python source code placed in files uses the .py extension. * Compiled bytecode is stored alongside source code in files with the .pyc extension. Python manages these, you can more-or-less ignore them. You don't need to revision control them and they auto-regenerate as necessary. They are also platform agnostic (but not version agnostic). * If using the IPython interpreter, you can execute source code in a file from within the interpreter using the :command:`run` command. >>> run script_name [optional-script-arguments] .. admonition:: Try it! :class: TryIt Open a terminal and type:: % cd /home/vagrant/Desktop/pythonedu/pythonedu-2017/doc/topics/program_and_code_structure % ipython3 Then, in the ipython terminal, type: >>> run try_it * Source code in a file can be fed directly to the Python interpreter at the command prompt using the syntax: .. code-block:: text % python3 script_name.py [optional-script-arguments] .. admonition:: Try it! :class: TryIt Open a terminal and type:: % cd /home/vagrant/Desktop/pythonedu/pythonedu-2017/doc/topics/program_and_code_structure % python3 try_it.py * In Linux, source code in a file can be executed directly by placing a shebang line at the top of the source file and adding the execute permissions to the file: .. code-block:: python :linenos: :emphasize-lines: 1 #!/usr/bin/python3 # -*- coding: -*- def print_greeting(): print("Hello World") if __name__ == "__main__": print_greeting() Additionally, you must make the file executable, which you can do by issuing the following command at the command line: .. code-block:: text chmod u+x script_name.py .. admonition:: Try it! :class: TryIt Open a terminal and type:: % cd /home/vagrant/Desktop/pythonedu/pythonedu-2017/doc/lessons/program_and_code_structure % nano try_it.py Add the shebang line to the top of the file. Save and exit. Then, at the terminal, type:: % chmod u+x try_it.py % ./try_it.py * In Windows, the .py extension is usually associated with the Python interpreter when installing Python. This allows you to double click on a source file to run it. * By default, source code is expected to be encoded as UTF-8. If that's not the case, put an encoding declaration in the first or second line of the file that names the encoding used (the name inside the < >): .. code-block:: python :linenos: :emphasize-lines: 2 #!/usr/bin/python3 # -*- coding: -*- def print_greeting(): print("Hello World") if __name__ == "__main__": print_greeting() The full list of supported encoding names is given `here `_. * Source code in files can tell if it is being called as a function from other source code, or, if it is the main script that is executing. It does this by checking the ``__name__`` variable using the following idiom: .. code-block:: python :linenos: :emphasize-lines: 7 #!/usr/bin/python3 # -*- coding: -*- def print_greeting(): print("Hello World") if __name__ == "__main__": print_greeting() If the source code is executed directly, then the ``if`` statement is entered and print_greeting() is called. If the source code has been imported into another file, the caller can call print_greeting() directly. .. _section_heading-Code_Structure: Code Structure -------------- .. _section_heading-Comments: Comments ^^^^^^^^ Comments use the pound ("#") symbol. There is no multi-line comment. Comments run from the point that the # is seen, until the end of the line. If the # sign is embedded in a string, it is not treated as a comment:: # This is a comment # This is another comment .. _section_heading-Line_Structure: Line Structure ^^^^^^^^^^^^^^ Python can use any standard end-of-line character sequence (``LF``, ``CR-LF``, ``CF``). Source code lines can be continued from one physical line to the next in 2 ways: 1) Explicitly, by using a \\ at the end of the line:: if a == 1 or \ b == 2: pass 2) Implicitly, when the expression is surrounded by brackets (either (), [] or {} but the brackets chosen must make sense in the context being used):: if (a == 1 or b == 2): pass Sorry...Backslashes don't continue comments. You'll manage :) Although Python allows you to place more than one statement on a line by placing semi-colons (";") between them, you shouldn't do it as it is difficult to read: >>> print("This");print("Is");print("Legal");print("But");print("Dumb") This Is Legal But Dumb .. _section_heading-Indentation: Indentation ^^^^^^^^^^^ Indenting code in Python in order to group statements is only based on the amount of white space at the start of the line which is unlike other languages that use bracing at the start or end of a statement-group (c, c++, c#) or explicit statement-group end markers (like ``end if`` in VHDL). This means that *white space is very important in Python* and remembering this is one of the biggest hurdles people have when they first start using Python. Technically, you can use tabs or spaces for indenting your source code. But, it's generally accepted that you should use spaces (i.e. use the :kbd:`space-bar` or setup your editor to insert spaces when you use the :kbd:`tab` key). If you mix actual tabs and spaces in a way that the interpreter can't figure things out, you will get a :py:exc:`TabError`. You will find that, due to :pep:`8`, practically all Python code in existence is written using 4-spaces for indentation. Furthermore, linters and other checkers are pre-setup to look for and use 4-spaces. So, unless you generally like going against the prevailing flow of things, it's best to stick to using 4-spaces. As an example, this code snippet is correctly indented:: # Check for the presence of the magic token for val in input_tokens: if val == 148: print("Found magic token value") print("Today is our lucky day!") else: print("Sadly, no magic token was found") print("Will try to stumble along the rest of the day") Python has the concept of a `"suite" `_ which is another way of saying a "list of statements". You will see the token "suite" used in many parts of the language. Take the "if" statement for example, which has the follow grammar: .. productionlist:: if_stmt if_stmt : “if” expression “:” suite : ( “elif” expression “:” suite )* : [“else” “:” suite] If you have only a 1-line suite, it is legal to stick it on the same line (although it's arguably harder to read than sticking them on their own lines):: if a == 1: print("Found it!") else: print("Not found") However, if you have multiple statements, you should move to the next line, indent it, and then list the statements:: if a == 1: print("Found it!") print("We are good to go.") else: print("Not found") print("Let NASA know") A suite cannot be empty. If you don't want to execute anything in a suite (e.g. to let reviewers / maintainers know you considered that situation), you can use the keyword ``pass`` instead. For example:: if a == 1: print("Found it!") print("We are good to go.") else: pass When you are finished the statements in a multi-line suite, un-indent (`dedent`_) in order to end the suite. So you see, indentation in Python really isn't that hard. Don't let this mess your head up. Just vow, here and now, to use the :kbd:`tab` key (setup to insert spaces) instead of a bracket symbol when ever you want to indent. Similarly, vow to use the :kbd:`shift-tab` combination (setup to remove spaces) instead of a bracket symbol or typing an end-marker, when ever you want to dedent. .. _section_heading-Identifiers: Identifiers ^^^^^^^^^^^ You can create identifiers (names) in your code using the following rules: * Can use upper or lower-case letters A-Z. * Can use the underscore. * Can use the digits 0-9 except as the first character. The above rules use only the letters and digits from the ASCII range of unicode characters (U+0001..U+007F). However, Python3 lets you use many more characters from the unicode set that are outside the ASCII range so that you can write identifiers in your native language. If you are interested in using those characters, consult :pep:`3131`. While it is possible to start/end your identifiers with the underscore character ``_``, Python interprets some uses of underscores in specific ways, and others are interpreted by agreed upon convention: ``_*`` - A single underscore in front of an identifier prevents it from being imported when you import code from one source file, into another, using the, ``from module import *``. We will discuss this more later in the course when we talk about importing code. ``__*__`` - The use of double leading underscores (commonly pronounced :term:`dunder`) and double trailing underscores (making for a dunder-dunder combination), denotes a special method name. We will learn more about special method names later. For now, resist the urge to name your identifiers like this. ``__*`` - The use of 2 leading underscores only, tells the interpreter that if that identifier belongs to something you've created in a class, then you want to make that identifier private. The interpreter will mangle the name to help avoid clashes between names in a base class and the same name in a derived class. ``*_`` - The use of a single trailing underscore can be used to avoid a name conflict with a Python keyword. For example, ``class_`` (since ``class`` is a Python keyword). This can be useful if you feel using that exact name has significant enough situation meaning and importance to warrant it. This is just a convention. ``_`` - The use of a single standalone underscore as the entire name, is often used to represent a don't care, temporary or insignificant piece of information. This is just a convention. .. _section_heading-Reserved_Words_Reference: Reserved Words Reference ^^^^^^^^^^^^^^^^^^^^^^^^ Python reserves a set of identifiers for its own use. Don't re-define these by creating an identifier with the same name in your source code. The keywords defined for Python 3.5 are:: False class finally is return None continue for lambda try True def from nonlocal while and del global not with as elif if or yield assert else import pass break except in raise As we progress through the course, you will learn about most of these keywords. For now, it's enough to know what they are so you don't define things with the same name. .. _section_heading-Operator_Reference: Operator Reference ^^^^^^^^^^^^^^^^^^ Python supports a similar set of operators as you would find in other languages. Many operators do different things depending on their operands. These operators, and their uses with different data types, are shown in :numref:`table-Python_Operators`: .. _table-Python_Operators: .. table:: Table of Python Operators +----+-----------------------------------------+ | Op | Description | +====+=========================================+ |\+ | | Numerical addition. | | | | Sequence concatenation. | +----+-----------------------------------------+ |\- | | Numerical subtraction of 2 operands. | | | | Numerical negation with 1 operand. | | | | Difference of set. | +----+-----------------------------------------+ |\* | | Numerical multiplication. | | | | Sequence replication. | | | | Sequence unpacking operator. | +----+-----------------------------------------+ |\** | | Numerical power | | | | Dictionary unpacking operator. | +----+-----------------------------------------+ | / | | Numerical division | +----+-----------------------------------------+ | // | | Numerical division with result floored| +----+-----------------------------------------+ | % | | Numerical remainder of x/y | +----+-----------------------------------------+ | @ | | Marks the usage of a decorator | +----+-----------------------------------------+ | << | | Bitwise shift left | +----+-----------------------------------------+ | >> | | Bitwise shift right | +----+-----------------------------------------+ | & | | Bitwise AND. | | | | Intersection of set. | +----+-----------------------------------------+ |\| | | Bitwise OR. | | | | Union of set. | +----+-----------------------------------------+ | ^ | | Bitwise XOR. | | | | Symmetric difference of set. | +----+-----------------------------------------+ | ~ | | Bitwise invert. | +----+-----------------------------------------+ | < | | Less-than comparator. | | | | Is-proper-subset of set. | +----+-----------------------------------------+ | > | | Greater-than comparator. | | | | Is-proper-superset of set. | +----+-----------------------------------------+ | <= | | Less-than-or-equal comparator. | | | | Is-subset of set. | +----+-----------------------------------------+ | >= | | Greater-than-or-equal comparator. | | | | Is-superset of set. | +----+-----------------------------------------+ | == | | Equal comparator. | +----+-----------------------------------------+ | != | | Not-equal comparator. | +----+-----------------------------------------+ .. _section_heading-Delimiter_Reference: Delimiter Reference ^^^^^^^^^^^^^^^^^^^ While not that exciting, for completeness, the list of delimiters used by Python is shown below:: ( ) [ ] { } , : . ; @ = -> += -= *= /= //= %= @= &= |= ^= >>= <<= **= ' " # \ Don't lose sleep over not remembering these. Their use at the right time will be obvious from the context. .. _CPython: https://en.wikipedia.org/wiki/CPython .. _Jython: https://en.wikipedia.org/wiki/Jython .. _IronPython: https://en.wikipedia.org/wiki/IronPython .. _PyPy: https://en.wikipedia.org/wiki/PyPy .. _suite: https://docs.python.org/3.5/reference/compound_stmts.html#grammar-token-suite .. _dedent: https://docs.python.org/3.5/library/token.html?highlight=dedent#token.DEDENT .. _standard_encodings: https://docs.python.org/3.5/library/codecs.html#standard-encodings