Setter for a field of a field - python

Given the code:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Block:
size = 40
def __init__(self, x=1, y=1):
self.pixel_position = Point(x * Block.size, y * Block.size)
self.__block_position = Point(x, y)
#property
def block_position(self):
return self.__block_position
#block_position.setter
def block_position(self, point):
#I want for pixel_position to be updated whenever block position changes
self.pixel_position.x += point.x * size
self.pixel_position.y += point.y * size
self.__block_position = point
Now for such code simple assignment works well
block = Block()
block.block_position = Point(2, 1)
but if I want to increment x of block position... well, code doesn't go into setter.
block.block_position.x -= 1
# now block_position = (1, 1) but pixel_position = (80, 40) not (40, 40)
How may I change it?
I know I can resolve this problem with adding property for __pixel_position that will calculate Block.size * __block_position before returning itself, but that approach doesn't satisfy me - well I want to know how in python one can set a property for a field of a field.
My question is not about finding any solution, but to find a solution where changing field block_position.x will redirect me to my setter/getter.

The problem there is that you are mixing some concepts trying to make use of Python property and things get confusing -
The basic thing is that if pixel_position is to be to be calculated - it should itself a property.
What your are trying to do is to put some gates on the setting of values on "block_position" and derive - when block_position is changed the new value for pixel_position. That is not working because you have not "gatted" always one could possibly modify the values inside your block_position.
What happens when you make:
block.block_position.x += 1
Is that the property getter for block_position is activated - the Point object in there then have its x attribute changed - but this change never goes through the outter block object,as x is an ordinay attribute, not a property.
Now, it would be possible to instrument your Point class so that actions could be triggered whenever x ou y are changed - but that could become really complicated, and fast.
A better approache there is to have pixel_position itself be a property, instead of an ordinary attribute, and have its values lazily calculated - generated whenever they are needed - and not depend on the value to be setted eagerly whenever block_position changes. This is a pattern from "reactive programing".
Actually, you will find out that "block_poisition" itself can be an ordinary instance attribute, and not be a property - unless you want its checker to ensure the assigned object is an instance of Point.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __mul__(self, scale):
return Point(self.x * scale, self.y * scale)
class Block:
size = 40
def __init__(self, x=1,y=1):
self._block_position = Point(x,y)
#property
def block_position(self):
return self._block_position
#block_position.setter
def block_position(self, point):
if not isinstance(point, Point):
# raise TypeError() # or, as an option, accept sequences of 2 coordinates:
point = Point(point[0], point[1])
self._block_position = point
#property
#pixel_position(self):
return self._block_position * self.size
So, now things are the other way around - and pixel_position can't be setted and is guaranteed to be always updated.
Three things in there:
I've added the __mul__ method to your Point so now one can just use the * operator to multiply it by a scalar.
There is no need or sense in actually prepending __ to Python "hidden" attributes. Early tutorials or unofficial documentation to the language could misleadingly say it is a way of having "private attributes". That is an error - there is no private attributes in Python what __ does is name mangling in order to allow a class to have attributes that are not messed up by subclasses. In almost 20 years of Python programming I've never actually needed that feature. On the other hand, it can give you strange errors if you have subclasses of Block. Just don't. The accepted convention is that one single "_" indicates an attribute that should not be changed or accessed directly by users of the class and this have no side effects.
Without a setter, pixel_position is mostly "unchangeable" - and if one does change the attributes inside it after retrieving block.pixel_position , he will be changing a detached Point instance.
If you really need round-trip changing between pixel_position and block_position (that is, make in such a way the class user can change either attribute and have the change reflected in the other), rather than trying to instrument a change notification inside Point , I suggest you make Point an immutable class instead. Anyone wanting to change coordinates would have to create a new point instance - as a result block.block_position.x += 1 would not work anymore - one would have to do: block.block_position += Point(1, 0) (and then you implement __add__ in Point, just as I did __mul__). Then you could write your setter for pixel_position to force a new value to block_position if it gets changed.
On the upside, if you make Point immutable, you can add __hash__ to it and have it working in sets and as dictionary keys: a lot of other uses open up.
Check the class V2 implementation on this project to have an idea of a nice implementation (Disclaimer: the link project is something I am working now as a hobby, and I have actually implemented this class over the past week)

