Diferències
Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.
| Ambdós costats versió prèvia Revisió prèvia | |||
| info:cursos:pue:python-pcpp1:m2:3.1 [08/11/2023 16:06] – mate | info:cursos:pue:python-pcpp1:m2:3.1 [13/12/2023 23:19] (actual) – mate | ||
|---|---|---|---|
| Línia 60: | Línia 60: | ||
| Examples: | Examples: | ||
| - | < | + | < |
| # Bad: | # Bad: | ||
| Línia 70: | Línia 70: | ||
| </ | </ | ||
| - | < | + | < |
| def my_function(x, | def my_function(x, | ||
| return x * y | return x * y | ||
| </ | </ | ||
| + | == Continuation lines | ||
| + | Continuation lines (i.e., logical lines of code that you want to split because they’re too long or because you want to improve readability) are allowed if using parentheses/ | ||
| + | |||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | my_list_one = [1, 2, 3, | ||
| + | 4, 5, 6 | ||
| + | ] | ||
| + | |||
| + | a = my_function_name(a, | ||
| + | d, e, f) | ||
| + | |||
| + | </ | ||
| + | |||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | my_list_one = [ | ||
| + | 1, 2, 3, | ||
| + | 4, 5, 6, | ||
| + | ] | ||
| + | |||
| + | a = my_function_name(a, | ||
| + | d, e, f) | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | my_list_two = [ | ||
| + | 1, 2, 3, | ||
| + | 4, 5, 6, | ||
| + | ] | ||
| + | |||
| + | |||
| + | def my_fun( | ||
| + | a, b, c, | ||
| + | d, e, f): | ||
| + | return (a + b + c) * (d + e + f) | ||
| + | </ | ||
| + | | ||
| + | You can read more about indentation in the context of continuation lines at https:// | ||
| + | |||
| + | == Maximum Line Length and Line Breaks | ||
| + | If possible, you should limit all lines to a maximum of 79 characters as this will help you avoid wrapping several lines of code. If line wrapping is inevitable, use Python’s implied line continuation from the previous page. | ||
| + | |||
| + | In the case of docstrings and comments, the line length should not exceed 72 characters. | ||
| + | |||
| + | For convenience, | ||
| + | |||
| + | Still, the Python Standard Library is conservative in this matter, and requires you to use no more than 79 characters per line (72 for comments/ | ||
| + | |||
| + | == Line breaks and operators | ||
| + | Even though in Python you’re allowed to break code lines before or after binary operators (providing you do so consistently and that this convention has been used in your code before), it is recommended that you follow Donald Knuth’s style suggestions and break before binary operators as this results in a more readable, eye-friendly code. | ||
| + | |||
| + | Example: | ||
| + | <code python ✔> | ||
| + | # Recommended | ||
| + | |||
| + | total_fruits = (apples | ||
| + | + pears | ||
| + | + grapes | ||
| + | - (black currants - red currants) | ||
| + | - bananas | ||
| + | + oranges) | ||
| + | |||
| + | </ | ||
| + | |||
| + | == Blank Lines | ||
| + | Blank lines, called vertical whitespaces, | ||
| + | |||
| + | They allow the person reading your code to see the division of the code into sections, help them better understand the relation between the sections, and grasp the logic of given blocks of code more easily. | ||
| + | |||
| + | In the same fashion, using too many blank lines in your code will make it look sparse and more difficult to follow, which is why you must always be careful not to overuse them. | ||
| + | |||
| + | PEP 8 recommends that you should use: | ||
| + | |||
| + | * **two blank lines** to surround top-level function and class definitions: | ||
| + | <code python ✔> | ||
| + | class ClassOne: | ||
| + | pass | ||
| + | |||
| + | |||
| + | Class ClassTwo: | ||
| + | pass | ||
| + | |||
| + | |||
| + | def my_top_level_function(): | ||
| + | return None | ||
| + | |||
| + | </ | ||
| + | * **a single blank line** to surround method definitions inside a class: | ||
| + | <code python ✔> | ||
| + | class MyClass: | ||
| + | def method_one(self): | ||
| + | return None | ||
| + | |||
| + | def method_two(self): | ||
| + | return None | ||
| + | </ | ||
| + | * **blank lines in functions in order to indicate logical sections** (sparingly). For example: | ||
| + | <code python ✔> | ||
| + | def calculate_average(): | ||
| + | how_many_numbers = int(input(" | ||
| + | | ||
| + | if how_many_numbers > 0: | ||
| + | sum_numbers = 0 | ||
| + | for i in range(0, how_many_numbers): | ||
| + | number = float(input(" | ||
| + | sum_numbers += number | ||
| + | |||
| + | average = 0 | ||
| + | average = sum_numbers / how_many_numbers | ||
| + | |||
| + | return average | ||
| + | else: | ||
| + | return " | ||
| + | </ | ||
| + | |||
| + | == Default encodings | ||
| + | It is recommended that you **use Python’s default encodings (Python 3 -- UTF-8, Python 2 -- ASCII)**. Non-default encodings are discouraged and should only be used for test purposes or in situations where your comments or docstrings use a name (e.g., an author’s name) that contains a non-ASCII character. | ||
| + | |||
| + | PEP 8 states that “all identifiers in the Python standard library **MUST use ASCII-only identifiers, | ||
| + | |||
| + | Note: See [[https:// | ||
| + | |||
| + | == Imports | ||
| + | You should always **put imports at the beginning of your script**, between module comments/ | ||
| + | |||
| + | - Standard library imports; | ||
| + | - Related third-party imports; | ||
| + | - Local application/ | ||
| + | |||
| + | PEP 8 recommends that your imports be **on separate lines**, rather than squeezed onto one line: | ||
| + | |||
| + | Make sure you insert a blank line to separate each of the above groups of imports. | ||
| + | |||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | import sys, os | ||
| + | |||
| + | </ | ||
| + | |||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | import os | ||
| + | import sys | ||
| + | |||
| + | </ | ||
| + | |||
| + | Still, it’s correct to make a one-line import using the '' | ||
| + | <code python ✔> | ||
| + | from subprocess import Popen, PIPE | ||
| + | </ | ||
| + | |||
| + | If possible, **use absolute imports** (i.e., imports that use absolute paths separated by full stops). For example: | ||
| + | <code python ✔> | ||
| + | import animals.mammals.dogs.puppies | ||
| + | </ | ||
| + | |||
| + | Such imports are preferred in Python, especially when your application is not overgrown or extremely complex. | ||
| + | |||
| + | You shouldn’t (and actually you cannot) use implicit relative imports, as these are no longer present in Python 3. You should also avoid using wildcard imports, for example: | ||
| + | <code python ❌> | ||
| + | from animals import * | ||
| + | </ | ||
| + | as they inhibit code readability and may interfere with some of the names already present in the namespace. | ||
| + | |||
| + | == Recommendations for string quotes, whitespace, and trailing commas | ||
| + | In this section, we’ll focus on style recommendations related to such things as: | ||
| + | |||
| + | * string quotes; | ||
| + | * whitespace in expressions and statements, and the use of trailing commas. | ||
| + | |||
| + | === String quotes | ||
| + | Python allows us to use single-quoted (e.g., 'a string' | ||
| + | |||
| + | However, to improve readability, | ||
| + | |||
| + | * if your string contains single-quote characters, it’s recommended that you use double-quoted strings; | ||
| + | * if your string contains double-quote characters, it’s recommended that you use single-quoted strings. | ||
| + | |||
| + | In the case of triple-quoted strings, PEP 8 recommends that you always use double-quote characters to maintain consistency with the docstring convention detailed in PEP 257 (we’re going to tell you more about this soon). | ||
| + | |||
| + | === Whitespace in expressions and statements | ||
| + | PEP 8 contains a long section that shows examples of correct and incorrect uses of whitespace in code. Generally, you should **avoid using too much whitespace**, | ||
| + | |||
| + | So, for example, do **not** use excessive whitespace **immediately inside parentheses/ | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | my_list = ( dog[ 2 ] , 5 , { " | ||
| + | if 5 in my_list : print( " | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | my_list = (dog[2], 5, {" | ||
| + | if 5 in my_list: print(" | ||
| + | </ | ||
| + | | ||
| + | In the case of a slice, the colon should have equal amounts of space on both sides (it should act like a binary operator) unless a slice parameter is omitted, in which case the space should be omitted, too. | ||
| + | |||
| + | Examples: | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | bread[0 : 3], roll[1: 3 :5], bun[3: 5:], donut[ 1: :5 ] | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | bread[0:3], roll[1: | ||
| + | |||
| + | </ | ||
| + | |||
| + | === Trailing commas | ||
| + | Again, do **not use excessive whitespace**: | ||
| + | |||
| + | * after a trailing comma followed by a closing parenthesis, | ||
| + | * immediately before an opening parenthesis that marks the beginning of the argument list of a function invocation, or | ||
| + | * immediately before an opening parenthesis that marks the beginning of indexing/ | ||
| + | Examples: | ||
| + | |||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | my_tuple = (0, 1, 2, ) | ||
| + | my_function (5) | ||
| + | my_dictionary [' | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | my_tuple = (0, 1, 2,) | ||
| + | my_function(5) | ||
| + | my_dictionary[' | ||
| + | </ | ||
| + | Don’t use more than one space before and after operators, e.g.: | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | a = 1 | ||
| + | b = a + 2 | ||
| + | my_string = ' | ||
| + | |||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | a = 1 | ||
| + | b = a + 2 | ||
| + | my_string = ' | ||
| + | |||
| + | </ | ||
| + | Surround binary operators with a single space on both sides. However, if in your code there are operators that have different priorities, you may wish to consider adding spacing around the low(est) priority operators only, e.g.: | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | x=x+3 | ||
| + | x -=1 | ||
| + | |||
| + | x = x * 2 - 1 | ||
| + | x = (x - 1) * (x + 2) | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | x = x + 3 | ||
| + | x -= 1 | ||
| + | |||
| + | x = x*2 - 1 # Use your own judgement. | ||
| + | x = (x-1) * (x+2) # Use your own judgement. | ||
| + | |||
| + | </ | ||
| + | Don’t surround the = operator with spaces if it’s used to indicate a keyword argument/ | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | def my_function(x, | ||
| + | return x * y | ||
| + | |||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | def my_function(x, | ||
| + | return x * y | ||
| + | </ | ||
| + | |||
| + | == Recommendations for using comments | ||
| + | Comments are meant to improve the readability of the code without affecting the output of the program. Good programmers document their code and explain the more complex code snippets, so that the person reading the code properly understands what’s going on in the program. You should use comments wisely, and whenever possible write code that will self-comment (e.g., give your variables, functions, and code elements proper names). | ||
| + | |||
| + | There are a few rules you should follow when leaving comments in code: | ||
| + | |||
| + | * Write comments that will not contradict the code or mislead the reader. They’re much worse than no comment at all. | ||
| + | * Update your comments when your program gets updated. | ||
| + | * Write comments as **complete sentences** (capitalize the first word if it’s not an identifier, and end your sentence with a full stop). For example: | ||
| + | |||
| + | <code python> | ||
| + | # Program that calculates body mass index (BMI). | ||
| + | |||
| + | height = float(input(" | ||
| + | weight = float(input(" | ||
| + | bmi = round(weight / (height*height), | ||
| + | |||
| + | print(" | ||
| + | </ | ||
| + | * When writing block comments with multi-sentence comments, use two spaces after each full stop ending a sentence, except after the final sentence. | ||
| + | * Write comments in English (unless you are 100% sure that the code will never be read by people who don’t speak your language.) | ||
| + | * Comments should consist of no more than 72 characters per line (but you know that already). | ||
| + | |||
| + | == Block comments | ||
| + | Block comments are usually longer, and you should use them to explain sections of code rather than particular lines. They let you leave information for the reader in multiple lines (and multiple sentences). Generally, block comments: | ||
| + | |||
| + | * should refer to the code that follows them; | ||
| + | * should be indented to the same level as the code they describe. | ||
| + | When writing block comments, start each line with # followed by a single space, and separate paragraphs by a line that contains the # symbol only. For example: | ||
| + | <code python> | ||
| + | def calculate_product(): | ||
| + | # Calculate the average of three numbers obtained from the user. Then | ||
| + | # multiply the result by 4.17, and assign it to the product variable. | ||
| + | # | ||
| + | # Return the value passed to the product variable and use it | ||
| + | # for the subsequent x to y calculations to speed up the process. | ||
| + | sum_numbers = 0 | ||
| + | | ||
| + | for number in range(0, 3): | ||
| + | number = float(input(" | ||
| + | sum_numbers += number | ||
| + | | ||
| + | average = (sum_numbers / 3) * 4.17 | ||
| + | product = average | ||
| + | return product | ||
| + | |||
| + | x = product * 1.73 | ||
| + | y = x ** 2 | ||
| + | x_to_y = (x*y) / 1.05 | ||
| + | </ | ||
| + | |||
| + | == Inline comments | ||
| + | Inline comments are comments that are **written on the same line as your statements**. They should address or provide **further explanation to a single line of code or a single statement**. You should not overuse them. | ||
| + | |||
| + | Generally, inline comments should be: | ||
| + | |||
| + | * separated by two (or more) spaces from the statement they address; | ||
| + | * used sparingly. | ||
| + | They can quickly help you remember what a particular line of code does, or be useful when read by someone unfamiliar with your code. For example: | ||
| + | <code python ✔> | ||
| + | counter = 0 # Initialize the counter. | ||
| + | </ | ||
| + | However, don’t use inline comments (or any other comments!) to explain obvious or unnecessary things. For example: | ||
| + | <code python ❌> | ||
| + | a += 1 # Increment a. | ||
| + | </ | ||
| + | Always try making your code self-commenting rather than adding comments, even if they seem sensible or necessary, e.g.: | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | a = ' | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | user_first_name = ' | ||
| + | </ | ||
| + | |||
| + | == Documentation strings | ||
| + | Documentation strings, or **docstrings** as they’re often called, let you provide **descriptions and explanations for all public modules, files, functions, classes, and methods** you use in your code. You should use them in this context. | ||
| + | |||
| + | We’re going to deal with docstrings when we talk about **PEP 257** later in the course. For the time being, you just need to remember that they’re a type of comment that begins and ends with three double quotes: """ | ||
| + | |||
| + | Examples: | ||
| + | <code python> | ||
| + | # A multi-line docstring: | ||
| + | |||
| + | def fun(x, y): | ||
| + | """ | ||
| + | and return a list of strings. | ||
| + | """ | ||
| + | ... | ||
| + | |||
| + | </ | ||
| + | <code python> | ||
| + | # A single-line docstring: | ||
| + | |||
| + | def fun(x): | ||
| + | """ | ||
| + | ... | ||
| + | </ | ||
| + | | ||
| + | == Naming conventions – Introduction | ||
| + | When programming, | ||
| + | |||
| + | You most certainly already follow some conventions for giving names to variables, functions, and classes in your code; some of them may come from your former programming experience in other languages, others may be a purely practical choice, while still others may be determined by the project requirements or practices adopted by your company or team. | ||
| + | |||
| + | Python naming conventions are, unfortunately, | ||
| + | === Naming styles | ||
| + | There are many different naming styles used in programming, | ||
| + | |||
| + | * a – single lowercase letter | ||
| + | * A – single uppercase letter | ||
| + | |||
| + | Generally, you should avoid using single-letter names like l (the lowercase letter el), I (the uppercase letter eye), and O (the uppercase letter oh), because they can easily be mistaken for the numbers 1 and 0, and make your code much less readable. | ||
| + | |||
| + | * mysamplename – lowercase | ||
| + | * my_sample_name – lowercase with underscores (snake_case) | ||
| + | * MYSAMPLENAME – uppercase | ||
| + | * MY_SAMPLE_NAME – uppercase with underscores (SNAKE_CASE) | ||
| + | * MySampleName – CamelCase (also known as capitalized words, StudlyCaps, or CapWords) | ||
| + | A short note: when you use acronyms, you should capitalize all the letters that make up the acronym, e.g., HTTPServerError | ||
| + | * mySampleName – mixed case, which actually differs from CamelCase only by having an initial lowercase character | ||
| + | My_Sample_Name – capitalized words with underscores (considered ugly by PEP 8) | ||
| + | * _my_sample_name – a name that starts with a single leading underscore indicates a weak " | ||
| + | * my_sample_name_ -– a single trailing underscore is used by convention in order to avoid any conflicts with Python keywords, e.g., class_ | ||
| + | * %%__my_sample_name%% – a name that starts with a double leading underscore is used for class attributes where it invokes name mangling, e.g., inside the class MySampleClass, | ||
| + | * %%__my_sample_name__%% – a name that starts and ends with a double underscore is used for " | ||
| + | |||
| + | === Naming conventions – recommendations | ||
| + | PEP 8 provides for a specific naming convention with regard to a specific identifier. | ||
| + | |||
| + | When giving a name to a **variable**, | ||
| + | |||
| + | Functions follow the same rules as variables, i.e., when giving a name to a **function**, | ||
| + | |||
| + | When giving a name to a **class**, you should adopt the CamelCase style, e.g., MySampleClass, | ||
| + | |||
| + | When giving a name to a **method**, you should use a lowercase word or words separated by underscores, | ||
| + | |||
| + | When giving a name to a **constant**, | ||
| + | |||
| + | When giving a name to a **module**, you should use a lowercase word or words, preferably short, and separate them with underscores, | ||
| + | |||
| + | When giving a name to a **package**, | ||
| + | |||
| + | **Type variable** names should follow the CamelCase convention and be short, e.g., AnyStr, or Num. | ||
| + | |||
| + | When giving a name to an **exception**, | ||
| + | |||
| + | Note: You can use a different style, e.g., mixed case (mySample) for functions and variables, but only if this helps to retain backwards compatibility, | ||
| + | |||
| + | For more detailed information about PEP 8 naming conventions, | ||
| + | |||
| + | == Programming recommendations | ||
| + | There are often multiple ways of writing code that will perform the same action in Python, however PEP 8, again, imposes certain conventions and provides tips as to how you should follow the best programming practices to avoid ambiguity, keep consistency with your previous code and Python libraries, and achieve better code performance/ | ||
| + | |||
| + | Here they are: | ||
| + | |||
| + | * make comparisons to the '' | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | if x == None: | ||
| + | print(" | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | if x is None: | ||
| + | print(" | ||
| + | </ | ||
| + | * do **not** use the (in)equality operators when comparing Boolean values to True or False. Again, use is or is not instead: | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | my_boolean_value = 2 > 1 | ||
| + | if my_boolean_value == True: | ||
| + | print(" | ||
| + | else: | ||
| + | print(" | ||
| + | |||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | my_boolean_value = 2 > 1 | ||
| + | if my_boolean_value is True: | ||
| + | print(" | ||
| + | else: | ||
| + | print(" | ||
| + | </ | ||
| + | <code python ✔ ✔> | ||
| + | # Better: | ||
| + | |||
| + | my_boolean_value = 2 > 1 | ||
| + | if my_boolean_value: | ||
| + | print(" | ||
| + | else: | ||
| + | print(" | ||
| + | </ | ||
| + | * for readability purposes, use the '' | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | if not x is None: | ||
| + | print(" | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | if x is not None: | ||
| + | print(" | ||
| + | </ | ||
| + | Note: avoid using '' | ||
| + | * when you want to “catch" | ||
| + | <code python> | ||
| + | try: | ||
| + | import my_module | ||
| + | except ImportError: | ||
| + | my_module = None | ||
| + | |||
| + | </ | ||
| + | * when checking for prefixes or suffixes, use the '' | ||
| + | <code python ❌> | ||
| + | # Bad: | ||
| + | |||
| + | if name[:4] == ' | ||
| + | # do something | ||
| + | </ | ||
| + | <code python ✔> | ||
| + | # Good: | ||
| + | |||
| + | if name.startswith(' | ||
| + | # do something | ||
| + | </ | ||
| + | For more suggestions about how to write better code and what practices you should avoid, see the official PEP 8 [[https:// | ||
| + | |||
| + | Now, let’s put some of the things we’ve learned into practice. | ||