Optional arguments in a class behave like class attributes.

Antoon Pardon antoon.pardon at vub.be
Mon Oct 17 14:13:40 EDT 2022


You can use the following decorator for what you probably want.

def copy_defaults(func):
     """
     This decorator makes that defaults values are copied on a call.
     """

     signature = inspect.signature(func)
     parameter_items = list(signature.parameters.items())

     @wraps(func)
     def wrapper(*args, **kwds):
         newargs = list(args)
         tail_parameters = parameter_items[len(args):]
         for name, parameter in tail_parameters:
             try:
                 newargs.append(kwds[name])
                 del kwds[name]
             except KeyError:
                 if parameter.default is not Parameter.empty:
                     newargs.append(copy.deepcopy(parameter.default))
                 else:
                     break
         return func(*newargs, **kwds)

     return wrapper

class GameOne:
   @copy_defaults
   def __init__(self, games = []) -> None:
     self.games = games

# Results I got after using this decorator in your code

Using a list []
Using a dictionary {}
Using an object []

Op 16/10/2022 om 12:48 schreef Abderrahim Adrabi:
> Hi all,
>
> I tried to create a class with some optional arguments as always, but this
> time I used the default values to be lists, dictionaries, and object
> references.
>
> So, these default values behave like class attributes, here is a demo:
>
> # Using a list -----------------------------
> class GameOne:
>    def __init__(self, games = []) -> None:
>      self.games = games
>
> h = GameOne()
> h.games.append("List, the first round")
>
> g = GameOne()
> g.games.append("List, the second round")
>
> k = GameOne()
> print('Using a list', k.games)
>
> # Using a dictionary --------------------------
> class GameTwo:
>    def __init__(self, games = {}) -> None:
>      self.games = games
>
> h = GameTwo()
> h.games['1er'] = "Dictionary, the first round"
>
> g = GameTwo()
> g.games['2ed'] = "Dictionary, the second round"
>
> k = GameTwo()
> print('Using a dictionary', k.games)
>
> # Using an object ------------------------------
> class Bonus:
>    def __init__(self) -> None:
>      self.stages = []
>
> class GameThree:
>    def __init__(self, bonus = Bonus()) -> None:
>      self.bonus = bonus
>
> h = GameThree()
> h.bonus.stages.append('Object, the first round')
>
> g = GameThree()
> g.bonus.stages.append('Object, the second round')
>
> k = GameThree()
> print('Using an object', k.bonus.stages)
>
> # Results ----------------------------------------
>
> Using a list ['List, the first round', 'List, the second round']
> Using a dictionary {'1er': 'Dictionary, the first round', '2ed':
> 'Dictionary, the second round'}
> Using an object ['Object, the first round', 'Object, the second round']
>
> # Used Python versions ---------------------------
>
> 3.5.1 (default, Dec  9 2015, 14:41:32)
> [GCC 5.2.0]
>
> 3.7.14 (default, Sep  8 2022, 00:06:44)
> [GCC 7.5.0]
>
> 3.8.6 (default, Jan 29 2021, 17:38:16)
> [GCC 8.4.1 20200928 (Red Hat 8.4.1-1)]
>
> 3.9.9 (main, Nov 20 2021, 21:30:06)
> [GCC 11.1.0]
>
> My question: Is this normal behavior?
>
> Thanks.


More information about the Python-list mailing list