Showing posts with label property. Show all posts
Showing posts with label property. Show all posts

Monday, March 29, 2010

Python Derived Attributes

Python allows classes to define managed properties. Managed properties are just like regular attributes when used. The only difference between regular instance attributes and managed properties is that the latter lets the developer define behavior that is executed when an attribute is set or accessed.

There are countless uses for such a feature. For instance, when an attribute is set, some constraint on the allowed attribute values can be enforced. Another powerful use of managed properties is to create derived attributes. A derived attribute looks like a normal attribute to the world outside of the object. The difference being that derived attributes are computed from other, possibly derived, attributes of the object.

Since the value returned from these attributes are in fact derived from other attributes, there is no way to set the attribute value directly. In order to alter the outcome of accessing a derived attribute, you would have to alter another attribute that is used to compute the derived attribute.

This also introduces a level of indirection that can also be quite powerful in most cases. Developers using the object do not need to concern themselves with the correct output of accessing the derived attribute.

To define a derived attribute, all you need is a method that will compute the value to return. This method is then assigned to a managed property. The method should really only use other attributes of the same object to compute the returned value. Otherwise, it really wouldn't be a derived attribute, just a computed attribute.

Below is a very simplistic example of how to derive a full name form a first name and last name.
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name

def get_full_name(self):
return "%s %s"%(self.first_name, self.last_name)

full_name = property(get_full_name)

if __name__ == "__main__":

person_obj = Person("John", "Smith")

print "Full Name:", person_obj.full_name

Wednesday, September 23, 2009

Using Python Properties

The Python programming language is a loosely-typed language. What this essentially means is that any variable defined in a program can be assigned a value of any type. This also applies to attributes of classes. There is no need to specify the allowable types that a given attribute may hold. This offers the developer much flexibility when implementing an application. Even more flexibility may be added to a given class implementation by use of properties.

Python has a built-in property type that can be used to build complex attributes. By complex, I mean that the attributes can hold both data and behavior. This functionality can be made useful by imposing constraints on the attributes of a given instance because the behavior associated with the attribute is invoked when a value is set. This doesn't necessarily mean that the behavior is checking for the type of the value. That would defeat the purpose of a dynamically-typed language. It can, however, perform more complex testing such as checking the state of the value or making sure it falls within some range. The invoked behavior can also store and retrieve values from a non-standard location such as a database.

So why go to all this trouble? Why not just implement standard attributes and methods? That depends. The only reason to implement dynamic properties for Python instances is to provide a cleaner API for the client using the instances.

There are actually two methods in which to implement dynamic Python properties, both of which are illustrated below. The first, just overloads the __getattr__() and __setattr__() methods. These methods are invoked if the attribute requested does not exist in the standard location as a regular attribute. The benefit to this method is that these are the only methods that need to be implemented for attribute management. This means that any attributes can be set or retrieved on the instances. This can however lead to more work for these two methods because they are responsible for everything that might go wrong.

The second method, the property method, provides a better distribution of responsibilities. There is more work involved with the class implementation but is cleaner work that leads to a better client API.
#Example; Python properties.

#Simple person class.
class Person(object):

#The data for the instance attributes. This serves as
#an example that these attributes can be stored elsewhere.
data={"first_name":"", "last_name":""}

#Set an attribute.
def __setattr__(self, name, value):
self.data[name]=value

#Get an attribute.
def __getattr__(self, name):
return self.data[name]

#Simple person class.
class PropertyPerson(object):

#The data for the instance attributes. This serves as
#an example that these attributes can be stored elsewhere.
data={"first_name":"", "last_name":""}

#Set the first name.
def set_first_name(self, value):
self.data["first_name"]=value

#Set the last name.
def set_last_name(self, value):
self.data["last_name"]=value

#Get the first name.
def get_first_name(self):
return self.data["first_name"]

#Get the last name.
def get_last_name(self):
return self.data["last_name"]

#Create the properties using the previously
#defined instance methods.
first_name=property(fset=set_first_name, fget=get_first_name)
last_name=property(fset=set_last_name, fget=get_last_name)

#Main.
if __name__=="__main__":
#Create the test person instances.
person_obj=Person()
pperson_obj=PropertyPerson()

#Set some values without using properties.
person_obj.first_name="FirstName"
person_obj.last_name="LastName"

#Set some values using properties.
pperson_obj.first_name="FirstName"
pperson_obj.last_name="LastName"

#Display the attribute values of both instances.
print "Non-Property: %s %s"%(person_obj.first_name, person_obj.last_name)
print "\nProperty: %s %s"%(pperson_obj.first_name, pperson_obj.last_name)

Tuesday, May 5, 2009

How UML constrains subsetted properties

Classes are by far the most commonly encountered UML modeling element. As most users of the language have heard hundreds of times, classes do not exist in isolation for any given object system. Classes are often related to other classes by an association element. At each end of an association is a Property element. These property elements are generally not modeled directly but exist in the UML meta-model. In the context of a class associated with another class, these Property elements correlate to attributes of the two classes. These properties can be subsets of other properties and classes. In the UML model, this would be specified by applying the subsets tagged-value along with the context for the value. This values both modelers and software tools a better clue about how the design is organized. The UML specifies constraints that must be satisfied for a Property subset to be considered valid.

The following is an illustration of what takes place when the constraints of a subsetted property are validated.



First, the subsetting property and the subsetting context are both checked for emptiness. If so, the subset is not valid. Next, the validation will iterate through each subsetting context element and each subsetting property element. It is in this iteration that the validation process will ensure that the elements of both sets conform with one another.