Python 3.15 adds bytearray.take_bytes(n=None) method to convert a bytearray to bytes and clear the bytearray. It has a complexity of O(1). See the related discussion.
Would it make sense to add a similar function to convert a dict to a frozendict and clear the dict? For example, add dict.as_frozendict_and_clear() method. In CPython, it should be possible to implement this method with O(1) complexity which makes it interesting for performance.
For example, there is a function with complex code filling a mutable dict, and then use return frozendict(dict) to return a frozendict. The dict is only used to build the frozendict, then it’s discarded anyway. frozendict(dict) conversion is inefficient since it has to copy all items. The idea would be to replace it with dict.as_frozendict_and_clear() to make it efficient.
If we add such method, it would also be interesting to add a similar list.as_tuple_and_clear() and set.as_frozendset_and_clear() methods. In the internal C API, there is already a _PyList_AsTupleAndClear() function. For example, this code:
def tuple_from_iterable(iterable):
return tuple(list(iterable))
would become:
def tuple_from_iterable(iterable):
return list(iterable).as_tuple_and_clear()
Note: internally, tuple(iterable) is already implemented as list(iterable).as_tuple_and_clear() ![]()
See also the related discussion in the C API: Provide a C-API to efficently convert dict into frozendict.
I implemented these method to run two benchmarks.
Benchmark 1 on dict to frozendict conversion:
Code
import pyperf
LARGE = 10 ** 5
def func1():
large_dict = {str(key): key for key in range(LARGE)}
return frozendict(large_dict)
# discard large_dict
def func2():
large_dict = {str(key): key for key in range(LARGE)}
return large_dict.as_frozendict_and_clear()
# large_dict is empty
runner = pyperf.Runner()
runner.bench_func('frozendict(dict)', func1)
runner.bench_func('as_frozendict_and_clear()', func2)
Result:
frozendict(dict): Mean ± std dev: 27.6 ms ± 2.1 msas_frozendict_and_clear(): Mean ± std dev: 21.5 ms ± 1.6 ms
dict.as_frozendict_and_clear() is 1.28x faster than frozendict(dict).
Benchmark 2 on list to tuple conversion:
Code
import pyperf
def func1():
large_list = list(range(10 ** 6))
return tuple(large_list)
# discard large_list
def func2():
large_list = list(range(10 ** 6))
return large_list.as_tuple_and_clear()
# large_list is empty
runner = pyperf.Runner()
runner.bench_func('tuple(list)', func1)
runner.bench_func('as_tuple_and_clear()', func2)
Result:
tuple(list): Mean ± std dev: 41.0 ms ± 1.9 msas_tuple_and_clear(): Mean ± std dev: 32.1 ms ± 0.3 ms
list.as_tuple_and_clear() is 1.28x faster than tuple(list).
Well, the exact speedup depends on the dict/list size.