Since you asked for it, I'm providing an example implementation where properties of an object notify their owner when being set, for it to synchronize with another object. I only consider 1D points (x) in this example since the implementation for y is the very same:
class NotificationProperty(property):
def __init__(self, fget=None, fset=None, fdel=None, doc=None, notify=None):
super().__init__(fget, fset, fdel, doc)
self.notify = notify
def __set_name__(self, owner, name):
self.name = name
def __set__(self, instance, val):
super().__set__(instance, val)
self.notify(instance, self.name, val)
# Should define similar methods for other attributes
# (see https://docs.python.org/3/howto/descriptor.html#properties).
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__, self.notify)
def notification_property(func):
from functools import partial
return partial(NotificationProperty, notify=func)
class SyncPoint:
def __init__(self, x, sync_with=None):
self.sync_with = sync_with
self.x = x
def sync(self, which, value):
if self.sync_with is not None:
obj, scale = self.sync_with
value = int(scale * value)
if getattr(obj, which) != value: # Check if already synced -> avoid RecursionError.
setattr(obj, which, value)
#notification_property(sync)
def x(self):
return self._x
#x.setter
def x(self, val):
self._x = val
class Block:
size = 40
def __init__(self, x=1):
self.pixel_position = SyncPoint(self.size * x)
self.block_position = SyncPoint(x, sync_with=(self.pixel_position, self.size))
self.pixel_position.sync_with = (self.block_position, 1/self.size)
block = Block(3)
print('block_pos: ', block.block_position.x) # block_pos: 3
print('pixel_pos: ', block.pixel_position.x) # pixel_pos: 120
block.block_position.x -= 1
print('block_pos: ', block.block_position.x) # block_pos: 2
print('pixel_pos: ', block.pixel_position.x) # pixel_pos: 80
block.pixel_position.x -= Block.size
print('block_pos: ', block.block_position.x) # block_pos: 1
print('pixel_pos: ', block.pixel_position.x) # pixel_pos: 40
Variation: specify the notify function via x.setter(func)
The following is a variation of the above code which let's you specify the function to be called for notifications during definition of x.setter. This might feel more intuitive since the notification happens on __set__ but in the end it's a matter of taste:
from functools import partial
class notification_property(property):
def __init__(self, fget=None, fset=None, fdel=None, doc=None, notify=None):
super().__init__(fget, fset, fdel, doc)
self.notify = notify
def __set_name__(self, owner, name):
self.name = name
def __set__(self, instance, val):
super().__set__(instance, val)
self.notify(instance, self.name, val)
# Should define similar methods for other attributes
# (see https://docs.python.org/3/howto/descriptor.html#properties).
def setter(self, func=None):
return partial(type(self), self.fget, fdel=self.fdel, doc=self.__doc__, notify=(func or self.notify))
class SyncPoint:
def __init__(self, x, sync_with=None):
self.sync_with = sync_with
self.x = x
def sync(self, which, value):
if self.sync_with is not None:
obj, scale = self.sync_with
value = int(scale * value)
if getattr(obj, which) != value: # Check if already synced -> avoid RecursionError.
setattr(obj, which, value)
#notification_property
def x(self):
return self._x
#x.setter(sync)
def x(self, val):
self._x = val

You can resolve this by making pixel_position a property since this attribute seems dependent on the other, block_position. That way block_position doesn't even have to be a property:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'{type(self).__name__}({self.x}, {self.y})'
class Block:
size = 40
def __init__(self, x=1, y=1):
self.block_position = Point(x,y)
#property
def pixel_position(self):
return Point(self.block_position.x * self.size, self.block_position.y * self.size)
block = Block()
block.block_position = Point(2,1)
block.block_position.x -= 1
print(block.block_position) # Point(1, 1)
print(block.pixel_position) # Point(40, 40)
In general dependent attributes are suitable for properties as they can be computed "on-the-fly" from other, independent ones.

