Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pojo like classes in Python

Tags:

python

class

I want to create a Pojo like class for User in Python. Each of the property will involve some validations. For example: I don't want someone to create a User with a negative value of age. To acheive that I will end up writing a class something like below.

 class User:
        def __init__(self, age):
            self.age = age

        @property
        def age(self):
            return self._age

        @age.setter
        def age(self, value):
            print("Called")
            if value >= 0:
                self._age = 0
            else:
                raise ValueError("Age can't be negative")

I am bit scared after seeing the class above. Reasons:

  1. My User class will have somewhere around 50'ish properties. I am bit scared to imagine how big this class will look in that case.

Is this a correct way of creating such classes in Python?

like image 655
Lokesh Agrawal Avatar asked Oct 21 '18 05:10

Lokesh Agrawal


People also ask

Is Python object oriented like Java?

Object Attributes. All object-oriented languages have some way to store data about the object. In Java and Python, data is stored in attributes, which are variables associated with specific objects. One of the most significant differences between Python vs Java is how they define and manage class and object attributes.

Is Python good for object oriented?

Python is a great programming language that supports OOP. You will use it to define a class with attributes and methods, which you will then call. Python offers a number of benefits compared to other programming languages like Java, C++ or R. It's a dynamic language, with high-level data types.

What is the difference between model and POJO?

Model is basically what data flows around, and Pojo which is same as Bean .

What are the POJO classes?

POJO classes POJO stands for Plain Old Java Object. It is an ordinary Java object, not bound by any special restriction other than those forced by the Java Language Specification and not requiring any classpath. POJOs are used for increasing the readability and re-usability of a program.


1 Answers

I don't see what's clumpsy about this - most languages out there do not have built-in getter/setter validation so you would end up writing something similar to this in any language you choose - if you want to turn all your properties into getter/setter pairs with validation, you'll have to write them separately.

Now, Python is a dynamic language of a very flexible nature so there are several ways which you can use to reduce the verbosity (but not the complexity) of this process. For example, you can create your own validator decorator to be clamped on top of your setters, e.g.:

def validator(cmp, exc):
    def decorator(setter):  # a decorator for the setter
        def wrapper(self, value):  # the wrapper around your setter
            if cmp(value):  # if cmp function returns True, raise the passed exception
                raise exc
            setter(self, value)  # otherwise just call the setter to do its job
        return wrapper
    return decorator

And now you can define your getter/setter pairs with validation included as:

class User:

    def __init__(self, age):
        self.age = age

    @property
    def age(self):
        return self._age

    @age.setter
    @validator(lambda x: x < 0, ValueError("Age can't be negative"))
    def age(self, value):
        self._age = value

However, if you're only ever going to just do the validation and no other processing in your setters (and getters), you can just define your own validating property and save a lot on verbosity, something like:

class ValidatingProperty(object):

    def __init__(self, prop, cmp, exc):
        self.prop = prop
        self.cmp = cmp
        self.exc = exc

    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return getattr(instance, self.prop, None)

    def __set__(self, instance, value):
        if self.cmp(value):
            raise self.exc
        setattr(instance, self.prop, value)

    def __delete__(self, instance):
        delattr(instance, self.prop)

And now you can build your class getters/setters as simple as:

class User:

    age = ValidatingProperty("_age", lambda x: x < 0, ValueError("Age can't be negative"))

    def __init__(self, age):
        self.age = age

And if you ever need to access the raw property (assuming it was set), without wrappers around it, you can still access it with self._age (or whatever 'real' property that you've passed as the first argument to ValidatingProperty). You can even build your validators separately so you don't rely on lambdas (e.g. create an IntegerValidator class which lets you pass the ranges for validation and then reuse where needed).

The other option is to treat the users of your classes as adults and explain the valid values in the documentation and if they go outside of that - there be dragons. If the class is intended to be populated with data from end-users, the validation should be performed on the side that collects the end-user data (so that the end users can get a meaningful error with them in mind), not necessarily in the model itself.

like image 168
zwer Avatar answered Oct 09 '22 13:10

zwer