summaryrefslogtreecommitdiffhomepage
path: root/python.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'python.html.markdown')
-rw-r--r--python.html.markdown118
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)