From ddc2c5a7239982d6e431ef81c4b1f8e664cf4939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=A0orn?= Date: Fri, 4 Oct 2024 18:41:43 +0200 Subject: [PATCH] Bump to 3.9. Datetime, Decorator, Match statement --- README.md | 37 ++++++++++++++++++------------------- index.html | 42 ++++++++++++++++++++---------------------- parse.js | 10 +++++----- web/faq.html | 4 ++-- 4 files changed, 45 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 867c839..3c38a34 100644 --- a/README.md +++ b/README.md @@ -590,7 +590,7 @@ Datetime ```python # $ pip3 install python-dateutil from datetime import date, time, datetime, timedelta, timezone -from dateutil.tz import tzlocal, gettz +import zoneinfo, dateutil.tz ``` ```python @@ -601,7 +601,7 @@ from dateutil.tz import tzlocal, gettz ``` * **Aware `` time and datetime objects have defined timezone, while naive `` don't. If object is naive, it is presumed to be in the system's timezone!** * **`'fold=1'` means the second pass in case of time jumping back for one hour.** -* **Timedelta normalizes arguments to ±days, seconds (< 86 400) and microseconds (< 1M).** +* **Timedelta normalizes arguments to ±days, seconds (< 86 400) and microseconds (< 1M). Its str() method returns `'[±D, ]H:MM:SS[.…]'` and total_seconds() a float of all seconds.** * **Use `'.weekday()'` to get the day of the week as an int, with Monday being 0.** ### Now @@ -615,13 +615,13 @@ from dateutil.tz import tzlocal, gettz ```python = timezone.utc # London without daylight saving time (DST). = timezone() # Timezone with fixed offset from UTC. - = tzlocal() # Local tz with dynamic offset. Also gettz(). - = gettz('/') # 'Continent/City_Name' timezone or None. + = dateutil.tz.tzlocal() # Local timezone with dynamic offset from UTC. + = zoneinfo.ZoneInfo('') # 'Continent/City_Name' zone with dynamic offset. =
.astimezone([]) # Converts DT to the passed or local fixed zone. = .replace(tzinfo=) # Changes object's timezone without conversion. ``` -* **Timezones returned by tzlocal(), gettz(), and implicit local timezone of naive objects have offsets that vary through time due to DST and historical changes of the zone's base offset.** -* **Standard library's zoneinfo.ZoneInfo() can be used instead of gettz() on Python 3.9 and later. It requires 'tzdata' package on Windows. It doesn't return local tz if arg. is omitted.** +* **Timezones returned by tzlocal(), ZoneInfo() and implicit local timezone of naive objects have offsets that vary through time due to DST and historical changes of the base offset.** +* **To get zoneinfo module to work on Windows run `'> pip3 install tzdata'`.** ### Encode ```python @@ -660,7 +660,7 @@ from dateutil.tz import tzlocal, gettz = - # Ignores jumps if they share tzinfo object. = ± # Returned datetime can fall into missing hour. = * # Also: = abs() and = ±% . - = / # How many hours/weeks/years are in TD. Also //. + = / # E.g. how many hours are in timedelta. Also //. ``` @@ -739,7 +739,7 @@ def f(x, y, *, z): ... # f(x=1, y=2, z=3) | f(1, y=2, z=3) | f(1, 2, z= = [* [, ...]] # Or: list() [+ ...] = (*, [...]) # Or: tuple() [+ ...] = {* [, ...]} # Or: set() [| ...] - = {** [, ...]} # Or: | ... (since 3.9) + = {** [, ...]} # Or: | ... ``` ```python @@ -913,21 +913,20 @@ def debug(func): def add(x, y): return x + y ``` -* **Wraps is a helper decorator that copies the metadata of the passed function (func) to the function it is wrapping (out).** -* **Without it, `'add.__name__'` would return `'out'`.** +* **Wraps is a helper decorator that copies the metadata of the passed function (func) to the function it is wrapping (out). Without it, `'add.__name__'` would return `'out'`.** -### LRU Cache +### Cache **Decorator that caches function's return values. All function's arguments must be hashable.** ```python -from functools import lru_cache +from functools import cache -@lru_cache(maxsize=None) +@cache def fib(n): return n if n < 2 else fib(n-2) + fib(n-1) ``` -* **Default size of the cache is 128 values. Passing `'maxsize=None'` makes it unbounded.** -* **CPython interpreter limits recursion depth to 3000 by default. To increase it use `'sys.setrecursionlimit()'`.** +* **Potential problem with cache is that it can grow indefinitely. To clear the cache run `'fib.cache_clear()'` or use `'@functools.lru_cache(maxsize=)'` instead.** +* **CPython interpreter limits recursion depth to 3000 by default. To increase it run `'sys.setrecursionlimit()'`.** ### Parametrized Decorator **A decorator that accepts arguments and returns a normal decorator that accepts a function.** @@ -1253,7 +1252,7 @@ True ### Collection * **Only required methods are iter() and len(). Len() should return the number of items.** * **This cheatsheet actually means `''` when it uses `''`.** -* **I chose not to use the name 'iterable' because it sounds scarier and more vague than 'collection'. The only drawback of this decision is that the reader could think a certain function doesn't accept iterators when it does, since iterators are the only built-in objects that are iterable but are not collections.** +* **I chose not to use the name 'iterable' because it sounds scarier and more vague than 'collection'. The main drawback of this decision is that the reader could think a certain function doesn't accept iterators when it does, since iterators are the only built-in objects that are iterable but are not collections.** ```python class MyCollection: def __init__(self, a): @@ -2201,8 +2200,8 @@ match : ### Patterns ```python = 1/'abc'/True/None/math.pi # Matches the literal or a dotted name. - = () # Matches any object of that type. - = _ # Matches any object. + = () # Matches any object of that type (or ABC). + = _ # Matches any object. Useful in last case. = # Matches any object and binds it to name. = as # Binds match to name. Also (). = | [| ...] # Matches any of the patterns. @@ -2212,7 +2211,7 @@ match : ``` * **Sequence pattern can also be written as a tuple.** * **Use `'*'` and `'**'` in sequence/mapping patterns to bind remaining items.** -* **Sequence pattern must match all items, while mapping pattern does not.** +* **Sequence pattern must match all items of the collection, while mapping pattern does not.** * **Patterns can be surrounded with brackets to override precedence (`'|'` > `'as'` > `','`).** * **Built-in types allow a single positional pattern that is matched against the entire object.** * **All names that are bound in the matching case, as well as variables initialized in its block, are visible after the match statement.** diff --git a/index.html b/index.html index 408be5b..afcff5b 100644 --- a/index.html +++ b/index.html @@ -54,7 +54,7 @@
- +
@@ -515,7 +515,7 @@ Point(x=1, y=2

#Datetime

Provides 'date', 'time', 'datetime' and 'timedelta' classes. All are immutable and hashable.

# $ pip3 install python-dateutil
 from datetime import date, time, datetime, timedelta, timezone
-from dateutil.tz import tzlocal, gettz
+import zoneinfo, dateutil.tz
 
@@ -527,7 +527,7 @@ Point(x=1, y=2
  • Aware <a> time and datetime objects have defined timezone, while naive <n> don't. If object is naive, it is presumed to be in the system's timezone!
  • 'fold=1' means the second pass in case of time jumping back for one hour.
  • -
  • Timedelta normalizes arguments to ±days, seconds (< 86 400) and microseconds (< 1M).
  • +
  • Timedelta normalizes arguments to ±days, seconds (< 86 400) and microseconds (< 1M). Its str() method returns '[±D, ]H:MM:SS[.…]' and total_seconds() a float of all seconds.
  • Use '<D/DT>.weekday()' to get the day of the week as an int, with Monday being 0.

Now

<D/DTn> = D/DT.today()                      # Current local date or naive DT. Also DT.now().
@@ -539,15 +539,15 @@ Point(x=1, y=2
 
 

Timezone

<tzinfo> = timezone.utc                     # London without daylight saving time (DST).
 <tzinfo> = timezone(<timedelta>)            # Timezone with fixed offset from UTC.
-<tzinfo> = tzlocal()                        # Local tz with dynamic offset. Also gettz().
-<tzinfo> = gettz('<Continent>/<City>')      # 'Continent/City_Name' timezone or None.
+<tzinfo> = dateutil.tz.tzlocal()            # Local timezone with dynamic offset from UTC.
+<tzinfo> = zoneinfo.ZoneInfo('<iana_key>')  # 'Continent/City_Name' zone with dynamic offset.
 <DTa>    = <DT>.astimezone([<tzinfo>])      # Converts DT to the passed or local fixed zone.
 <Ta/DTa> = <T/DT>.replace(tzinfo=<tzinfo>)  # Changes object's timezone without conversion.
 
    -
  • Timezones returned by tzlocal(), gettz(), and implicit local timezone of naive objects have offsets that vary through time due to DST and historical changes of the zone's base offset.
  • -
  • Standard library's zoneinfo.ZoneInfo() can be used instead of gettz() on Python 3.9 and later. It requires 'tzdata' package on Windows. It doesn't return local tz if arg. is omitted.
  • +
  • Timezones returned by tzlocal(), ZoneInfo() and implicit local timezone of naive objects have offsets that vary through time due to DST and historical changes of the base offset.
  • +
  • To get zoneinfo module to work on Windows run '> pip3 install tzdata'.

Encode

<D/T/DT> = D/T/DT.fromisoformat(<str>)      # Object from ISO string. Raises ValueError.
 <DT>     = DT.strptime(<str>, '<format>')   # Datetime from str, according to format.
@@ -582,7 +582,7 @@ Point(x=1, y=2
 <TD>     = <DTa>     - <DTa>                # Ignores jumps if they share tzinfo object.
 <D/DT>   = <D/DT>    ± <TD>                 # Returned datetime can fall into missing hour.
 <TD>     = <TD>      * <float>              # Also: <TD> = abs(<TD>) and <TD> = <TD> ±% <TD>.
-<float>  = <TD>      / <TD>                 # How many hours/weeks/years are in TD. Also //.
+<float>  = <TD>      / <TD>                 # E.g. how many hours are in timedelta. Also //.
 

#Arguments

Inside Function Call

func(<positional_args>)                           # func(0, 0)
@@ -637,7 +637,7 @@ func(*args, **kwargs)
 

Other Uses

<list>  = [*<coll.> [, ...]]    # Or: list(<collection>) [+ ...]
 <tuple> = (*<coll.>, [...])     # Or: tuple(<collection>) [+ ...]
 <set>   = {*<coll.> [, ...]}    # Or: set(<collection>) [| ...]
-<dict>  = {**<dict> [, ...]}    # Or: <dict> | ... (since 3.9)
+<dict>  = {**<dict> [, ...]}    # Or: <dict> | ...
 
head, *body, tail = <coll.>     # Head or tail can be omitted.
@@ -766,20 +766,18 @@ player = Player(point, direction)                   #
 
 
 
    -
  • Wraps is a helper decorator that copies the metadata of the passed function (func) to the function it is wrapping (out).
  • -
  • Without it, 'add.__name__' would return 'out'.
  • +
  • Wraps is a helper decorator that copies the metadata of the passed function (func) to the function it is wrapping (out). Without it, 'add.__name__' would return 'out'.
-

LRU Cache

Decorator that caches function's return values. All function's arguments must be hashable.

from functools import lru_cache
+

Cache

Decorator that caches function's return values. All function's arguments must be hashable.

from functools import cache
 
-@lru_cache(maxsize=None)
+@cache
 def fib(n):
-    return n if n < 2 else fib(n-2) + fib(n-1)
-
+ return n if n < 2 else fib(n-2) + fib(n-1)
    -
  • Default size of the cache is 128 values. Passing 'maxsize=None' makes it unbounded.
  • -
  • CPython interpreter limits recursion depth to 3000 by default. To increase it use 'sys.setrecursionlimit(<int>)'.
  • +
  • Potential problem with cache is that it can grow indefinitely. To clear the cache run 'fib.cache_clear()' or use '@functools.lru_cache(maxsize=<int>)' instead.
  • +
  • CPython interpreter limits recursion depth to 3000 by default. To increase it run 'sys.setrecursionlimit(<int>)'.

Parametrized Decorator

A decorator that accepts arguments and returns a normal decorator that accepts a function.

from functools import wraps
 
@@ -1063,7 +1061,7 @@ Hello World!
 

Collection

  • Only required methods are iter() and len(). Len() should return the number of items.
  • This cheatsheet actually means '<iterable>' when it uses '<collection>'.
  • -
  • I chose not to use the name 'iterable' because it sounds scarier and more vague than 'collection'. The only drawback of this decision is that the reader could think a certain function doesn't accept iterators when it does, since iterators are the only built-in objects that are iterable but are not collections.
  • +
  • I chose not to use the name 'iterable' because it sounds scarier and more vague than 'collection'. The main drawback of this decision is that the reader could think a certain function doesn't accept iterators when it does, since iterators are the only built-in objects that are iterable but are not collections.
class MyCollection:
     def __init__(self, a):
         self.a = a
@@ -1805,8 +1803,8 @@ first_element    = op.methodcaller('pop', 

Patterns

<value_pattern> = 1/'abc'/True/None/math.pi        # Matches the literal or a dotted name.
-<class_pattern> = <type>()                         # Matches any object of that type.
-<wildcard_patt> = _                                # Matches any object.
+<class_pattern> = <type>()                         # Matches any object of that type (or ABC).
+<wildcard_patt> = _                                # Matches any object. Useful in last case.
 <capture_patt>  = <name>                           # Matches any object and binds it to name.
 <as_pattern>    = <pattern> as <name>              # Binds match to name. Also <type>(<name>).
 <or_pattern>    = <pattern> | <pattern> [| ...]    # Matches any of the patterns.
@@ -1818,7 +1816,7 @@ first_element    = op.methodcaller('pop', 
 
  • Sequence pattern can also be written as a tuple.
  • Use '*<name>' and '**<name>' in sequence/mapping patterns to bind remaining items.
  • -
  • Sequence pattern must match all items, while mapping pattern does not.
  • +
  • Sequence pattern must match all items of the collection, while mapping pattern does not.
  • Patterns can be surrounded with brackets to override precedence ('|' > 'as' > ',').
  • Built-in types allow a single positional pattern that is matched against the entire object.
  • All names that are bound in the matching case, as well as variables initialized in its block, are visible after the match statement.
  • @@ -2931,7 +2929,7 @@ $ deactivate # Deactivates the active diff --git a/parse.js b/parse.js index ef23fb1..593e648 100755 --- a/parse.js +++ b/parse.js @@ -50,12 +50,12 @@ const BIN_HEX = '<int> = int(\'±0b<bin>\', 0) # Or: int(\'±0x<hex>\', 0)\n' + '<str> = bin(<int>) # Returns \'[-]0b<bin>\'. Also hex().\n'; -const LRU_CACHE = - 'from functools import lru_cache\n' + +const CACHE = + 'from functools import cache\n' + '\n' + - '@lru_cache(maxsize=None)\n' + + '@cache\n' + 'def fib(n):\n' + - ' return n if n < 2 else fib(n-2) + fib(n-1)\n'; + ' return n if n < 2 else fib(n-2) + fib(n-1)'; const PARAMETRIZED_DECORATOR = 'from functools import wraps\n' + @@ -838,7 +838,7 @@ function fixClasses() { function fixHighlights() { $(`code:contains( = ±0b)`).html(BIN_HEX); - $(`code:contains(@lru_cache(maxsize=None))`).html(LRU_CACHE); + $(`code:contains(@cache)`).html(CACHE); $(`code:contains(@debug(print_result=True))`).html(PARAMETRIZED_DECORATOR); $(`code:contains(print/str/repr([]))`).html(REPR_USE_CASES); $(`code:contains((self, a=None):)`).html(CONSTRUCTOR_OVERLOADING); diff --git a/web/faq.html b/web/faq.html index 349678c..b1e6752 100644 --- a/web/faq.html +++ b/web/faq.html @@ -1,6 +1,6 @@
    Which Python version is this for?
    -    Everything should work in the latest Python version, which is 3.12. Every feature that requires version higher than 3.8 has that mentioned in comments or brackets. There are only six such features, four requiring 3.9, and two requiring 3.10.

    -    As of 12th March 2024, the only libraries whose latest version requires Python version higher than 3.8 are: numpy, pandas and matplotlib. They all require Python 3.9. This cheatsheet covers pandas library version 2.0 or higher which was released on 3rd April 2023. +    Everything should work in the latest Python version, which is 3.12. Every feature that requires version higher than 3.9 has that mentioned in comments or brackets. There are only two such features, both requiring 3.10.

    +    As of 12th March 2024, the only libraries whose latest version requires Python version higher than 3.8 are: numpy, pandas and matplotlib. They all require Python 3.9. This cheatsheet covers numpy version numpy 2.0 (or higher) that was released on 16th June, 2024 pandas version 2.0 (or higher) that was released on 3rd April 2023.

    How to use it?