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.
Related
Is there a way to have completion/intellisense on (*args ,**kwargs) functions?
For instance:
class GetVar(GetVarInterface):
#classmethod
def fromcustom(cls,locorvar,offset=0,varType="int", name=None,deref=False,member=None):
return GetVarCustom(locorvar,offset,varType, name,deref,member)
class GetVarCustom(GetVar):
def __init__(self,locorvar,offset=0,varType="int", name=None,deref=False,member=None):
I wanted to implement this without specifying every argument of the constructor (For example using *vars, **kwargs) but didn't want to lose completion/intellisense abilities. Is there a way?
The disadvantage in the current implementation is that you would have to replicate the signature twice for every change...
The only option is to add a comment under the function to hint the arguments, otherwise you can't; if the ide is reading that a function has undefined arguments, it will show you that it's undefined.
A "solution" is to just use the common arguments and pass the rest as kwargs, or you can keep the original init.
class Single_Init:
def __init__(self, val_a, val_b, name=None):
self.val_a = val_a
self.val_b = val_b
self.name = name
class Single_Init_B(Single_Init):
# The previous contructor is calld
def get_result(self):
return self.val_a + self.val_b
class Split_Const:
def op_offset(self, offset):
self.offset = offset
def __init__(self, name, member=None, **kwargs):
""" You olso can hint in a func coment """
self.name = name
self.member = member
if 'offset' in kwargs:
self.offset = kwargs['offset']
else:
self.offset = None
if __name__ == '__main__':
single = Single_Init_B(2, 3)
print('Single:', single.get_result())
split = Split_Const('Name')
split.op_offset(0.5)
print('Split:', split.offset)
Got the solution outside this site..
#functools.wraps(functools.partial(GetVarCustom.__init__,1))
def f(*args,**kwargs):
return GetVarCustom(*args,**kwargs)
Of course, it would have been easier in case of a standard function. However, you need to update the assigned attribute of wraps. Otherwise it will change the function name.
#functools.wraps(GetVarCustom.value,assigned=['__doc__'])
def getvalue(*args,**kwargs):
return self_custom.value(*args,**kwargs)
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 have a class which contains a list like so:
class Zoo:
def __init__(self):
self._animals = []
I populate the list of animals with animal objects that have various properties:
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
You can imagine subclasses of Animal that have other properties. I want to be able to write methods that perform the same calculation but on different attributes of the Animal. For example, an average. I could write the following in Zoo:
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self.animals) / len(self.animals)
That string lookup not only messes with my ability to document nicely, but using getattr seems odd (and maybe I'm just nervous passing strings around?). If this is good standard practice, that's fine. Creating get_average_speed(), get_average_height(), and get_average_length() methods, especially as I add more properties, seems unwise, too.
I realize I am trying to encapsulate a one-liner in this example, but is there a better way to go about creating methods like this based on properties of the objects in the Zoo's list? I've looked a little bit at factory functions, so when I understand them better, I think I could write something like this:
all_properties = ['speed', 'height', 'length']
for p in all_properties:
Zoo.make_average_function(p)
And then any instance of Zoo will have methods called get_average_speed(), get_average_height(), and get_average_length(), ideally with nice docstrings. Taking it one step further, I'd really like the Animal objects themselves to tell my Zoo what properties can be turned into get_average() methods. Going to the very end, let's say I subclass Animal and would like it to indicate it creates a new average method: (the following is pseudo-code, I don't know if decorators can be used like this)
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
#Zoo.make_average_function
#property
def tail_length(self):
return self._tail_length
Then, upon adding a Tiger to a Zoo, my method that adds animals to Zoo object would know to create a get_average_tail_length() method for that instance of the Zoo. Instead of having to keep a list of what average methods I need to make, the Animal-type objects indicate what things can be averaged.
Is there a nice way to get this sort of method generation? Or is there another approach besides getattr() to say "do some computation/work on an a particular property of every member in this list"?
Try this:
import functools
class Zoo:
def __init__(self):
self._animals = []
#classmethod
def make_average_function(cls, func):
setattr(cls, "get_average_{}".format(func.__name__), functools.partialmethod(cls.get_average, propertyname=func.__name__))
return func
def get_average(self, propertyname):
return sum(getattr(x, propertyname) for x in self._animals) / len(self._animals)
class Animal:
def __init__(self, speed, height, length):
self._speed = speed
self._height = height
self._length = length
class Tiger(Animal):
def __init__(self, tail_length):
self._tail_length = tail_length
#property
#Zoo.make_average_function
def tail_length(self):
return self._tail_length
my_zoo = Zoo()
my_zoo._animals.append(Tiger(10))
my_zoo._animals.append(Tiger(1))
my_zoo._animals.append(Tiger(13))
print(my_zoo.get_average_tail_length())
Note: If there are different zoos have different types of animals, it will lead to confusion.
Example
class Bird(Animal):
def __init__(self, speed):
self._speed = speed
#property
#Zoo.make_average_function
def speed(self):
return self._speed
my_zoo2 = Zoo()
my_zoo2._animals.append(Bird(13))
print(my_zoo2.get_average_speed()) # ok
print(my_zoo.get_average_speed()) # wrong
print(my_zoo2.get_average_tail_length()) # wrong
I'm building a simulator, which will model various types of entities. So I've got a base class, ModelObject, and will use subclasses for all the different entities. Each entity will have a set of properties that I want to keep track of, so I've also got a class called RecordedDetail, that keeps tracks of changes (basically builds a list of (time_step, value) pairs) and each ModelObject has a dict to store these in. So I've got, effectively,
class ModelObject(object):
def __init__(self):
self.details = {}
self.time_step = 0
def get_detail(self, d_name):
""" get the current value of the specified RecordedDetail"""
return self.details[d_name].current_value()
def set_detail(self, d_name, value):
""" set the current value of the specified RecordedDetail"""
self.details[d_name].set_value(value, self.time_step)
class Widget(ModelObject):
def __init__(self):
super().__init__(self)
self.details["level"] = RecordedDetail()
self.details["angle"] = RecordedDetail()
#property
def level(self):
return self.get_detail("level")
#level.setter
def level(self, value):
self.set_detail("level", value)
#property
def angle(self):
return self.get_detail("angle")
#angle.setter
def angle(self):
self.set_detail("angle", value)
This gets terribly repetitious, and I can't help thinking there must be a way of automating it using a descriptor, but I can't work out how. I end up with
class RecordedProperty(object):
def __init__(self, p_name):
self.p_name = p_name
def __get__(self, instance, owner):
if instance is None:
return self
return instance.get_detail(self.p_name)
def __set__(self, instance, value):
instance.set_detail(self.p_name, value)
class Widget(ModelObject):
level = RecordedProperty("level")
angle = RecordedProperty("angle")
def __init__(self):
super().__init__(self)
self.details["level"] = RecordedDetail()
self.details["angle"] = RecordedDetail()
which is a bit of an improvement, but still a lot of typing.
So, a few questions.
Can I just add the descriptor stuff (__get__, __set__ etc) into the RecordedDetail class? Would there be any advantage to doing that?
Is there any way of typing the new property name (such as "level") fewer than three times, in two different places?
or
Am I barking up the wrong tree entirely?
The last bit of code is on the right track. You can make the process less nasty by using a metaclass to create a named RecordedProperty and a matching RecordedDetail for every item in a list. Here's a simple example:
class WidgetMeta(type):
def __new__(cls, name, parents, kwargs):
'''
Automate the creation of the class
'''
for item in kwargs['_ATTRIBS']:
kwargs[item] = RecordedProperty(item)
return super(WidgetMeta, cls).__new__(cls, name, parents, kwargs)
class Widget(ModelObject):
_ATTRIBS = ['level', 'angle']
__metaclass__ = WidgetMeta
def __init__(self, *args, **kwargs):
super().__init__(self)
self.Details = {}
for detail in self._ATTRIBS:
self.Details[detail] = RecordedDetail()
Subclasses would then just need to have different data in _ATTRIBS.
As an alternative (I think it's more complex) you could use the metaclass to customize the init in the same way you customize the new, creating the RecordedDetails out of the _ATTRIBS list.
A third option would be to create a RecordedDetail in every instance on first access. That would work fine as long as you don't have code that expects a RecordedDetail for every property even if the RecordedDetail has not been touched.
Caveat I'm not super familiar with Python3; I've used the above pattern often in 2.7x
I have recently stated trying to use the newer style of classes in Python (those derived from object). As an excersise to familiarise myself with them I am trying to define a class which has a number of class instances as attributes, with each of these class instances describing a different type of data, e.g. 1d lists, 2d arrays, scalars etc. Essentially I wish to be able to write
some_class.data_type.some_variable
where data_type is a class instance describing a collection of variables. Below is my first attempt at implementing this, using just a profiles_1d instance and rather generic names:
class profiles_1d(object):
def __init__(self, x, y1=None, y2=None, y3=None):
self.x = x
self.y1 = y1
self.y2 = y2
self.y3 = y3
class collection(object):
def __init__(self):
self._profiles_1d = None
def get_profiles(self):
return self._profiles_1d
def set_profiles(self, x, *args, **kwargs):
self._profiles_1d = profiles_1d(x, *args, **kwargs)
def del_profiles(self):
self._profiles_1d = None
profiles1d = property(fget=get_profiles, fset=set_profiles, fdel=del_profiles,
doc="One dimensional profiles")
Is the above code roughly an appropriate way of tackling this problem. The examples I have seen of using property just set the value of some variable. Here I require my set method to initialise an instance of some class. If not, any other suggestions of better ways to implement this would be greatly appreciated.
In addition, is the way I am defining my set method ok? Generally the set method, as far as I understand, defines what to do when the user types, in this example,
collection.profiles1d = ...
The only way I can correctly set the attributes of the profiles_1d instance with the above code is to type collection.set_profiles([...], y1=[...], ...), but I think that I shouldn't be directly calling this method. Ideally I would want to type collection.profiles = ([...], y1=[...], ...): is this correct/possible?
Finally, I have seen a decorators mentioned alot with repect to the new style of classes, but this is something I know very little about. Is the use of decorators appropriate here? Is this something I should know more about for this problem?
First, it's good you're learning new-style classes. They've got lots of advantages.
The modern way to make properties in Python is:
class Collection(object):
def __init__(self):
self._profiles_1d = None
#property
def profiles(self):
"""One dimensional profiles"""
return self._profiles_1d
#profiles.setter
def profiles(self, argtuple):
args, kwargs = argtuple
self._profiles_1d = profiles_1d(*args, **kwargs)
#profiles.deleter
def profiles(self):
self._profiles_1d = None
then set profiles by doing
collection = Collection()
collection.profiles = (arg1, arg2, arg3), {'kwarg1':val1, 'kwarg2':val2}
Notice all three methods having the same name.
This is not normally done; either have them pass the attributes to collections constructor or have them create the profiles_1d themselves and then do collections.profiles = myprofiles1d or pass it to the constructor.
When you want the attribute to manage access to itself instead of the class managing access to the attribute, make the attribute a class with a descriptor. Do this if, unlike in the property example above, you actually want the data stored inside the attribute (instead of another, faux-private instance variable). Also, it's good for if you're going to use the same property over and over again -- make it a descriptor and you don't need to write the code multiple times or use a base class.
I actually like the page by #S.Lott -- Building Skills in Python's Attributes, Properties and Descriptors.
When creating propertys (or other descriptors) that need to call other instance methods the naming convention is to prepend an _ to those methods; so your names above would be _get_profiles, _set_profiles, and _del_profiles.
In Python 2.6+ each property is also a decorator, so you don't have to create the (otherwise useless) _name methods:
#property
def test(self):
return self._test
#test.setter
def test(self, newvalue):
# validate newvalue if necessary
self._test = newvalue
#test.deleter
def test(self):
del self._test
It looks like your code is trying to set profiles on the class instead of instances -- if this is so, properties on the class won't work as collections.profiles would be overridden with a profiles_1d object, clobbering the property... if this is really what you want, you'll have to make a metaclass and put the property there instead.
Hopefully you are talking about instances, so the class would look like:
class Collection(object): # notice the capital C in Collection
def __init__(self):
self._profiles_1d = None
#property
def profiles1d(self):
"One dimensional profiles"
return self._profiles_1d
#profiles1d.setter
def profiles1d(self, value):
self._profiles_1d = profiles_1d(*value)
#profiles1d.deleter
def profiles1d(self):
del self._profiles_1d
and then you would do something like:
collection = Collection()
collection.profiles1d = x, y1, y2, y3
A couple things to note: the setter method gets called with only two items: self, and the new value (which is why you were having to call set_profiles1d manually); when doing an assignment, keyword naming is not an option (that only works in function calls, which an assignment is not). If it makes sense for you, you can get fancy and do something like:
collection.profiles1d = (x, dict(y1=y1, y2=y2, y3=y3))
and then change the setter to:
#profiles1d.setter
def profiles1d(self, value):
x, y = value
self._profiles_1d = profiles_1d(x, **y)
which is still fairly readable (although I prefer the x, y1, y2, y3 version myself).