Question: Suppose I have a class with a constructor (or other function) that takes a variable number of arguments and then sets them as class attributes conditionally.

I could set them manually, but it seems that variable parameters are common enough in python that there should be a common idiom for doing this. But I'm not sure how to do this dynamically.

I have an example using eval, but that's hardly safe. I want to know the proper way to do this -- maybe with lambda?

```
class Foo:
    def setAllManually(self, a=None, b=None, c=None):
        if a!=None: 
            self.a = a
        if b!=None:
            self.b = b
        if c!=None:
            self.c = c
    def setAllWithEval(self, **kwargs):
        for key in **kwargs:
            if kwargs[param] != None
                eval("self." + key + "=" + kwargs[param])

```

Answer: 
Both the `setattr()` and `__dict__.update()` methods bypass property `@setter` functions. The only way I have found to get this to work is by using `exec()`.

`exec` is considered a security risk, but we're not using it with any old user input, so I can't see why it would be. If you disagree I'd really like to learn why, so please leave a comment. I don't want to be advocating or committing insecure code.

My example is mostly borrowed from previous answers for completeness, but the main difference is the line `exec(f"self.{key} = '{value}'")`

```py
class Foo:
    def __init__(self, **kwargs):
        # Predefine attributes with default values
        self.a = 0
        self.b = 0
        self.name = " "

        # get a list of all predefined attributes
        allowed_keys = [attr for attr in dir(self) if not attr.startswith("_")]
        for key, value in kwargs.items():
            # Update properties, but only for keys that have been predefined 
            # (silently ignore others)
            if key in allowed_keys:
                exec(f"self.{key} = '{value}'")

    @property
    def name(self):
        return f"{self.firstname} {self.lastname}"

    @name.setter
    def name(self, name):
        self.firstname, self.lastname = name.split(" ", 2)

```
I suspect it might be better in most instances to use named args (for better self documenting code) so it might look something like this:

```
class Foo:
    def setAll(a=None, b=None, c=None):
        for key, value in (a, b, c):
            if (value != None):
                settattr(self, key, value)

```