diff options
Diffstat (limited to 'python.html.markdown')
-rw-r--r-- | python.html.markdown | 118 |
1 files changed, 86 insertions, 32 deletions
diff --git a/python.html.markdown b/python.html.markdown index 175f17ec..9d97e64d 100644 --- a/python.html.markdown +++ b/python.html.markdown @@ -10,6 +10,7 @@ contributors: - ["Roberto Fernandez Diaz", "https://github.com/robertofd1995"] - ["caminsha", "https://github.com/caminsha"] - ["Stanislav Modrak", "https://stanislav.gq"] + - ["John Paul Wohlscheid", "https://gitpi.us"] filename: learnpython.py --- @@ -84,7 +85,7 @@ False - 5 # => -5 # Comparison operators look at the numerical value of True and False 0 == False # => True -1 == True # => True +2 > True # => True 2 == True # => False -5 != False # => True @@ -184,7 +185,7 @@ print("Hello, World", end="!") # => Hello, World! input_string_var = input("Enter some data: ") # Returns the data as a string # There are no declarations, only assignments. -# Convention is to use lower_case_with_underscores +# Convention in naming variables is snake_case style some_var = 5 some_var # => 5 @@ -225,7 +226,7 @@ li[4] # Raises an IndexError li[1:3] # Return list from index 1 to 3 => [2, 4] li[2:] # Return list starting from index 2 => [4, 3] li[:3] # Return list from beginning until index 3 => [1, 2, 4] -li[::2] # Return list selecting every second entry => [1, 4] +li[::2] # Return list selecting elements with a step size of 2 => [1, 4] li[::-1] # Return list in reverse order => [3, 4, 2, 1] # Use any combination of these to make advanced slices # li[start:end:step] @@ -500,20 +501,20 @@ with open("myfile.txt") as f: # Writing to a file contents = {"aa": 12, "bb": 21} -with open("myfile1.txt", "w+") as file: +with open("myfile1.txt", "w") as file: file.write(str(contents)) # writes a string to a file import json -with open("myfile2.txt", "w+") as file: +with open("myfile2.txt", "w") as file: file.write(json.dumps(contents)) # writes an object to a file # Reading from a file -with open('myfile1.txt', "r+") as file: +with open('myfile1.txt', "r") as file: contents = file.read() # reads a string from a file print(contents) # print: {"aa": 12, "bb": 21} -with open('myfile2.txt', "r+") as file: +with open('myfile2.txt', "r") as file: contents = json.load(file) # reads a json object from a file print(contents) # print: {"aa": 12, "bb": 21} @@ -602,7 +603,7 @@ all_the_args(1, 2, a=3, b=4) prints: """ # When calling functions, you can do the opposite of args/kwargs! -# Use * to expand tuples and use ** to expand kwargs. +# Use * to expand args (tuples) and use ** to expand kwargs (dictionaries). args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # equivalent: all_the_args(1, 2, 3, 4) @@ -654,6 +655,22 @@ def create_adder(x): add_10 = create_adder(10) add_10(3) # => 13 +# Closures in nested functions: +# We can use the nonlocal keyword to work with variables in nested scope which shouldn't be declared in the inner functions. +def create_avg(): + total = 0 + count = 0 + def avg(n): + nonlocal total, count + total += n + count += 1 + return total/count + return avg +avg = create_avg() +avg(3) # => 3.0 +avg(5) # (3+5)/2 => 4.0 +avg(7) # (8+7)/3 => 5.0 + # There are also anonymous functions (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 @@ -684,8 +701,8 @@ print(math.sqrt(16)) # => 4.0 # You can get specific functions from a module from math import ceil, floor -print(ceil(3.7)) # => 4.0 -print(floor(3.7)) # => 3.0 +print(ceil(3.7)) # => 4 +print(floor(3.7)) # => 3 # You can import all functions from a module. # Warning: this is not recommended @@ -732,7 +749,9 @@ class Human: self.name = name # Initialize property - self._age = 0 + self._age = 0 # the leading underscore indicates the "age" property is + # intended to be used internally + # do not rely on this to be enforced: it's a hint to other devs # An instance method. All methods take "self" as the first argument def say(self, msg): @@ -875,7 +894,8 @@ if __name__ == '__main__': if type(sup) is Superhero: print('I am a superhero') - # Get the Method Resolution search Order used by both getattr() and super() + # Get the "Method Resolution Order" used by both getattr() and super() + # (the order in which classes are searched for an attribute or method) # This attribute is dynamic and can be updated print(Superhero.__mro__) # => (<class '__main__.Superhero'>, # => <class 'human.Human'>, <class 'object'>) @@ -957,8 +977,7 @@ class Batman(Superhero, Bat): if __name__ == '__main__': sup = Batman() - # Get the Method Resolution search Order used by both getattr() and super(). - # This attribute is dynamic and can be updated + # The Method Resolution Order print(Batman.__mro__) # => (<class '__main__.Batman'>, # => <class 'superhero.Superhero'>, # => <class 'human.Human'>, @@ -1015,37 +1034,72 @@ gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] -# Decorators -# In this example `beg` wraps `say`. If say_please is True then it -# will change the returned message. -from functools import wraps +# Decorators are a form of syntactic sugar. +# They make code easier to read while accomplishing clunky syntax. +# Wrappers are one type of decorator. +# They're really useful for adding logging to existing functions without needing to modify them. -def beg(target_function): - @wraps(target_function) +def log_function(func): def wrapper(*args, **kwargs): - msg, say_please = target_function(*args, **kwargs) - if say_please: - return "{} {}".format(msg, "Please! I am poor :(") - return msg - + print("Entering function", func.__name__) + result = func(*args, **kwargs) + print("Exiting function", func.__name__) + return result return wrapper +@log_function # equivalent: +def my_function(x,y): # def my_function(x,y): + return x+y # return x+y + # my_function = log_function(my_function) +# The decorator @log_function tells us as we begin reading the function definition +# for my_function that this function will be wrapped with log_function. +# When function definitions are long, it can be hard to parse the non-decorated +# assignment at the end of the definition. + +my_function(1,2) # => "Entering function my_function" + # => "3" + # => "Exiting function my_function" + +# But there's a problem. +# What happens if we try to get some information about my_function? + +print(my_function.__name__) # => 'wrapper' +print(my_function.__code__.co_argcount) # => 0. The argcount is 0 because both arguments in wrapper()'s signature are optional. + +# Because our decorator is equivalent to my_function = log_function(my_function) +# we've replaced information about my_function with information from wrapper + +# Fix this using functools + +from functools import wraps + +def log_function(func): + @wraps(func) # this ensures docstring, function name, arguments list, etc. are all copied + # to the wrapped function - instead of being replaced with wrapper's info + def wrapper(*args, **kwargs): + print("Entering function", func.__name__) + result = func(*args, **kwargs) + print("Exiting function", func.__name__) + return result + return wrapper -@beg -def say(say_please=False): - msg = "Can you buy me a beer?" - return msg, say_please +@log_function +def my_function(x,y): + return x+y + +my_function(1,2) # => "Entering function my_function" + # => "3" + # => "Exiting function my_function" +print(my_function.__name__) # => 'my_function' +print(my_function.__code__.co_argcount) # => 2 -print(say()) # Can you buy me a beer? -print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( ``` ### Free Online * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) -* [Ideas for Python Projects](http://pythonpracticeprojects.com) * [The Official Docs](https://docs.python.org/3/) * [Hitchhiker's Guide to Python](https://docs.python-guide.org/en/latest/) * [Python Course](https://www.python-course.eu) |