Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
1e798bb
Add double lbrace token
nineteendo Jun 4, 2024
e104d43
Construct frozenset
nineteendo Jun 4, 2024
6f807cb
Construct dynamic frozensets
nineteendo Jun 4, 2024
366ab41
Add grammar tests
nineteendo Jun 4, 2024
a5aeefe
Document new node
nineteendo Jun 4, 2024
fc48a5c
Fix grammar
nineteendo Jun 4, 2024
e714040
Document `CALL_INTRINSIC_1`
nineteendo Jun 4, 2024
3bbf27f
Test dis
nineteendo Jun 4, 2024
32d83c0
Fix indent in unparsed ast
nineteendo Jun 4, 2024
a130604
Add extra test
nineteendo Jun 4, 2024
f10508f
Test node
nineteendo Jun 4, 2024
0ecfd57
Update stdtypes
nineteendo Jun 4, 2024
63096f4
Build frozenset opcode
nineteendo Jun 5, 2024
0719566
Update expected ops
nineteendo Jun 5, 2024
c433fd3
Mention frozen sets in data structures
nineteendo Jun 5, 2024
c1f07cf
Explain output format
nineteendo Jun 5, 2024
1aebc4c
Clarify `{{}}`
nineteendo Jun 5, 2024
aabe7b8
Document grammar
nineteendo Jun 5, 2024
b8a6142
Fix grammar
nineteendo Jun 5, 2024
c51632b
Revert unneeded change
nineteendo Jun 5, 2024
8f2af14
Add frozen
nineteendo Jun 5, 2024
56057fa
Add to atoms
nineteendo Jun 5, 2024
580eb6a
Rename variable
nineteendo Jun 5, 2024
ee5eac8
Rename variable 2
nineteendo Jun 5, 2024
42093f0
Add note in grammar file
nineteendo Jun 5, 2024
fed894a
Make note shorter
nineteendo Jun 5, 2024
0ad89fc
Add nested test
nineteendo Jun 5, 2024
7373969
Test in dict
nineteendo Jun 5, 2024
c4ba6be
Add grammar for frozenset comprehensions
nineteendo Jun 6, 2024
69336f1
Generate frozenset
nineteendo Jun 6, 2024
81210ef
Update ast
nineteendo Jun 6, 2024
773c03a
Add `test_frozensetcomps`
nineteendo Jun 6, 2024
f7a415f
Fix dict
nineteendo Jun 6, 2024
c856bcd
Test frozenset literals
nineteendo Jun 6, 2024
85f43a9
More grammar tests
nineteendo Jun 6, 2024
0fc4b9e
Group set checks
nineteendo Jun 6, 2024
545efb5
Update docs
nineteendo Jun 6, 2024
e6d4f36
Update dsl parser
nineteendo Jun 6, 2024
212cf7e
versionadded tag
nineteendo Jun 6, 2024
ed33891
Update glossary
nineteendo Jun 6, 2024
94f327c
Add frozen
nineteendo Jun 6, 2024
b499324
Add frozen
nineteendo Jun 6, 2024
a14b1ad
Add frozen 3
nineteendo Jun 6, 2024
4be42ab
Merge branch 'main' into frozenset-literals
nineteendo Jun 6, 2024
0efd3c6
Allow `ast.literal_eval('frozenset()')`
nineteendo Jun 6, 2024
f4c1664
More tests
nineteendo Jun 6, 2024
e60cafe
test frozenset comprehension
nineteendo Jun 6, 2024
7b2a939
test named expressions
nineteendo Jun 6, 2024
b600f39
test compile
nineteendo Jun 6, 2024
1c32457
test stack size
nineteendo Jun 6, 2024
a21237f
Group tests
nineteendo Jun 6, 2024
65fae0b
Group frozen set code 2
nineteendo Jun 6, 2024
fa306f5
Split up list
nineteendo Jun 6, 2024
ab4bb5f
Remove repeated word
nineteendo Jun 6, 2024
f2e2dc5
Add missing word
nineteendo Jun 6, 2024
052e8d3
Update generated results
nineteendo Jun 6, 2024
a56dd37
Fix tokenize
nineteendo Jun 6, 2024
4a5e543
frozenset in fstring
nineteendo Jun 6, 2024
b1a048e
Fix frozenset in fstring
nineteendo Jun 6, 2024
b362265
Add extra test
nineteendo Jun 6, 2024
594c524
Add todo notes
nineteendo Jun 6, 2024
399ce4f
Only use space for comparisions when necessary
nineteendo Jun 6, 2024
6ed9eaf
Only use space for literals when necessary
nineteendo Jun 6, 2024
4413a4e
Remove unneeded space
nineteendo Jun 6, 2024
08885af
Replace list
nineteendo Jun 6, 2024
db6069e
Remove unneeded space again
nineteendo Jun 6, 2024
f7394d6
made frozenset.__repr__ output in literal format
blhsing Jun 7, 2024
6bc3968
Update setobject.c
blhsing Jun 7, 2024
1cf7ff2
Merge pull request #7 from blhsing/frozenset-literals
nineteendo Jun 7, 2024
a2fb873
Update representation in docs
nineteendo Jun 7, 2024
dee08ff
adding spaces to reprs of dicts and sets with inner frozensets at sta…
blhsing Jun 11, 2024
3ba4cad
Merge pull request #9 from blhsing/frozenset-literals
nineteendo Jun 12, 2024
a840dd4
Fix space
nineteendo Jun 12, 2024
7ad105a
for reprs of dicts and sets, only insert space after ending inner fro…
blhsing Jun 12, 2024
3cadd0b
Merge pull request #10 from blhsing/frozenset-literals
nineteendo Jun 12, 2024
6af7981
Save assignment separately
nineteendo Jun 12, 2024
a07b354
Add more representation tests
nineteendo Jun 12, 2024
534d418
Fix test name
nineteendo Jun 12, 2024
a97267b
Test with set of frozensets
nineteendo Jun 12, 2024
6cff396
Test with set of frozensets
nineteendo Jun 12, 2024
2e9d223
Make symmetric
nineteendo Jun 12, 2024
cf09b14
Use list for items
nineteendo Jun 12, 2024
f8cd830
Document frozensets in dicts and sets
nineteendo Jun 12, 2024
47e042a
Add empty line
nineteendo Jun 12, 2024
dd2a13b
Add example with comprehension
nineteendo Jun 12, 2024
488b614
Handle brackets in frozenset subclasses
nineteendo Jun 12, 2024
65ac5a0
Fix subclass formatting
nineteendo Jun 12, 2024
6b5d9c4
Allign
nineteendo Jun 12, 2024
ad67234
Add more tests
nineteendo Jun 12, 2024
1ef5255
Use frozenset in subclass representation
nineteendo Jun 12, 2024
e7e6601
Use new syntax in stdlib
nineteendo Jun 12, 2024
ae28aff
Use frozenset literals in misc files
nineteendo Jun 12, 2024
c97028b
Revert "Use frozenset literals in misc files"
nineteendo Jun 12, 2024
2097356
Merge branch 'main' into frozenset-literals
nineteendo Jun 12, 2024
bf83dff
Git fix blurb
nineteendo Apr 12, 2025
1994fc9
Empty sets
nineteendo Apr 14, 2025
4ef3b62
Test grammar
nineteendo Apr 14, 2025
0cc9de9
Update repr
nineteendo Apr 14, 2025
6568bd8
Remove trailing whitespace
nineteendo Apr 14, 2025
86d2592
Invalid comprehensions
nineteendo Apr 14, 2025
032b6b4
Remove double l-brace
nineteendo Apr 14, 2025
61e8cc6
Simplify repr
nineteendo Apr 14, 2025
f3f8590
Decrease reference count
nineteendo Apr 14, 2025
253fc29
Reduce diff
nineteendo Apr 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Doc/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,12 @@ Glossary
c not in 'abc'}`` generates the set of strings ``{'r', 'd'}``. See
:ref:`comprehensions`.

