1
0
mirror of https://github.com/adambard/learnxinyminutes-docs.git synced 2025-09-25 13:58:59 +02:00

Merge branch 'master' into patch-1

This commit is contained in:
Boris Verkhovskiy
2024-04-03 04:31:13 -07:00
committed by GitHub
329 changed files with 24884 additions and 4759 deletions

View File

@@ -9,14 +9,18 @@ contributors:
- ["Rommel Martinez", "https://ebzzry.io"]
- ["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
---
Python was created by Guido van Rossum in the early 90s. It is now one of the most popular
languages in existence. I fell in love with Python for its syntactic clarity. It's basically
executable pseudocode.
Python was created by Guido van Rossum in the early 90s. It is now one of the
most popular languages in existence. I fell in love with Python for its
syntactic clarity. It's basically executable pseudocode.
Note: This article applies to Python 3 specifically. Check out [here](http://learnxinyminutes.com/docs/pythonlegacy/) if you want to learn the old Python 2.7
Note: This article applies to Python 3 specifically. Check out
[here](http://learnxinyminutes.com/docs/pythonlegacy/) if you want to learn the
old Python 2.7
```python
@@ -81,16 +85,29 @@ 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
# Using boolean logical operators on ints casts them to booleans for evaluation, but their non-cast value is returned
# Don't mix up with bool(ints) and bitwise and/or (&,|)
# None, 0, and empty strings/lists/dicts/tuples/sets all evaluate to False.
# All other values are True
bool(0) # => False
bool("") # => False
bool([]) # => False
bool({}) # => False
bool(()) # => False
bool(set()) # => False
bool(4) # => True
bool(-6) # => True
# Using boolean logical operators on ints casts them to booleans for evaluation,
# but their non-cast value is returned. Don't mix up with bool(ints) and bitwise
# and/or (&,|)
bool(0) # => False
bool(2) # => True
0 and 2 # => 0
bool(-5) # => True
bool(2) # => True
-5 or 0 # => -5
# Equality is ==
@@ -139,10 +156,10 @@ b == a # => True, a's and b's objects are equal
# You can find the length of a string
len("This is a string") # => 16
# You can also format using f-strings or formatted string literals (in Python 3.6+)
# Since Python 3.6, you can use f-strings or formatted string literals.
name = "Reiko"
f"She said her name is {name}." # => "She said her name is Reiko"
# You can basically put any Python expression inside the braces and it will be output in the string.
# Any valid Python expression inside these braces is returned to the string.
f"{name} is {len(name)} characters long." # => "Reiko is 5 characters long."
# None is an object
@@ -153,14 +170,6 @@ None # => None
"etc" is None # => False
None is None # => True
# None, 0, and empty strings/lists/dicts/tuples all evaluate to False.
# All other values are True
bool(0) # => False
bool("") # => False
bool([]) # => False
bool({}) # => False
bool(()) # => False
####################################################
## 2. Variables and Collections
####################################################
@@ -176,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
@@ -217,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]
@@ -289,7 +298,7 @@ filled_dict = {"one": 1, "two": 2, "three": 3}
# Note keys for dictionaries have to be immutable types. This is to ensure that
# the key can be converted to a constant hash value for quick look-ups.
# Immutable types include ints, floats, strings, tuples.
invalid_dict = {[1,2,3]: "123"} # => Raises a TypeError: unhashable type: 'list'
invalid_dict = {[1,2,3]: "123"} # => Yield a TypeError: unhashable type: 'list'
valid_dict = {(1,2,3):[1,2,3]} # Values can be of any type, however.
# Look up values with []
@@ -343,7 +352,7 @@ del filled_dict["one"] # Removes the key "one" from filled dict
# Sets store ... well sets
empty_set = set()
# Initialize a set with a bunch of values. Yeah, it looks a bit like a dict. Sorry.
# Initialize a set with a bunch of values.
some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4}
# Similar to keys of a dictionary, elements of a set have to be immutable.
@@ -415,7 +424,7 @@ for animal in ["dog", "cat", "mouse"]:
"""
"range(number)" returns an iterable of numbers
from zero to the given number
from zero up to (but excluding) the given number
prints:
0
1
@@ -449,8 +458,7 @@ for i in range(4, 8, 2):
print(i)
"""
To loop over a list, and retrieve both the index and the value of each item in the list
prints:
Loop over a list to retrieve both the index and the value of each list item:
0 dog
1 cat
2 mouse
@@ -477,10 +485,11 @@ try:
# Use "raise" to raise an error
raise IndexError("This is an index error")
except IndexError as e:
pass # Pass is just a no-op. Usually you would do recovery here.
pass # Refrain from this, provide a recovery (next example).
except (TypeError, NameError):
pass # Multiple exceptions can be handled together, if required.
else: # Optional clause to the try/except block. Must follow all except blocks
pass # Multiple exceptions can be processed jointly.
else: # Optional clause to the try/except block. Must follow
# all except blocks.
print("All good!") # Runs only if the code in try raises no exceptions
finally: # Execute under all circumstances
print("We can clean up resources here")
@@ -495,6 +504,7 @@ contents = {"aa": 12, "bb": 21}
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:
file.write(json.dumps(contents)) # writes an object to a file
@@ -516,7 +526,8 @@ print(contents)
filled_dict = {"one": 1, "two": 2, "three": 3}
our_iterable = filled_dict.keys()
print(our_iterable) # => dict_keys(['one', 'two', 'three']). This is an object that implements our Iterable interface.
print(our_iterable) # => dict_keys(['one', 'two', 'three']). This is an object
# that implements our Iterable interface.
# We can loop over it.
for i in our_iterable:
@@ -528,15 +539,16 @@ our_iterable[1] # Raises a TypeError
# An iterable is an object that knows how to create an iterator.
our_iterator = iter(our_iterable)
# Our iterator is an object that can remember the state as we traverse through it.
# We get the next object with "next()".
# Our iterator is an object that can remember the state as we traverse through
# it. We get the next object with "next()".
next(our_iterator) # => "one"
# It maintains state as we iterate.
next(our_iterator) # => "two"
next(our_iterator) # => "three"
# After the iterator has returned all of its data, it raises a StopIteration exception
# After the iterator has returned all of its data, it raises a
# StopIteration exception
next(our_iterator) # Raises StopIteration
# We can also loop over it, in fact, "for" does this implicitly!
@@ -544,7 +556,7 @@ our_iterator = iter(our_iterable)
for i in our_iterator:
print(i) # Prints one, two, three
# You can grab all the elements of an iterable or iterator by calling list() on it.
# You can grab all the elements of an iterable or iterator by call of list().
list(our_iterable) # => Returns ["one", "two", "three"]
list(our_iterator) # => Returns [] because state is saved
@@ -591,12 +603,12 @@ 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 to all_the_args(1, 2, 3, 4)
all_the_args(**kwargs) # equivalent to all_the_args(a=3, b=4)
all_the_args(*args, **kwargs) # equivalent to all_the_args(1, 2, 3, 4, a=3, b=4)
all_the_args(*args) # equivalent: all_the_args(1, 2, 3, 4)
all_the_args(**kwargs) # equivalent: all_the_args(a=3, b=4)
all_the_args(*args, **kwargs) # equivalent: all_the_args(1, 2, 3, 4, a=3, b=4)
# Returning multiple values (with tuple assignments)
def swap(x, y):
@@ -606,17 +618,19 @@ def swap(x, y):
x = 1
y = 2
x, y = swap(x, y) # => x = 2, y = 1
# (x, y) = swap(x,y) # Again parenthesis have been excluded but can be included.
# (x, y) = swap(x,y) # Again the use of parenthesis is optional.
# Function Scope
# global scope
x = 5
def set_x(num):
# Local var x not the same as global variable x
# local scope begins here
# local var x not the same as global var x
x = num # => 43
print(x) # => 43
def set_global_x(num):
# global indicates that particular var lives in the global scope
global x
print(x) # => 5
x = num # global var x is now set to 6
@@ -624,6 +638,12 @@ def set_global_x(num):
set_x(43)
set_global_x(6)
"""
prints:
43
5
6
"""
# Python has first class functions
@@ -635,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
@@ -646,7 +682,7 @@ list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3]
list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7]
# We can use list comprehensions for nice maps and filters
# List comprehension stores the output as a list which can itself be a nested list
# List comprehension stores the output as a list (which itself may be nested).
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
@@ -665,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
@@ -706,14 +742,16 @@ class Human:
# Note that the double leading and trailing underscores denote objects
# or attributes that are used by Python but that live in user-controlled
# namespaces. Methods(or objects or attributes) like: __init__, __str__,
# __repr__ etc. are called special methods (or sometimes called dunder methods)
# You should not invent such names on your own.
# __repr__ etc. are called special methods (or sometimes called dunder
# methods). You should not invent such names on your own.
def __init__(self, name):
# Assign the argument to the instance's name attribute
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):
@@ -761,7 +799,7 @@ if __name__ == '__main__':
i.say("hi") # "Ian: hi"
j = Human("Joel")
j.say("hello") # "Joel: hello"
# i and j are instances of type Human, or in other words: they are Human objects
# i and j are instances of type Human; i.e., they are Human objects.
# Call our class method
i.say(i.get_species()) # "Ian: H. sapiens"
@@ -798,8 +836,8 @@ if __name__ == '__main__':
# "species", "name", and "age", as well as methods, like "sing" and "grunt"
# from the Human class, but can also have its own unique properties.
# To take advantage of modularization by file you could place the classes above in their own files,
# say, human.py
# To take advantage of modularization by file you could place the classes above
# in their own files, say, human.py
# To import functions from other files use the following format
# from "filename-without-extension" import "function-or-class"
@@ -856,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'>)
@@ -923,8 +962,8 @@ class Batman(Superhero, Bat):
# However we are dealing with multiple inheritance here, and super()
# only works with the next base class in the MRO list.
# So instead we explicitly call __init__ for all ancestors.
# The use of *args and **kwargs allows for a clean way to pass arguments,
# with each parent "peeling a layer of the onion".
# The use of *args and **kwargs allows for a clean way to pass
# arguments, with each parent "peeling a layer of the onion".
Superhero.__init__(self, 'anonymous', movie=True,
superpowers=['Wealthy'], *args, **kwargs)
Bat.__init__(self, *args, can_fly=False, **kwargs)
@@ -938,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'>,
@@ -996,39 +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.
@beg
def say(say_please=False):
msg = "Can you buy me a beer?"
return msg, say_please
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
@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 :(
```
## Ready For More?
### 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)