3

I wonder if there is a better solution to define a new type in python.

I am writing the init method of a new class in this way:

class MyType (Base):

  def __init__(self, **kwargs):
    self.a1 = kwargs['a1']
    self.a2 = kwargs['a2']
    self.a3 = kwargs['a3']

but I would like to write a compact coding style like that:

class MyType (Base):

   __fields__ = ['a1', 'a2', 'a3']

The following solution vars(self).update(kwargs) or self.__dict__.update(**kwargs) does not satisfied me, because the user can enter any dictionary with no error messages. I need to check that the user insert the following signature ('a1', 'a2', 'a3', 'a4', 'a5'). Moreover, the user should be able to use the object by passing the "positional parameters" or the "kay-value pairs parameters".

I implemented the following code which is able to spot KeyError when some parameter is missing. but when extra argument is added I do not get any error:

class Structure:
    _fields = []
    def __init__(self, *args, **kwargs):
        print(self._fields, kwargs)
        for name in self._fields:
            setattr(self, name, kwargs[name])

class MyType (Structure):
    _fields = ['a1', 'a2', 'a3']

if __name__ == '__main__':
    m = MyType(**{'a1': 1}) # KeyError: 'a2'
    print(vars(m))      
    m = MyType(**{'a1': 1, 'a2': 3, 'a3': 4, 'a4': 5}) # no KeyError!!
    print(vars(m))

Thanks, Frederick

  • just do `self.__dict__.update(**kwargs)`. – Mazdak Nov 03 '18 at 09:42
  • 1
    Why don't you just store the `**kwargs` directly in an inner dictionary and access it that way when needed given that you obviously don't care about defining an interface? – zwer Nov 03 '18 at 09:43
  • 1
    @Kasrâmvd, Sorry, but in my previous question, I have not been precise. I updated my question adding details about signature verification. – frederickpy Nov 03 '18 at 21:47
  • @frederickpy you should use the Signature object. https://docs.python.org/3/library/inspect.html#introspecting-callables-with-the-signature-object – antonjs Nov 04 '18 at 09:09
  • 1
    @frederickpy does [this](https://pastebin.com/cTygSeXB) meet your requirements? (will error on trying to set an attribute name not in the slots) – timgeb Nov 04 '18 at 09:19

2 Answers2

3

Have a look at python3.7 data classes.

Quote from there:

@dataclass
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

Will add, among other things, a __init__() that looks like:

def __init__(self, name: str, unit_price: float, quantity_on_hand: int=0):
    self.name = name
    self.unit_price = unit_price
    self.quantity_on_hand = quantity_on_hand
RunOrVeith
  • 4,487
  • 4
  • 32
  • 50
1

You can just update the instance dict in __init__.

>>> class MyType:
...:    def __init__(self, **kwargs):
...:        vars(self).update(kwargs)
...:        
>>> m = MyType(a1=1, a2=2, a3=3)
>>> vars(m)
>>> {'a1': 1, 'a2': 2, 'a3': 3}
>>> m.a1, m.a2, m.a3
>>> (1, 2, 3)
timgeb
  • 76,762
  • 20
  • 123
  • 145