frozen set comprehension
A compact way to process all or part of the elements in an iterable and
return a frozen set with the results. ``results = {{c for c in 'abracadabra'
if c not in 'abc'}}`` generates the frozen set of strings ``{{'r', 'd'}}``.
See :ref:`comprehensions`.

single dispatch
A form of :term:`generic function` dispatch where the implementation is
chosen based on the type of a single argument.
Expand Down
41 changes: 38 additions & 3 deletions Doc/library/ast.rst
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,21 @@ Literals
Constant(value=2),
Constant(value=3)]))

.. class:: FrozenSet(elts)

A frozen set. ``elts`` holds a list of nodes representing the frozen set's elements.

.. doctest::

>>> print(ast.dump(ast.parse('{{1, 2, 3}}', mode='eval'), indent=4))
Expression(
body=FrozenSet(
elts=[
Constant(value=1),
Constant(value=2),
Constant(value=3)]))

.. versionadded:: 3.14

.. class:: Dict(keys, values)

Expand Down Expand Up @@ -723,12 +738,14 @@ Comprehensions

.. class:: ListComp(elt, generators)
SetComp(elt, generators)
FrozenSetComp(elt, generators)
GeneratorExp(elt, generators)
DictComp(key, value, generators)

List and set comprehensions, generator expressions, and dictionary
comprehensions. ``elt`` (or ``key`` and ``value``) is a single node
representing the part that will be evaluated for each item.
List and (frozen) set comprehensions, generator expressions, and
dictionary comprehensions. ``elt`` (or ``key`` and ``value``) is
a single node representing the part that will be evaluated for
each item.

