Skip to content

Commit b39fe9a

Browse files
List support: copy method (pyccel#1797)
Add support for the `copy()` method of Python lists to the semantic stage and Python codegen. This fixes pyccel#1696. **Commit Summary** - Add a class representation for the `copy()` method, inheriting from `ListMethod`. The constructor copies the attributes of the list object, to the current object that represents the resulting new copy of the list. - Add check for `HomogeneousListType` in `_print_IndexedElement` to support indexing a multidimensional list. - Add success and error tests for the `copy()` method involving many scenarios where the function could be used.
1 parent 9c08d24 commit b39fe9a

File tree

5 files changed

+72
-3
lines changed

5 files changed

+72
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
66
### Added
77
- #1720 : Add support for `Ellipsis` as the only index for an array.
88
- #1694 : Add Python support for list method `extend()`.
9+
- #1696 : Add Python support for list method `copy()`.
910
- #1693 : Add Python support for list method `remove()`.
1011
- #1739 : Add abstract class `SetMethod` to handle calls to various set methods.
1112
- #1739 : Add Python support for set method `clear()`.
@@ -22,6 +23,7 @@ All notable changes to this project will be documented in this file.
2223
- Allow printing the result of a function returning multiple objects of different types.
2324
- #1792 : Fix array unpacking.
2425
- #1795 : Fix bug when returning slices in C.
26+
- #1732 : Fix multidimensional list indexing in Python.
2527

2628
### Changed
2729
- #1720 : functions with the `@inline` decorator are no longer exposed to Python in the shared library.

pyccel/ast/builtin_methods/list_methods.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
__all__ = ('ListAppend',
1717
'ListClear',
18+
'ListCopy',
1819
'ListExtend',
1920
'ListInsert',
2021
'ListMethod',
@@ -270,3 +271,38 @@ def __init__(self, list_obj, removed_obj) -> None:
270271
raise TypeError(f"Can't remove an element of type {removed_obj.class_type} from {list_obj.class_type}")
271272
super().__init__(list_obj, removed_obj)
272273

274+
#==============================================================================
275+
class ListCopy(ListMethod) :
276+
"""
277+
Represents a call to the .copy() method.
278+
279+
Represents a call to the .copy() method which is used to create a shallow
280+
copy of a list, meaning that any modification in the new list will be
281+
reflected in the original list.
282+
The method returns a list.
283+
284+
>>> a = [1, 2, 3, 4]
285+
>>> b = a.copy()
286+
>>> print(a, b)
287+
[1, 2, 3, 4]
288+
[1, 2, 3, 4]
289+
>>> a[0] = 0
290+
>>> a[1] = 0
291+
>>> print(a, b)
292+
[0, 0, 3, 4]
293+
[0, 0, 3, 4]
294+
295+
Parameters
296+
----------
297+
list_obj : TypedAstNode
298+
The list object which the method is called from.
299+
"""
300+
__slots__ = ('_class_type', '_rank', '_shape', '_order')
301+
name = 'copy'
302+
303+
def __init__(self, list_obj) -> None:
304+
self._rank = list_obj.rank
305+
self._shape = list_obj.shape
306+
self._order = list_obj.order
307+
self._class_type = list_obj.class_type
308+
super().__init__(list_obj)

pyccel/ast/class_defs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
from pyccel.ast.builtin_methods.set_methods import SetAdd, SetClear, SetCopy, SetPop, SetRemove
1010
from pyccel.ast.builtin_methods.list_methods import (ListAppend, ListInsert, ListPop,
11-
ListClear, ListExtend, ListRemove)
11+
ListClear, ListExtend, ListRemove,
12+
ListCopy)
1213

1314
from .builtins import PythonImag, PythonReal, PythonConjugate
1415
from .core import ClassDef, PyccelFunctionDef
@@ -142,6 +143,7 @@
142143
methods=[
143144
PyccelFunctionDef('append', func_class = ListAppend),
144145
PyccelFunctionDef('clear', func_class = ListClear),
146+
PyccelFunctionDef('copy', func_class = ListCopy),
145147
PyccelFunctionDef('extend', func_class = ListExtend),
146148
PyccelFunctionDef('insert', func_class = ListInsert),
147149
PyccelFunctionDef('pop', func_class = ListPop),

pyccel/codegen/printing/pycode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pyccel.ast.builtins import PythonComplex, DtypePrecisionToCastFunction
1212
from pyccel.ast.core import CodeBlock, Import, Assign, FunctionCall, For, AsName, FunctionAddress
1313
from pyccel.ast.core import IfSection, FunctionDef, Module, PyccelFunctionDef
14-
from pyccel.ast.datatypes import HomogeneousTupleType
14+
from pyccel.ast.datatypes import HomogeneousTupleType, HomogeneousListType
1515
from pyccel.ast.functionalexpr import FunctionalFor
1616
from pyccel.ast.literals import LiteralTrue, LiteralString
1717
from pyccel.ast.literals import LiteralInteger, LiteralFloat, LiteralComplex
@@ -284,7 +284,7 @@ def _print_IndexedElement(self, expr):
284284
indices = indices[0]
285285

286286
indices = [self._print(i) for i in indices]
287-
if expr.pyccel_staging != 'syntactic' and isinstance(expr.base.class_type, HomogeneousTupleType):
287+
if expr.pyccel_staging != 'syntactic' and isinstance(expr.base.class_type, (HomogeneousTupleType, HomogeneousListType)):
288288
indices = ']['.join(i for i in indices)
289289
else:
290290
indices = ','.join(i for i in indices)

tests/epyccel/test_epyccel_lists.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,35 @@ def test_extend_list_class_attribute(language):
568568
accelerated_list = modnew.fn()
569569
assert python_list == accelerated_list
570570

571+
def test_copy_basic(language):
572+
def f():
573+
a = [1, 2, 3]
574+
b = a.copy()
575+
return b
576+
577+
epyc_f = epyccel(f, language=language)
578+
assert f() == epyc_f()
579+
580+
def test_copy_nested(language):
581+
def f():
582+
a = [[1, 2], [3, 4]]
583+
b = a.copy()
584+
return b
585+
586+
epyc_f = epyccel(f, language=language)
587+
assert f() == epyc_f()
588+
589+
def test_copy_modify_nested_values(language):
590+
def f():
591+
a = [[1, 2], [3, 4]]
592+
b = a.copy()
593+
a[0][0] = 0
594+
a[0][1] = 0
595+
return b
596+
597+
epyc_f = epyccel(f, language=language)
598+
assert f() == epyc_f()
599+
571600
def test_mixed_list_methods(language):
572601
def f():
573602
a = [(1, 4, 5), (33, 12, 5), (3, 5)]

0 commit comments

Comments
 (0)