Related

Monkey patching __eq__ in Python

Having some trouble understanding why I'm able to re-define (monkey patch) __eq__ outside of a class, but not change its definition through __init__ or in a method:
class SpecialInteger:
def __init__(self,x):
self.x = x
self.__eq__ = self.equals_normal
def equals_normal(self,other):
return self.x == other.x
def equals_special(self,other):
return self.x != other.x
def switch_to_normal(self):
self.__eq__ = self.equals_normal
def switch_to_special(self):
self.__eq__ = self.equals_special
a = SpecialInteger(3)
b = SpecialInteger(3)
print(a == b) # false
a.switch_to_normal()
print(a == b) # false
SpecialInteger.__eq__ = SpecialInteger.equals_normal
print(a == b) # true
SpecialInteger.__eq__ = SpecialInteger.equals_special
print(a == b) # false
Am I just using self incorrectly or is there some other reason it works like this?
To do it inside the class, you would simply define the __eq__ method inside of your class.
class SpecialInteger:
def __init__(self,x):
self.x = x
def __eq__(self, other):
# do stuff, call whatever other methods you want
EDIT: I see what you are asking, you wish to override the method (which is a "magic" method) at the instance level. I don't believe this is possible in the base construct of the language, per this discussion.
The reason your monkey patch works in that example is because it is being passed on the Class level, as opposed to the instance level, whereas self is referring to the instance.
Just to add on to an excellent existing answer, but this doesn't work because you are modifying the class instance, and not the class.
In order to get the behavior you desire, you can modify the class during __init__, however, this is woefully inadequate (since it modifies the class, and therefore all instances of the class), and you are better off making those changes visible at the class scope.
For example, the following are equivalent:
class SpecialInteger1:
def __init__(self,x):
self.x = x
self.__class__.__eq__ = self.equals_normal
...
class SpecialInteger2:
def __init__(self,x):
self.x = x
def equals_normal(self,other):
return self.x == other.x
def __eq__(self, other):
return self.equals_normal(other)
You should prefer case SpecialInteger2 in all examples, since it is more explicit about what it does.
However, none of this actually solves the issue you are trying to solve: how can I create a specialized equality comparison at the instance level that I can toggle? The answer is through the use of an enum (in Python 3):
from enum import Enum
class Equality(Enum):
NORMAL = 1
SPECIAL = 2
class SpecialInteger:
def __init__(self, x, eq = Equality.NORMAL):
self.x = x
self.eq = eq
def equals_normal(self, other):
return self.x == other.x
def equals_special(self, other):
return self.x != other.x
def __eq__(self, other):
return self.__comp[self.eq](self, other)
# Define a dictionary for O(1) access
# to call the right method.
__comp = {
Equality.NORMAL: equals_normal,
Equality.SPECIAL: equals_special
}
Let's walk through this quickly, since there are 3 parts:
An instance member variable of eq, which can be modified dynamically.
An implementation of __eq__ that selects the correct equality function based on the value of self.eq.
A namespace-mangled dictionary (a class/member variable that starts with __, in this case, self.__comp) that allows efficient lookup of the desired equality method.
The dictionary can easily be done-away with, especially for cases where you only wish to support 1-5 different possible comparisons, and replaced with idiomatic if/then statements, however, if you ever wish to support many more comparison options (say, 300), a dictionary will be much more efficient O(1) than if/then comparisons (linear search, O(n)).
If you wish to do this with setters (like in the original example), and actually hide the member functions from the user, you can also do this by directly storing the function as a variable.
All method definitions are defined at class level (literally the name is a key in a dict belonging to the class). This is also true of anything else you put at class level. Which is why for instance a variable assignment outside a method in a class produces a class variable.
The easiest way to keep the same functionality would be to just refer to some other variable from __eq__. It could be some reference variable, or a saved method.
class SpecialInteger:
def __init__(self,x):
self.x = x
self._equal_method = self.equals_normal
# ...
def switch_to_normal(self):
self._equal_method = self.equals_normal
def switch_to_special(self):
self._equal_method = self.equals_special
def __eq__(self, other):
return self._equal_method(other)