``generators`` is a list of :class:`comprehension` nodes.

Expand Down Expand Up @@ -774,6 +791,21 @@ Comprehensions
target=Name(id='x', ctx=Store()),
iter=Name(id='numbers', ctx=Load()),
is_async=0)]))
>>> print(ast.dump(
... ast.parse('{{x for x in numbers}}', mode='eval'),
... indent=4,
... ))
Expression(
body=FrozenSetComp(
elt=Name(id='x', ctx=Load()),
generators=[
comprehension(
target=Name(id='x', ctx=Store()),
iter=Name(id='numbers', ctx=Load()),
is_async=0)]))

.. versionadded:: 3.14
``FrozenSetComp``


.. class:: comprehension(target, iter, ifs, is_async)
Expand Down Expand Up @@ -2233,6 +2265,9 @@ and classes for traversing abstract syntax trees:
.. versionchanged:: 3.10
For string inputs, leading spaces and tabs are now stripped.

.. versionchanged:: 3.14
Now supports creating empty frozen sets with ``'frozenset()'``.


.. function:: get_docstring(node, clean=True)

Expand Down
11 changes: 9 additions & 2 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ not have to be) the original ``STACK[-2]``.
item = STACK.pop()
set.add(STACK[-i], item)

Used to implement set comprehensions.
Used to implement (frozen) set comprehensions.


.. opcode:: LIST_APPEND (i)
Expand Down Expand Up @@ -1120,6 +1120,13 @@ iterations of the loop.
Works as :opcode:`BUILD_TUPLE`, but creates a set.


.. opcode:: BUILD_FROZENSET (count)

Works as :opcode:`BUILD_TUPLE`, but creates a frozen set.

.. versionadded:: 3.14


.. opcode:: BUILD_MAP (count)

Pushes a new dictionary object onto the stack. Pops ``2 * count`` items
Expand Down Expand Up @@ -1167,7 +1174,7 @@ iterations of the loop.
seq = STACK.pop()
set.update(STACK[-i], seq)

Used to build sets.
Used to build (frozen) sets.

.. versionadded:: 3.9

Expand Down
20 changes: 15 additions & 5 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ objects considered false:
* zero of any numeric type: ``0``, ``0.0``, ``0j``, ``Decimal(0)``,
``Fraction(0, 1)``

* empty sequences and collections: ``''``, ``()``, ``[]``, ``{}``, ``set()``,
``range(0)``
* empty sequences and collections: ``''``, ``()``, ``[]``, ``{}``, ``{/}``,
``{{/}}``, ``range(0)``

.. index::
pair: operator; or
Expand Down Expand Up @@ -4247,9 +4247,10 @@ another set. The :class:`frozenset` type is immutable and :term:`hashable` ---
its contents cannot be altered after it is created; it can therefore be used as
a dictionary key or as an element of another set.

