Question

I wrote a code that simulates the use of abc module and properties. However, it seems that I couldn't be able to access width and height variables. The code is as the following:

from abc import ABCMeta, abstractmethod

class Polygon:

__metaclass__ = ABCMeta

@abstractmethod
def compute_area(self): pass


def __init__(self):
    self.width = None
    self.height = None

@property
def width_prop(self):
    return self.width

@property
def height_prop(self):
    return self.height

@width_setter.setter
def width_setter(self, width):
    self.width = width

@height_setter.setter
def height_setter(self, height):
    self.height = height



class Triangle(Polygon):
    def compute_area(self):
        return 0.5 * width * height




if __name__ == "__main__":
    tri = Triangle()
    tri.height_setter(20)
    tri.width_setter(30)
    print "Area of the triangle = ", tri.compute_area()

The error message that I obtained is NameError: name 'width_setter' is not defined. What could be wrong in my implementation?

EDIT:

from abc import ABCMeta, abstractmethod

class Polygon:

__metaclass__ = ABCMeta

@abstractmethod
def compute_area(self): pass


def __init__(self):
    self.width = None
    self.height = None

@property
def width_prop(self):
    return self.width

@width_prop.setter
def width_setter(self, width):
    self.width = width

@property
def height_prop(self):
    return self.height

@height_prop.setter
def height_setter(self, height):
    self.height = height



class Triangle(Polygon):
    def compute_area(self):
        return 0.5 * self.width * self.height




if __name__ == "__main__":
    tri = Triangle()
    tri.height_prop = 20
    tri.width_prop = 30
    print "Area of the triangle = ", tri.compute_area()
Was it helpful?

Solution

edit: In such simple case like example use direct variable access. See Ned Batchelder's answer.

If you need extra functionality when accessing variables you can use this.


http://docs.python.org/library/functions.html#property

from abc import ABCMeta, abstractmethod

class Polygon(object):

    __metaclass__ = ABCMeta

    @abstractmethod
    def compute_area(self): 
        pass


    def __init__(self):
        self._width = None
        self._height = None

    @property
    def width(self):
        getting_variable_value()
        return self._width

    @width.setter
    def width(self, width):
        setting_variable_value()
        self._width = width

    @property
    def height(self):
        getting_variable_value()
        return self._height

    @height.setter
    def height(self, height):
        setting_variable_value()
        self._height = height



class Triangle(Polygon):
    def compute_area(self):
        return 0.5 * self.width * self.height


if __name__ == "__main__":
    tri = Triangle()
    tri.height = 20
    tri.width = 30
    print "Area of the triangle = ", tri.compute_area()

OTHER TIPS

Write Python as Python, not as C++ or Java:

class Polygon:
    def compute_area(self):             # if you need this at all...
        raise NotImplementedError()     # what does it do for you?

    def __init__(self):
        self.width = None
        self.height = None

class Triangle(Polygon):
    def compute_area(self):
        return 0.5 * self.width * self.height

if __name__ == "__main__":
    tri = Triangle()
    tri.height = 20
    tri.width = 30
    print "Area of the triangle = ", tri.compute_area()

"fixed" (but totally unpythonic) code:

class Polygon(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def compute_area(self): 
        pass

    def __init__(self):
        self.width = None
        self.height = None

    @property
    def width_prop(self):
        return self.width

    @width_prop.setter
    def width_prop(self, width):
        self.width = width

    @property
    def height_prop(self):
        return self.height

   @height_prop.setter
   def height_prop(self, height):
    self.height = height


class Triangle(Polygon):
    def compute_area(self):
        return 0.5 * self.width_prop * self.height_prop

if __name__ == "__main__":
    tri = Triangle()
    tri.height_prop = 20
    tri.width_prop = 30
    print "Area of the triangle = ", tri.compute_area()

Now for the serious part: Python is not Java. You don't need getters/setters for plain attributes access, since Python as a pretty good support for computed attributes (the property type you failed to use correctly being a very simplistic generic - but very handy - implementation of). Your getters and setters are not doing anything useful, and you'll have the very same result (with less code and better perfs) accessing the attributes directly:

class Polygon(whatever):
    __metaclass__ = ABCMeta

    def __init__(self, witdh=None, height=None):
        self.width = width
        self.height = height


    @abstractmethod
    def compute_area(self): 
        pass


class Triangle(Polygon):
    def compute_area(self):
        return 0.5 * self.width * self.height


if __name__ == "__main__":
    tri = Triangle(20, 30)
    print "Area of the triangle = ", tri.compute_area()

For the record, Python doesn't have "private" / "public" keywords - only a convention that names starting with a leading underscore are "implementation stuff" and shouldn't be accessed by client code. Note that the "shouldn't" only means what it means : nothing prevents you from accessing them, but then don't complain if anything breaks, now or in next release. Kind of "warranty void if unsealed".

wrt/ proper use or property: I won't go into details (would require an in-depth Python execution model and object model explanation), but the correct syntax is:

class MyClass(object):

    def __init__(self, prop):
        # this will invoke prop.setter
        self.prop = prop

    # defines a property named "prop"
    # will be accessed just like a plain
    # attribute but will go thru the getter and setter

    @property
    def prop(self):
        # this is the getter
        return self._some_val * 42

    # now add a setter to 'prop':
    @prop.setter
    def prop(self, val):
        self._some_val = val / 42


obj = MyClass(10)
print obj.prop
obj.prop = 5
print obj.prop

Also (and finally): Python has no "implicit this" (or "implicit self"). You must use self.attr within a method to access any attribute.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top