Python OOP: how to use a flag parameter to access methods?

It's unclear to me how one accomplishes this in Python, though I am confused about the fundamentals of OOP:
Let's say I create a Shape class, and use this as an example.
class Shape:
def __init__(self, x, y):
self.x = x
self.y = y
def area(self):
return self.x * self.y
def perimeter(self):
return 2 * self.x + 2 * self.y
def scaleSize(self,scale):
self.x = self.x * scale
self.y = self.y * scale
In my case, I must create a Class which inputs a file whereby there are only two types, file_typeA and file_typeB. For the user, it would be exceptionally cumbersome to use a Class for Type A and a Class for Type B.
## use case for an a "read in file name" class `filename`
foo = filename(path = "path/to/file.txt", file_type = "TypeA")
My question is, how do I restrict the "Type A" methods for a file initialized with flag file_type="TypeA", and restrict the methods for a file initialized with flag file_type = "TypeB"?
Let's try the Shape class again, whereby the two types are Square and Triangle. The wrong way to code this is something like this:
class Shape:
def __init__(self, x, y, type):
self.x = x
self.y = y
self.type = type
if type == "Square":
def area(self):
return self.x * self.y
def perimeter(self):
return 2 * self.x + 2 * self.y
def scaleSize(self,scale):
self.x = self.x * scale
self.y = self.y * scale
elif type == "Triangle":
def hooray(self):
print("HOORAY! It's hip to be a triangle!")
else:
print("'type' must be either Circle or Triangle")
## example Class instantiation
bar = Shape(2, 3, type="Square")
For such a class, how do I create it such that the method area cannot be used for a Shape of type=="TypeB"?
I think you need to define a mother class:
class Shape:
pass
then sub-classes
class Triangle(Shape):
# whatever methods there are
What you're describing is a factory function which creates the proper object according to some parameter:
def create(type):
if type=="Triangle":
return Triangle()
elif type=="Square":
return Square()
but it's not very useful since the caller has to pass the name of the class instead:
c = create("Triangle")
instead of just doing:
c = Triangle()
Well, it may have its interest when saving/restoring a program state from a text file containing the type(s) of the objects in the program memory when saved (if you don't want to use pickle).
That's not how you OOP! OOP helps to eliminate those kinds of conditionals. You should create a Shape base class, then use that to define subclasses for each individual kind of shape. The subclasses should include the methods needed for that kind of shape.
If you want the caller to be able to specify a shape using a string, for example because they are using data from a file or the user, you can write a factory method to do that. You can actually ask Python for the subclasses of your class; no need to list them out! DRY
class Shape(object):
__subs = {}
#classmethod
def of_type(cls, name, *args, **kwargs):
"""Factory method that instantiates Shape subclasses given their name as a string"""
lname = name.lower()
subs = cls._Shape__subs
if cls is Shape:
if not subs: # build subclass dictionary
subs.update({c.__name__.lower(): c for c in cls.__subclasses__()})
if lname in subs: # instantiate the named subclass
return subs[lname](*args, **kwargs)
raise NameError("invalid shape name: %s" % name)
raise TypeError("of_type() may be called only on Shape base class")
class Square(Shape):
pass
class Triangle(Shape):
pass
# set tri to an instance of type Triangle
tri = Shape.of_type("Triangle")
Note that the factory method passes through any arguments given after the name. Class names are case-insensitive.

Recreate class object changing one constructor argument

I'd like to have implement an update method in my class that recreates the class but changes just one constructor argument.
My attempt:
class Updateable:
def update(self, var, var_str, **kwargs):
kwargs.update(self._vars)
kwargs[var_str] = var
self.__init__(**kwargs)
class Rectangle(Updateable):
def __init__(self, length, perimeter):
self._vars = locals()
self.length = length
self.width = 0.5*(perimeter - 2.*length)
r = Rectangle(10, 20)
r.update('perimeter', 16)
The problem is, the whole locals() thing, I think, is pretty dodgy, and it means that any class that is Updateable needs to assign self._vars.
What would be the correct way to achieve this functionality? Decorators, metaclasses? Something simpler?
Please correct me if I misunderstood your question, or if you don't want high level advise and your just question solved.
What your __init__ currently does is recalculate the properties of a geometric shape if a (possibly relevant) variable is changed. Step 1 is to take this out of the __init__, and into a seperate def which is called by init. The main thing here is that you do not pass variables to this function, but use the class variables which have been set in either __init__ or one the superclass updating methods.
Step 2 is to change your update function.
Python has a form of getters and setters called properties allowing you to hook tasks to updating your variables. On the other hand a more generalized way is more similar to your own update, and is listed as option 2 below
Example alternative
class Updateable:
# Option 1
#property
def perimeter(self):
return self.__perimeter
#perimeter.setter
def perimeter(self, perimeter):
self.__perimeter = perimeter
self.recalculate_everything() # or self.calculate_width() or something
# Option 2
def update(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
self.recalculate_everything
class Rectable(Updateable):
def __init__(self, length, perimeter):
self.__length = length
self.__perimeter = perimeter
recalculate_everything()
def recalculate_everything():
self.calculate_width()
...
def calculate_width():
self.__width = 0.5*(self.__perimeter - 2.*self.__length)
Laurens Koppenol suggested using properties (Python's generic support for computed attribute) which is a good idea but his example code is both broken in many ways and more complicated than it has to be, so here's a simpler, working and pythonic example (no Updatable class nor any other extraneous stuff required):
class Rectangle(object):
def __init__(self, length, perimeter):
self.length = length
self.perimeter = perimeter
#property
def width(self):
return 0.5*(self.perimeter - 2.*self.length)
If you want to cache the width value (to avoid useless computations) but still make sure it's updated when length or perimeter change, you'll need to make them all properties:
class Rectangle(object):
def __init__(self, length, perimeter):
self.length = length
self.perimeter = perimeter
#property
def length(self):
return self._length
#length.setter
def length(self, value):
self._length = value
self._width = None
#property
def perimeter(self):
return self._perimeter
#length.setter
def perimiter(self, value):
self._perimeter = value
self._width = None
#property
def width(self):
if self._width is None:
self._width = 0.5*(self.perimeter - 2.*self.length)
return self._width
or (if you have a lot of such stuff) use some "cached_property with invalidation" implementation as this one: Storing calculated values in an object
edit: wrt/ your question, the call to locals is indeed ugly (and can easily break - you may have local variables that are not supposed to be parts of _vars), as well as the need to explicitely set self._vars in child classes. Also the update() API is itself quite ugly IMHO. Now you don't need anything fancy to make the whole thing more pythonic - here's a solution whose only boilerplate is the need to call Updateable.__init__ with named arguments (won't work with positional ones):
class Updateable(object):
def __init__(self, **kwargs):
self._vars = kwargs
def update(self, **kwargs):
vars = self._vars.copy()
vars.update(**kwargs)
self.__init__(**vars)
class Rectangle(Updateable):
def __init__(self, length, perimeter):
super(Rectangle, self).__init__(length=length, perimeter=perimeter)
self.length = length
self.width = 0.5*(perimeter - 2.*length)
r = Rectangle(10, 20)
r.update(perimeter=40)
As a side note, I personnaly find quite disturbing that your Rectangle class takes a perimeter argument but stores a width instead... Maybe you should consider a perimeter property ? (even if read-only to avoid recomputing etc)
As others have observed, computations like width should be moved to a property or method; they don't belong in an initialiser.
If you really want to return a new instance, this would work for the simplest cases, where the instance's attributes are immutable objects like strings or integers:
import copy
class Copyable:
"""Mixin to create copies with a changed attribute."""
def copy_and_modify(self, var, var_str, **kwargs):
new = copy.copy(self)
setattr(new, var, var_str)
return new
class Rectangle(Copyable):
def __init__(self, length, perimeter):
self.perimeter = perimeter
self.length = length
#property
def width(self):
return 0.5 * (self.perimeter - 2.0 * self.length)
however if your objects contain nested mutable structures such as dictionaries or lists you would need to change copy_and_modify to use copy.deepcopy (but note deep copying is slow)
class Copyable:
def copy_and_modify(self, var, var_str, **kwargs):
new = copy.deepcopy(self)
setattr(new, var, var_str)
return new
You can define __copy__ and __deepcopy__ methods in your subclasses as described in the docs to fine-tune control over the copying process.

Creating a Rectangle class [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I really don't understand classes very much and any help would be great.
Rectangle class should have the following private data attributes:
__length
__width
The Rectangle class should have an __init__ method that creates these attributes and initializes them to 1. It should also have the following methods:
set_length – this method assigns a value to the __length field
set_width – this method assigns a value to the __width field
get_length – this method returns the value of the __length field
get_width – this method returns the value of the __width field
get_area – this method returns the area of Rectangle
__str__ – this method returns the object’s state
class Rectangle:
def __init__(self):
self.set_length = 1
self.set_width = 1
self.get_length = 1
self.get_width = 1
self.get_area = 1
def get_area(self):
self.get_area = self.get_width * self.get_length
return self.get_area
def main():
my_rect = Rectangle()
my_rect.set_length(4)
my_rect.set_width(2)
print('The length is',my_rect.get_length())
print('The width is', my_rect.get_width())
print('The area is',my_rect.get_area())
print(my_rect)
input('press enter to continue')
Python does not restrict the access to private data attributes, so you seldom get yourself writing "getters" and "setters" like in more restrictive languages (we are all consenting adults).
Except when it is something for internal use (an implementation detail that you may change in the future) you just expose the property to the world - so a more idiomatic Rectangle would be just this:
class Rectangle(object):
def __init__(self, width=1, height=1):
self.width = width
self.height = height
#property
def area(self):
return self.width * self.height
Then:
>>> r = Rectangle(5, 10)
>>> r.area
50
>>> r.width = 100
>>> r.area
1000
Of course you can write the Rectancle class using getters and setters, but you only do that when you want to validate or transform the input - then you probably want to learn more about the #property decorator.
You've got a few issues with your class. See the below comments
class Rectangle:
# Init function
def __init__(self):
# The only members are length and width
self.length = 1
self.width = 1
# Setters
def set_width(self, width):
self.width = width
def set_length(self, length):
self.length = length
# Getters
def get_width(self):
return self.width
def get_length(self):
return self.length
def get_area(self):
return self.length * self.width
# String representation
def __str__(self):
return 'length = {}, width = {}'.format(self.length, self.width)
Testing the class
>>> a = Rectangle()
>>> a.set_width(3)
>>> a.set_length(5)
>>> a.get_width()
3
>>> a.get_length()
5
>>> a.get_area()
15
>>> print(a)
length = 5, width = 3
As others have noted, setter's and getter's are superfluous in Python, as all member variables are public. I understand that these methods are required for your assignment, but in the future, know that you can save yourself the trouble and just directly access the members
>>> a.length # Instead of the getter
5
>>> a.length = 2 # Instead of the setter
>>> a.length
2
First, this assignment is a very bad idea. In Python, you almost never want "private" attributes and getter and setter functions, and whoever's teaching you to do this is leading you astray.
But, if you just want to pass the assignment instead of learning how to write decent Python code, here's how you do it.
First, to create an attribute named __length, you just assign to it, the same as any other attribute:
def __init__(self):
self.__length = 1
Now, to write getters and setters for that attribute, do the same thing:
def get_length(self):
return self.__length
def set_length(self, length):
self.__length = length
Now, get_area is a bit trickier, because you don't have an __area to get. (This is a stupid idea, because it looks like a getter function even though it isn't…) But you know how to figure out the area of a rectangle: it's just the length times the width, right?
def get_area(self):
return self.__length * self.__width
The __str__ method is the only good idea in the whole assignment—although it's probably a bad idea to write a __str__ without a __repr__ for a class like this. Anyway, both of these are methods that just return a string with some useful representation of your objects. The str should be something friendly to an end-user, while the repr should be something useful to the programmer (you, or someone using your class). For example:
def __str__(self):
return '{} x {} rectangle'.format(self.__length, self.__width)
def __repr__(self):
return '{}({}, {})'.format(type(self).__name__, self.__length, self.__width)
You would do absolutely fine without the set_'s and get_'s functions, and you should perhaps be more careful when using mangled variables (such as __variablename), but here's a less-than-brilliant code that fulfills your requirements. Hopefully that helps.
PS: print statements in Python 2.7 format.
class Rectangle():
def __init__(self):
self.__length = 1.0
self.__width = 1.0
def __str__(self):
return "This is class Rectangle"
def set_length(self,len=1.0): #len=1 --> default value
self.__length = len
def set_width(self,wid=1.0): #wid=1 --> default value
self.__width = wid
def get_length(self):
return self.__length
def get_width(self):
return self.__width
def get_area(self):
return self.get_width() * self.get_length()
if __name__ == '__main__':
my_rect = Rectangle()
my_rect.set_length(4.0)
my_rect.set_width(2.0)
print "The length is ", my_rect.get_length()
print "The width is ", my_rect.get_width()
print "The area is ", my_rect.get_area()
print my_rect
raw_input('Press enter to continue')

Getting field names reflectively with Python

Is it possible to get the name of a field reflectively in Python (3.2)?
See the following example:
class Something:
def __init__(self):
self.x = 1
def validate():
return validator.max(self.x, 10)
validator.max(self.x, 10) should produce an error message containing the name of the field x as string (in this case "x").
You would have to pass the attribute name as a string
def validate():
return validator.max(self, "x", 10)
then validator.max might look like this
def max(ob, attr, max_value):
val = getattr(ob, attr) # val would be self.x now
...
Unlikely. Things might not even have names - what is:
validator.max(3,10)
supposed to do?
Pass the name as well as the value if you want it output:
validator.max(self.x,10,"x")
whatever validator.max is, it needs another argument, or if its a builtin, you need to wrap it.
In Python the expression self.x is just the current value of that member and the information that the value is coming from an object is therefore lost.
However you can move the validation logic at an higher level (base class) and having it working on a whole object. With this approach validator "name" will be known by the validate function and can be used for the error message:
class ValidatedObject:
def validate(self):
for name in dir(self):
if (name.startswith("validate_") and # Is a validator
not getattr(self, name)()): # and failed
raise RuntimeError("%s: %s" %
(name, getattr(self, name).__doc__))
class Something(ValidatedObject):
def __init__(self, x, y):
self.x = x
self.y = y
def validate_x(self):
"Horizontal position shouldn't be that big"
return self.x < 10
def validate_y(self):
"Vertical position must be neither too low nor too high"
return 20 <= self.y <= 30
def validate_sum(self):
"The position must be on the prescribed line"
return self.x + self.y == 25
class Something2(Something):
def validate_sum(self):
return True
Something(3, 22).validate() # Ok
Something2(5, 30).validate() # Ok (derived class relaxed checks)
print "About to crash...."
Something2(5, 31).validate() # Not ok (Y is too high - inherited check)
Note of course that disabling a check in a derived class is illogical from an IS-A point of view, here is just as an example showing that dir will correctly find inherited members.

Categories