Non-empty sets (not frozensets) can be created by placing a comma-separated list
of elements within braces, for example: ``{'jack', 'sjoerd'}``, in addition to the
:class:`set` constructor.
Non-empty sets can be created by placing a comma-separated list of elements
within braces (or double braces for frozen sets), for example: ``{'jack', 'sjoerd'}``
and ``{{'jack', 'sjoerd'}}`` in addition to the :class:`set` and :class:`frozenset`
constructors.

The constructors for both classes work the same:

Expand All @@ -4264,10 +4265,19 @@ The constructors for both classes work the same:

Sets can be created by several means:

* Use a slash within braces for an empty set: ``{/}``
* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``

You can do the same for frozen sets:

* Use a slash within double braces for an empty set: ``{{/}}``
* Use a comma-separated list of elements within double braces: ``{{'jack', 'sjoerd'}}``
* Use a frozen set comprehension: ``{{c for c in 'abracadabra' if c not in 'abc'}}``
* Use the type constructor: ``frozenset()``, ``frozenset('foobar')``,
``frozenset(['a', 'b', 'foo'])``

Instances of :class:`set` and :class:`frozenset` provide the following
operations:

Expand Down
48 changes: 38 additions & 10 deletions Doc/reference/expressions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ also categorized syntactically as atoms. The syntax for atoms is:
.. productionlist:: python-grammar
atom: `identifier` | `literal` | `enclosure`
enclosure: `parenth_form` | `list_display` | `dict_display` | `set_display`
: | `generator_expression` | `yield_atom`
: | `frozenset_display` | `generator_expression` | `yield_atom`


.. _atom-identifiers:
Expand Down Expand Up @@ -161,13 +161,13 @@ ambiguities and allow common typos to pass uncaught.

.. _comprehensions:

Displays for lists, sets and dictionaries
-----------------------------------------
Displays for lists, (frozen) sets and dictionaries
--------------------------------------------------

.. index:: single: comprehensions

For constructing a list, a set or a dictionary Python provides special syntax
called "displays", each of them in two flavors:
For constructing a list, a (frozen) set or a dictionary Python provides special
syntax called "displays", each of them in two flavors:

* either the container contents are listed explicitly, or

Expand Down Expand Up @@ -278,16 +278,44 @@ A set display is denoted by curly braces and distinguishable from dictionary
displays by the lack of colons separating keys and values:

.. productionlist:: python-grammar
set_display: "{" (`starred_list` | `comprehension`) "}"
set_display: "{" (`starred_list` | "/" | `comprehension`) "}"

A set display yields a new mutable set object, the contents being specified by
either a sequence of expressions or a comprehension. When a comma-separated
list of expressions is supplied, its elements are evaluated from left to right
and added to the set object. When a comprehension is supplied, the set is
constructed from the elements resulting from the comprehension.

An empty set cannot be constructed with ``{}``; this literal constructs an empty
dictionary.
An empty set is constructed with ``{/}``, not ``{}``; the latter constructs an
empty dictionary.


.. _frozenset:

Frozen set displays
-------------------

.. index::
pair: frozenset; display
pair: frozenset; comprehensions
pair: object; frozenset
single: {{}} (double curly brackets); frozenset expression
single: , (comma); expression list

A frozen set display is denoted by double curly braces:

.. productionlist:: python-grammar
frozenset_display: "{{" (`starred_list` | "/" | `comprehension`) "}}"

A frozen set display yields a new immutable set object, the contents being
specified by either a sequence of expressions or a comprehension. When a
comma-separated list of expressions is supplied, its elements are evaluated
from left to right and added to the frozenset object. When a comprehension
is supplied, the frozen set is constructed from the elements resulting from
the comprehension.

An empty frozen set is constructed with ``{{/}}``, not ``{{}}``; the latter is
reserved for an empty frozen dictionary.


.. _dict:
Expand Down Expand Up @@ -333,8 +361,8 @@ earlier dict items and earlier dictionary unpackings.
.. versionadded:: 3.5
Unpacking into dictionary displays, originally proposed by :pep:`448`.

