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:
Is this a correct way of creating such classes in Python?
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.
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.
Model is basically what data flows around, and Pojo which is same as Bean .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With