This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Copying functions doesn't actually copy them
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Numerlor, serhiy.storchaka, steven.daprano, vstinner
Priority: normal Keywords:

Created on 2020-03-01 03:42 by steven.daprano, last changed 2022-04-11 14:59 by admin.

Messages (7)
msg363039 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-03-01 03:42
Function objects are mutable, so I expected that a copy of a function should be an actual independent copy. But it isn't.

    py> from copy import copy
    py> a = lambda: 1
    py> b = copy(a)
    py> a is b
    True

This burned me when I modified the copy and the original changed too:

    py> a.attr = 27  # add extra data
    py> b.attr = 42
    py> a.attr
    42


`deepcopy` doesn't copy the function either.
msg363041 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-03-01 04:14
I think this is sufficient for a shallow copy.

import copy
import types

def copyfunction(func):
    new = types.FunctionType(
            func.__code__,
            func.__globals__,
            func.__name__,
            func.__defaults__,
            func.__closure__
            )
    vars(new).update(vars(func))
    new.__annotations__.update(func.__annotations__)
    if func.__kwdefaults__ is not None:
        new.__kwdefaults__ = func.__kwdefaults__.copy()
    return new
msg413163 - (view) Author: Numerlor (Numerlor) * Date: 2022-02-13 03:18
Ran into this myself today; do you have any plans on implementing the proposed change?
msg413178 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2022-02-13 11:51
It is by design. Functions and types are pickled by name. The copy module uses the pickling protocol and only use different methods for performance or for non-pickleable objects. Changing this will break existing code.
msg413180 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2022-02-13 13:26
If we can't change the default behaviour of copying functions, can we 
add a specialised copy_function() function, for when we really need to 
make a genuine copy?
msg413182 - (view) Author: Numerlor (Numerlor) * Date: 2022-02-13 14:21
Having copy be an identity function for anything mutable seems very bug prone, even if it's functions. If not changed in the copy interface I would say that at least a warning would be helpful.
msg416223 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2022-03-28 22:19
See also bpo-47143 "Add functools.copy_class() which updates closures".
History
Date User Action Args
2022-04-11 14:59:27adminsetgithub: 83986
2022-03-28 22:19:55vstinnersetnosy: + vstinner
messages: + msg416223
2022-02-13 14:21:07Numerlorsetmessages: + msg413182
2022-02-13 13:26:50steven.dapranosetmessages: + msg413180
2022-02-13 11:51:08serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg413178
2022-02-13 03:18:15Numerlorsetnosy: + Numerlor
messages: + msg413163
2020-03-01 04:14:36steven.dapranosetmessages: + msg363041
2020-03-01 03:42:42steven.dapranocreate