title: Create class with properties from config file
body: <p>I am trying to dynamically create a Python class from a configuration file (I use a dictionary in the example for simplicity). The attributes that I create I would like to be set as properties since I have validation functions that I would like to run when the attributes are set.</p>
  <p>I have a code that is sort-of working, but it's having some unexpected results.</p>
  <pre><code>def func(x):
      &quot;&quot;&quot; Example validation function. &quot;&quot;&quot;
      if x &lt; 0:
          raise ValueError
  
      return
  
  
  config = {
      &quot;x&quot;: {
          &quot;type&quot;: int,
          &quot;default&quot;: 0,
          &quot;validate&quot;: func
      },
      &quot;y&quot;: {
          &quot;type&quot;: int,
          &quot;default&quot;: 10,
          &quot;validate&quot;: func
      },
      &quot;z&quot;: {
          &quot;type&quot;: str,
          &quot;default&quot;: &quot;bar&quot;,
          &quot;validate&quot;: None
      }
  }
  
  
  def get_property(prop, validate):
      key = f&quot;_{prop}&quot;
  
      def get_(self):
          return exec(f&quot;self.{key}&quot;)
  
      def set_(self, value):
          if validate is not None:
              validate(value)
          exec(f&quot;self.{key} = value&quot;)
  
      def del_(self):
          exec(f&quot;del self.{key}&quot;)
  
      return property(get_, set_, del_)
  
  
  def get_Foo(**kwargs):
      class Foo:
          def __init__(self, **_kwargs):
              for k_, v_ in _kwargs.items():
                  setattr(self, &quot;_&quot; + k_, None)
  
                  if v_[&quot;type&quot;] == str:
                      exec(f&quot;self.{k_} = '{v_['default']}'&quot;)
                  else:
                      exec(f&quot;self.{k_} = {v_['default']}&quot;)
  
      # Add properties to Foo class
      for k, v in kwargs.items():
          prop_ = get_property(k, v[&quot;validate&quot;])
          setattr(Foo, k, prop_)
  
      # Create Foo class and set defaults
      return Foo(**kwargs)
  
  
  foo = get_Foo(**config)
  </code></pre>
  <p>Now when testing it appears that 'setter' is working, but 'getter' is not and 'deleter' is partially working.</p>
  <pre><code>print(foo.x)  # prints None
  print(foo._x) # prints 0
  foo.x = 10
  print(foo.x)  # prints None (getter not working)
  print(foo._x) # prints 10  (setter works)
  foo.x = -1    # raises error (validator in setter works)
  del foo.x
  print(foo.x)  # AttributeError: 'Foo' object has no attribute '_x' (del sort-of works?)
  </code></pre>
  <p>Could anyone explain the results?</p>