Home > Software engineering >  Python: code duplication on class attribute definition
Python: code duplication on class attribute definition

Time:03-03

I'm trying to implement a simple ORM in python. I'm facing a code duplication issue and I do not know how to solve it. Here is a simplified example of a class in my project:

class Person:

    TABLE_NAME = 'person'

    FIELDS = [
        ('name', 'VARCHAR(50)'),
        ('age', 'INTEGER')
    ]

    # CODE DUPLICATION: the two next lines shoudl be genereated with FIELDS not hard coded...
    name: str
    age: int

    def __init__(self, **kwargs):
        self.__dict__ = kwargs

    @classmethod
    def create_sql_table(cls):
        # use TABLE_NAME and FIELDS to create sql table
        pass


alice = Person(name='Alice', age=25)

print(alice.name)

If I remove the two lines name: strand age: int I lose auto-completion and I get a mypy error on the print line (Error: Person has no attribute name)

But If I keep it, I have code duplication (I write twice each field name).

Is there a way to avoid the code duplication (by generating this two lines using FIELDS variable for instance) ?

Or another way to implement this class that avoid code duplication (without mypy error and auto-completion loss) ?

CodePudding user response:

In the class Person try to add data type in constructor

CodePudding user response:

Ok, I ended up with that

class Person:
    # this is not full, you need to fill other types you use it with the correct relationship
    types = {
        str: 'VARCHAR(50)',
        int: 'INTEGER',
    }  # you should extract that out if you use it elsewhere


    TABLE_NAME = 'person'
    

    # NOTE: the only annotated fields should be these. if you annotate anything else, It will break
    name: str
    age: int

    def __init__(self, **kwargs):
        self.__dict__ = kwargs

    @property
    def FIELDS(cls):
        return [(key, cls.types[value]) for key, value in cls.__annotations__.items()]


alice = Person(name='Alice', age=25)

print(alice.FIELDS)  # [('name', 'VARCHAR(50)'), ('age', 'INTEGER')]

And

>>> mypy <module>
>>> Success: no issues found in 1 source file
  • Related