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')
Related
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.
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.
This is the example of using properties given in the Python documentation:
Class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
As far as I can tell, this behaves just like a regular property-less instance variable:
Class D(object):
def __init__(self):
self.x = None
Of course this doesn't have the ability to add additional logic to the getter or setter, but, since there is no difference in how other code interacts with C and D, you could always add a property later if you needed it without breaking any other code.
I know that this creates a problem if you use mutable types that are declared at the class level, i.e.:
class E(object):
x = [1,2,3]
Apart from that case, though, is it bad practice to leave out the properties until it they are needed or is it acceptable?
Thanks!
You use property to evaluate the value an object attribute that is a funciton of other attributes. Consider the following class:
class shape:
def __init__(self,l,w):
self.length = l
self.width = w
#property
def area(self):
return self.length*self.width
If we change the value of either length or width, the value of area will be updated immediately when we ask for it.
[In:] s = shape(2,3)
[In:] print s.length, s.width, s.area
[Out:] 2 3 6
[In:] s.length = 5
[In:] print s.length, s.width, s.area
[Out:] 5 3 15
To help clarify how this works, consider the following case: if we try to define area in __init__():
class shape2:
def __init__(self,l,w):
self.length = l
self.width = w
self.area = self.length * self.width
area will only be evaluated when the class is instantiated. Changing the values of length or width won't modify the value of area:
[In:] s = shape2(2,3)
[In:] print s.length, s.width, s.area
[Out:] 2 3 6
[In:] s.length = 5
[In:] print s.length, s.width, s.area
[Out:] 5 3 6
What I think personally is that Python exposes variables as part of its philosophy, so you do not need to make properties out of everything. You can use properties to add logic to what was once a simple variable, or in order to keep the (client) code clean.
Classes like C in are useless outside tutorials/documentation.
(This is my own opinion. I don't know what is "considered" bad practice, as I am not an experienced developer or something)
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.
In Python is there any way to make a class, then make a second version of that class with identical dat,a but which can be changed, then reverted to be the same as the data in the original class?
So I would make a class with the numbers 1 to 5 as the data in it, then make a second class with the same names for sections (or very similar). Mess around with the numbers in the second class then with one function then reset them to be the same as in the first class.
The only alternative I've found is to make one aggravatingly long class with too many separate pieces of data in it to be readily usable.
A class is a template, it allows you to create a blueprint, you can then have multiple instances of a class each with different numbers, like so.
class dog(object):
def __init__(self, height, width, lenght):
self.height = height
self.width = width
self.length = length
def revert(self):
self.height = 1
self.width = 2
self.length = 3
dog1 = dog(5, 6, 7)
dog2 = dog(2, 3, 4)
dog1.revert()
Here's another answer kind of like pobk's; it uses the instance's dict to do the work of saving/resetting variables, but doesn't require you to specify the names of them in your code. You can call save() at any time to save the state of the instance and reset() to reset to that state.
class MyReset:
def __init__(self, x, y):
self.x = x
self.y = y
self.save()
def save(self):
self.saved = self.__dict__.copy()
def reset(self):
self.__dict__ = self.saved.copy()
a = MyReset(20, 30)
a.x = 50
print a.x
a.reset()
print a.x
Why do you want to do this? It might not be the best/only way.
Classes don't have values. Objects do. Is what you want basically a class that can reset an instance (object) to a set of default values?
How about just providing a reset method, that resets the properties of your object to whatever is the default?
I think you should simplify your question, or tell us what you really want to do. It's not at all clear.
I think you are confused. You should re-check the meaning of "class" and "instance".
I think you are trying to first declare a Instance of a certain Class, and then declare a instance of other Class, use the data from the first one, and then find a way to convert the data in the second instance and use it on the first instance...
I recommend that you use operator overloading to assign the data.
class ABC(self):
numbers = [0,1,2,3]
class DEF(ABC):
def __init__(self):
self.new_numbers = super(ABC,self).numbers
def setnums(self, numbers):
self.new_numbers = numbers
def getnums(self):
return self.new_numbers
def reset(self):
__init__()
Just FYI, here's an alternate implementation... Probably violates about 15 million pythonic rules, but I publish it per information/observation:
class Resettable(object):
base_dict = {}
def reset(self):
self.__dict__ = self.__class__.base_dict
def __init__(self):
self.__dict__ = self.__class__.base_dict.copy()
class SomeClass(Resettable):
base_dict = {
'number_one': 1,
'number_two': 2,
'number_three': 3,
'number_four': 4,
'number_five': 5,
}
def __init__(self):
Resettable.__init__(self)
p = SomeClass()
p.number_one = 100
print p.number_one
p.reset()
print p.number_one