A dict comprehension, in contrast to list and set comprehensions, needs two
expressions separated with a colon followed by the usual "for" and "if" clauses.
A dict comprehension, in contrast to list and (frozen) set comprehensions, needs
two expressions separated with a colon followed by the usual "for" and "if" clauses.
When the comprehension is run, the resulting key and value elements are inserted
in the new dictionary in the order they are produced.

Expand Down
22 changes: 21 additions & 1 deletion Doc/tutorial/datastructures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ eliminating duplicate entries. Set objects also support mathematical operations
like union, intersection, difference, and symmetric difference.

Curly braces or the :func:`set` function can be used to create sets. Note: to
create an empty set you have to use ``set()``, not ``{}``; the latter creates an
create an empty set you have to use ``{/}``, not ``{}``; the latter creates an
empty dictionary, a data structure that we discuss in the next section.

Here is a brief demonstration::
Expand Down Expand Up @@ -486,6 +486,26 @@ are also supported::
>>> a
{'r', 'd'}

Frozen sets
-----------

Frozen sets are :term:`immutable` sets and can be used for constants. Double
curly braces or the :func:`frozenset` function can be used to create them::

>>> {{1, 2, 3}}
{{1, 2, 3}}
>>> frozenset('foobar')
{{'f', 'r', 'a', 'b', 'o'}}

.. note::
To create an empty frozen set you have to use ``{{/}}``, not ``{{}}``; the
latter is reserved for an empty frozen dictionary.

Like sets, comprehensions are also supported::

>>> a = {{x for x in 'abracadabra' if x not in 'abc'}}
>>> a
{{'r', 'd'}}

.. _tut-dictionaries:

Expand Down
23 changes: 19 additions & 4 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,7 @@ atom[expr_ty]:
| NUMBER
| &'(' (tuple | group | genexp)
| &'[' (list | listcomp)
| &('{' '{') !invalid_frozenset (frozenset | frozensetcomp)
| &'{' (dict | set | dictcomp | setcomp)
| '...' { _PyAST_Constant(Py_Ellipsis, NULL, EXTRA) }

Expand Down Expand Up @@ -937,7 +938,17 @@ tuple[expr_ty]:
| '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {
_PyAST_Tuple(a, Load, EXTRA) }

set[expr_ty]: '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) }
set[expr_ty]:
| '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) }
| '{' '/' '}' { _PyAST_Set(NULL, EXTRA) }

frozenset[expr_ty]:
| '{' '{' a=star_named_expressions '}' '}' { _PyAST_FrozenSet(a, EXTRA) }
| '{' '{' '/' '}' '}' { _PyAST_FrozenSet(NULL, EXTRA) }

invalid_frozenset:
| '{' '{' ~ invalid_frozenset '}' '}'
| (dict | set | dictcomp | setcomp)

# Dicts
# -----
Expand Down Expand Up @@ -980,6 +991,10 @@ setcomp[expr_ty]:
| '{' a=named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) }
| invalid_comprehension

frozensetcomp[expr_ty]:
| '{' '{' a=named_expression b=for_if_clauses '}' '}' { _PyAST_FrozenSetComp(a, b, EXTRA) }
| invalid_comprehension

genexp[expr_ty]:
| '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
| invalid_comprehension
Expand Down Expand Up @@ -1227,12 +1242,12 @@ invalid_del_stmt:
invalid_block:
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
invalid_comprehension:
| ('[' | '(' | '{') a=starred_expression for_if_clauses {
| ('[' | '(' | '{' | '{' '{') a=starred_expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable unpacking cannot be used in comprehension") }
| ('[' | '{') a=star_named_expression ',' b=star_named_expressions for_if_clauses {
| ('[' | '{' | '{' '{') a=star_named_expression ',' b=star_named_expressions for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, PyPegen_last_item(b, expr_ty),
"did you forget parentheses around the comprehension target?") }
| ('[' | '{') a=star_named_expression b=',' for_if_clauses {
| ('[' | '{' | '{' '{') a=star_named_expression b=',' for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "did you forget parentheses around the comprehension target?") }
invalid_dict_comprehension:
| '{' a='**' bitwise_or for_if_clauses '}' {
Expand Down
27 changes: 21 additions & 6 deletions Include/internal/pycore_ast.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading