mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-11-26 09:21:00 +03:00
[python/en] Set, dict, and generator comprehensions (#2298)
* Add set and dict comprehensions for python 2 and 3 * Clean up formatting and generator explanation * Include documentation for generator comprehensions
This commit is contained in:
parent
5dee671bfe
commit
e053806775
@ -8,21 +8,21 @@ contributors:
|
|||||||
filename: learnpython.py
|
filename: learnpython.py
|
||||||
---
|
---
|
||||||
|
|
||||||
Python was created by Guido Van Rossum in the early 90s. It is now one of the
|
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
|
most popular languages in existence. I fell in love with Python for its
|
||||||
syntactic clarity. It's basically executable pseudocode.
|
syntactic clarity. It's basically executable pseudocode.
|
||||||
|
|
||||||
Feedback would be highly appreciated! You can reach me at [@louiedinh](http://twitter.com/louiedinh)
|
Feedback would be highly appreciated! You can reach me at [@louiedinh](http://twitter.com/louiedinh)
|
||||||
or louiedinh [at] [google's email service]
|
or louiedinh [at] [google's email service]
|
||||||
|
|
||||||
Note: This article applies to Python 2.7 specifically, but should be applicable
|
Note: This article applies to Python 2.7 specifically, but should be applicable
|
||||||
to Python 2.x. Python 2.7 is reaching end of life and will stop being
|
to Python 2.x. Python 2.7 is reaching end of life and will stop being
|
||||||
maintained in 2020, it is though recommended to start learning Python with
|
maintained in 2020, it is though recommended to start learning Python with
|
||||||
Python 3. For Python 3.x, take a look at the [Python 3 tutorial](http://learnxinyminutes.com/docs/python3/).
|
Python 3. For Python 3.x, take a look at the [Python 3 tutorial](http://learnxinyminutes.com/docs/python3/).
|
||||||
|
|
||||||
It is also possible to write Python code which is compatible with Python 2.7
|
It is also possible to write Python code which is compatible with Python 2.7
|
||||||
and 3.x at the same time, using Python [`__future__` imports](https://docs.python.org/2/library/__future__.html). `__future__` imports
|
and 3.x at the same time, using Python [`__future__` imports](https://docs.python.org/2/library/__future__.html). `__future__` imports
|
||||||
allow you to write Python 3 code that will run on Python 2, so check out the
|
allow you to write Python 3 code that will run on Python 2, so check out the
|
||||||
Python 3 tutorial.
|
Python 3 tutorial.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -549,6 +549,10 @@ filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
|
|||||||
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
|
[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]
|
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
|
||||||
|
|
||||||
|
# You can construct set and dict comprehensions as well.
|
||||||
|
{x for x in 'abcddeef' if x in 'abc'} # => {'d', 'e', 'f'}
|
||||||
|
{x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
## 5. Classes
|
## 5. Classes
|
||||||
@ -668,10 +672,10 @@ import math
|
|||||||
dir(math)
|
dir(math)
|
||||||
|
|
||||||
# If you have a Python script named math.py in the same
|
# If you have a Python script named math.py in the same
|
||||||
# folder as your current script, the file math.py will
|
# folder as your current script, the file math.py will
|
||||||
# be loaded instead of the built-in Python module.
|
# be loaded instead of the built-in Python module.
|
||||||
# This happens because the local folder has priority
|
# This happens because the local folder has priority
|
||||||
# over Python's built-in libraries.
|
# over Python's built-in libraries.
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
@ -679,44 +683,54 @@ dir(math)
|
|||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
# Generators
|
# Generators
|
||||||
# A generator "generates" values as they are requested instead of storing
|
# A generator "generates" values as they are requested instead of storing
|
||||||
# everything up front
|
# everything up front
|
||||||
|
|
||||||
# The following method (*NOT* a generator) will double all values and store it
|
# The following method (*NOT* a generator) will double all values and store it
|
||||||
# in `double_arr`. For large size of iterables, that might get huge!
|
# in `double_arr`. For large size of iterables, that might get huge!
|
||||||
def double_numbers(iterable):
|
def double_numbers(iterable):
|
||||||
double_arr = []
|
double_arr = []
|
||||||
for i in iterable:
|
for i in iterable:
|
||||||
double_arr.append(i + i)
|
double_arr.append(i + i)
|
||||||
|
|
||||||
# Running the following would mean we'll double all values first and return all
|
# Running the following would mean we'll double all values first and return all
|
||||||
# of them back to be checked by our condition
|
# of them back to be checked by our condition
|
||||||
for value in double_numbers(range(1000000)): # `test_non_generator`
|
for value in double_numbers(range(1000000)): # `test_non_generator`
|
||||||
print value
|
print value
|
||||||
if value > 5:
|
if value > 5:
|
||||||
break
|
break
|
||||||
|
|
||||||
# We could instead use a generator to "generate" the doubled value as the item
|
# We could instead use a generator to "generate" the doubled value as the item
|
||||||
# is being requested
|
# is being requested
|
||||||
def double_numbers_generator(iterable):
|
def double_numbers_generator(iterable):
|
||||||
for i in iterable:
|
for i in iterable:
|
||||||
yield i + i
|
yield i + i
|
||||||
|
|
||||||
# Running the same code as before, but with a generator, now allows us to iterate
|
# Running the same code as before, but with a generator, now allows us to iterate
|
||||||
# over the values and doubling them one by one as they are being consumed by
|
# over the values and doubling them one by one as they are being consumed by
|
||||||
# our logic. Hence as soon as we see a value > 5, we stop break out of the
|
# our logic. Hence as soon as we see a value > 5, we break out of the
|
||||||
# loop and don't need to double most of the values sent in (MUCH FASTER!)
|
# loop and don't need to double most of the values sent in (MUCH FASTER!)
|
||||||
for value in double_numbers_generator(xrange(1000000)): # `test_generator`
|
for value in double_numbers_generator(xrange(1000000)): # `test_generator`
|
||||||
print value
|
print value
|
||||||
if value > 5:
|
if value > 5:
|
||||||
break
|
break
|
||||||
|
|
||||||
# BTW: did you notice the use of `range` in `test_non_generator` and `xrange` in `test_generator`?
|
# BTW: did you notice the use of `range` in `test_non_generator` and `xrange` in `test_generator`?
|
||||||
# Just as `double_numbers_generator` is the generator version of `double_numbers`
|
# Just as `double_numbers_generator` is the generator version of `double_numbers`
|
||||||
# We have `xrange` as the generator version of `range`
|
# We have `xrange` as the generator version of `range`
|
||||||
# `range` would return back and array with 1000000 values for us to use
|
# `range` would return back and array with 1000000 values for us to use
|
||||||
# `xrange` would generate 1000000 values for us as we request / iterate over those items
|
# `xrange` would generate 1000000 values for us as we request / iterate over those items
|
||||||
|
|
||||||
|
# Just as you can create a list comprehension, you can create generator
|
||||||
|
# comprehensions as well.
|
||||||
|
values = (-x for x in [1,2,3,4,5])
|
||||||
|
for x in values:
|
||||||
|
print(x) # prints -1 -2 -3 -4 -5 to console/terminal
|
||||||
|
|
||||||
|
# You can also cast a generator comprehension directly to a list.
|
||||||
|
values = (-x for x in [1,2,3,4,5])
|
||||||
|
gen_to_list = list(values)
|
||||||
|
print(gen_to_list) # => [-1, -2, -3, -4, -5]
|
||||||
|
|
||||||
|
|
||||||
# Decorators
|
# Decorators
|
||||||
|
@ -601,6 +601,10 @@ list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7]
|
|||||||
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
|
[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]
|
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
|
||||||
|
|
||||||
|
# You can construct set and dict comprehensions as well.
|
||||||
|
{x for x in 'abcddeef' if x in 'abc'} # => {'d', 'e', 'f'}
|
||||||
|
{x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
## 5. Modules
|
## 5. Modules
|
||||||
@ -816,7 +820,7 @@ if __name__ == '__main__':
|
|||||||
sup.age = 100
|
sup.age = 100
|
||||||
print(sup.age)
|
print(sup.age)
|
||||||
|
|
||||||
# Inherited attribute from 2nd ancestor whose default value was overriden
|
# Inherited attribute from 2nd ancestor whose default value was overridden.
|
||||||
print('Can I fly? ' + str(sup.fly))
|
print('Can I fly? ' + str(sup.fly))
|
||||||
|
|
||||||
|
|
||||||
@ -825,29 +829,35 @@ if __name__ == '__main__':
|
|||||||
## 7. Advanced
|
## 7. Advanced
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
# Generators help you make lazy code
|
# Generators help you make lazy code.
|
||||||
def double_numbers(iterable):
|
def double_numbers(iterable):
|
||||||
for i in iterable:
|
for i in iterable:
|
||||||
yield i + i
|
yield i + i
|
||||||
|
|
||||||
# A generator creates values on the fly.
|
# Generators are memory-efficient because they only load the data needed to
|
||||||
# Instead of generating and returning all values at once it creates one in each
|
# process the next value in the iterable. This allows them to perform
|
||||||
# iteration. This means values bigger than 15 wont be processed in
|
# operations on otherwise prohibitively large value ranges.
|
||||||
# double_numbers.
|
# NOTE: `range` replaces `xrange` in Python 3.
|
||||||
# We use a trailing underscore in variable names when we want to use a name that
|
for i in double_numbers(range(1, 900000000)): # `range` is a generator.
|
||||||
# would normally collide with a python keyword
|
|
||||||
range_ = range(1, 900000000)
|
|
||||||
# will double all numbers until a result >=30 found
|
|
||||||
for i in double_numbers(range_):
|
|
||||||
print(i)
|
print(i)
|
||||||
if i >= 30:
|
if i >= 30:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Just as you can create a list comprehension, you can create generator
|
||||||
|
# comprehensions as well.
|
||||||
|
values = (-x for x in [1,2,3,4,5])
|
||||||
|
for x in values:
|
||||||
|
print(x) # prints -1 -2 -3 -4 -5 to console/terminal
|
||||||
|
|
||||||
|
# You can also cast a generator comprehension directly to a list.
|
||||||
|
values = (-x for x in [1,2,3,4,5])
|
||||||
|
gen_to_list = list(values)
|
||||||
|
print(gen_to_list) # => [-1, -2, -3, -4, -5]
|
||||||
|
|
||||||
|
|
||||||
# Decorators
|
# Decorators
|
||||||
# in this example beg wraps say
|
# In this example `beg` wraps `say`. If say_please is True then it
|
||||||
# Beg will call say. If say_please is True then it will change the returned
|
# will change the returned message.
|
||||||
# message
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user