Developing with Python Class - python

Nothing scares me more than the Python Class concept; and recently I have been trying to use/create classes to understand their purpose, structure and features, etc. However, I am not clear about the concept of class and how to create them.
Please take a look at the following example:
class Prob(object):
def __init__ (self,filename):
self.file_contents = read_file(filename)
def prob_build(self):
self.problem, self.aux_vars = build_problem(file_contents)
first_object = Prob(some_file)
alpha,beta, gamma = first_object.prob_build()
In this case, read_file, build_problem are custom functions that read data from a CSV file and build a PuLP-based linear problem, respectively. Now, my understanding is that when I initialize an object based on my Prob class, the file_contents are available for the class to use internally. In that case, how do I get the variables alpha, beta and gamma? For the current code, I get a TypeError: 'NoneType' object is not iterable. I have tested the functions and I know that they work without any error, which leaves me thinking that there is something wrong with the way I have defined the class.
Any suggestions?

Your prob_build method needs to return three values. You are currently not explicitly returning anything so it implicitly returns the single value None, and Python tries to parse that into three values, and obviously failing.
This has nothing to do with the fact that this is a method of a class; functions return values regardless of how and where they are defined.
It's perfectly okay for functions to not return anything, of course; but then obviously it doesn't produce a result you can obtain with something like variable = func()

Nothing scares me more than the Python Class concept;
This is actually not a Python concept - classes exist in most object oriented languages.
and recently I have been trying (...) to understand their purpose, structure and features, etc. However, I am not clear about the concept of class
Before we talk about classes, you have to understand objects. An object is a way to group together a state (a set of data) and a behavior (a set of functions acting on the state or according to the state). Now this is a bit of an abstract definition so let's see how it works with a simple example - a geometric point in a 2d space.
For the state part, a 2d point is defined by it's x and y coordinates. You can represent this with a dict:
my_point = {"x": 0, "y": 0}
Ok, fine but not very explicit and a bit error prone. We can start with a function that is responsible for creating a new point:
def new_point(x=0, y=0):
return {"x": x, "y": y}
p1 = new_point()
p2 = new_point(42, 84)
Now we can build points without have to worry on the gory details. Ok, now let's a bit of behavior... A first useful function would be to check whether two points are equal (let's say they are equal if they have the same coordinates):
def points_are_equal(p1, p2):
return p1["x"] == p2["x"] and p1["y"] == p2["y"]
You can see that this behavior depends on both points states.
We could also want to move a point along the horizontal axis:
def move_x(p, distance):
p["x"] += distance
or along the vertical axis:
def move_y(p, distance):
p["y"] += distance
or both at the same time:
def move_by(p, x_distance, y_distance):
move_x(p, x_distance)
move_y(p, y_distance)
Notice that here, the behavior is to change the point's state.
And of course we want to have a way to get the point's x or y coordinates:
def get_x(p):
return p["x"]
def get_y(p)
return p["y"]
What we've built here is what is known as an "abstract data type": instead of manually building a dict, manually comparing two dicts, manually updating our dict and manually checking it's state, we have defined a set a function to do all this, more or less hiding the internal representation.
and how to create them.
A class is, mostly, another way to do the same thing, but with a lot of other goodness. Let's rewrite our "point" datatype as a Python class:
class Point(object):
# this is the function that creates a new point
def __init__(self, x=0, y=0):
self.x = x
self.y = y
# equality test:
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# move
def move_x(self, distance):
self.x += distance
def move_y(self, distance):
self.y += distance
def move_by(self, x_distance, y_distance):
And we don't actually need to write get_x() nor get_y(), we can directly access x and y:
p = Point(2, 5)
p.move_by(3, 1)
p2 = Point(p.x, p.y)
print(p == p2) # => True
print(p == p2) # => False
Actually, behind the hood, our p object is a dict:
Other OOPLs might use other ways to store an object's state (structs for C-like languages for example), but in Python an object is actually mainly a dict. Well, a dict plus a class:
and a set of "attribute lookup rules" (provided by the base class object) that will first lookup attributes on the object's __dict__ then on the object's class (which is how p.move_x(42) is actually interpreted as Point.move_x(p, 42).
Classes and objects provide a lot of other goodies (inheritance etc), but basically they are just this: a dict (which stores the state) and a class (which stores the behavior).
Now for your example:
my understanding is that when I initialize an object based on my Prob class, the file_contents are available for the class to use internally
file_contents is available for the instance - and the class functions can access it on the current instance - which is the self parameter. IOW, your build_prob function should use self.file_contents:
def prob_build(self):
self.problem, self.aux_vars = build_problem(self.file_contents)
Then you can access the problem and aux_vars on your instance:
first_object = Prob(some_file)
Just note that the problem and aux_vars attributes only exist after you called prob_build. This is considered as bad practice, since you can get an AttributeError :
first_object = Prob(some_file)
# Doesn't work !!!
A first step to fix this would be to initialize those attributes in the __init__ method (yes, that's why it's called "init"):
class Prob(object):
def __init__ (self,filename):
self.file_contents = read_file(filename)
self.problem = None
self.aux_vars = None
def prob_build(self):
self.problem, self.aux_vars = build_problem(self.file_contents)
but that's hardly better - you still need to call yourobj.prob_build() to have a usable state. The obvious fix here is to do all the initialization in the initializer and get rid of prob_build:
class Prob(object):
def __init__ (self,filename):
self.file_contents = read_file(filename)
self.problem, self.aux_vars = build_problem(self.file_contents)
but then you can ask yourself: what's the point of this class if it has no behavior, and all you do is:
prob = Prob("path/to/file.csv")
prob, aux_vars = prob.problem, prob.aux_vars
result = do_something_with(prob, aux_vars)
You could as well replace it with a simple function:
def build_problem_from_file(path):
return build_problem(read_file(path))
prob, aux_vars = build_problem_from_file(...)
result = do_something_with(prob, aux_vars)
As a general rule, if your class as either no state or no behavior, chances are you don't need a class. There are exceptions to this rule of course but this is still a good guideline. In your case, the hypothetical do_something_with(prob, aux_vars) might be a method too:
class Prob(object):
def __init__ (self,filename):
self.file_contents = read_file(filename)
self.problem, self.aux_vars = build_problem(self.file_contents)
def do_something(self):
# some computations here using self.problem and self.aux_vars
return result
prob = Prob("path/to/file.csv")
result = prob.do_something()
but if that's the only behavior, you still don't need a class:
def build_problem_from_file(path):
return build_problem(read_file(path))
def resolve_problem_from_file(path):
prob, aux_vars = build_problem_from_file(...)
return do_something_with(prob, aux_vars)
result = resolve_problem_from_file(...)
So to make a long story short: ask yourself if and why you want a class. OOP is a good solution for some problems but is not the solution to all problems.

Similar to normal functions, class methods need to return something if you want the results! In your code, prob_build doesn't return anything! So, it should be something like this:
def prob_build(self):
self.problem, self.aux_vars = build_problem(file_contents)
return (self.problem, self.aux_vars)
Note that in this case, it returns two arguments. You should be more specific on what alpha, beta, and gamma are!

Your class function prob_build() does not return anything. It only sets variables internal to the class.


Updating Class Instance Attributes via SuperClass update() method

I'm in the midst of coding a simulation for studying UAV interaction in swarms and obstacle avoidance scenarios. The issue I'm having currently is in getting the vehicles to update their positions. Basically, I have a base class which contains the update() method which does the calculation to arrive at the new position and velocity. The actual objects in the sim code are instances of a subclass of this, and in the subclass's update() method, all I do is update the acceleration vector and call super().update(). However, the values are retained after the function call. I assume this is just a lack of knowledge of Python on my part, as I'm just starting with it (coming from C++ for many years). The searches I've done for pass by reference and such are giving me good information, but so far I can't get an answer to this specific problem. Here's the code:
[EDIT] Per jonrsharpe's request, I've written out a minimal example that encapsulates the problem I'm having. Here's the minimal code:
class UpdateTester:
x = [0,0]
def update(self):
for elem in self.x:
elem += 1
class SubClassTester(UpdateTester):
def update(self):
a = SubClassTester()
for i in range(1,5):
So basically, per my(admittedly limited) understanding, I should get an output which shows increments to the list a.x. However, my output from running this example shows repeated [0,0]'s as output.
Integers are immutable in Python therefore for elem in self.x: elem += 1 does nothing. It doesn't change self.x. If you want to change self.x:
for i, value in enumerate(self.x):
self.x[i] = value + 1
Also UpdateTester.x is a class variable. It is the same for all instances. Lists are mutable in Python therefore if you call .update() on any instance of UpdateTester class then you change the list for all of them. To create per instance list instead, put it in __init__():
class UpdateTester(object):
def __init__(self, **kwargs):
super(UpdateTester, self).__init__(**kwargs) # for multiple inheritence
self.x = []

Self in python Class - I can do it with out it…? [duplicate]

This question already has an answer here:
Why do you need explicitly have the “self” argument into a Python method?
8 answers
Consider this code:
class example(object):
def __init__ (): # No self
test() # No self
def test(x,y): # No self
return x+y
def test1(x,y): # No self
return x-y
This works as expected. I believe I can write a whole program not using self. What am I missing? What is this self; why is it needed in some practical way?
I have read a lot about it - (stack, Python documentation), but I just don't understand why it's needed, since I can obviously create a program without it.
You haven't utilised a class or object properly. Cutting out the garbage code, your program reduces to:
def test(x,y): #No class
return x+y
def test1(x,y): #No class
return x-y
Your "class" is no more useful than if you wrapped your program in the nested structures:
if True:
for i in range(1):
A proper object will have attributes (data fields) and functions that operate on that data (see below). Your code has an empty object; hence, you have nothing on which to operate, no need for self, and no need for a class at all.
Rather, use a class when you need to encapsulate a data representation and associated operations. Below, I've reused some of your code to make example do some trivial complex number work. There are many extensions and improvements to make in this; I kept it relatively close to your original work.
class example(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
sign = ' + ' if self.b >= 0 else ' - '
return str(self.a) + sign + str(abs(self.b)) + 'i'
def add(self, x):
self.a += x.a
self.b += x.b
def sub(self, x):
self.a -= x.a
self.b -= x.b
complex1 = example(10, 5)
complex2 = example(-3, 2)
7 + 7i
-10 - 5i
Are you familiar with Object-Oriented Paradigm?
If you don't you should check it. Python is a Object-Oriented Language and self lets you define your object properties.
An example:
You have a class named Vehicle. A vehicle could be a bike, a car, even a plane. So something you can include is a name and a type.
class Vehicle():
def init(self, name, type): # Constructor = name
self.type = type
def info(self):
print("I'm a ")
That's all, now you have a vehicle with name and type. Every instance of Vehicle would have a name and a type different or not and every intance can access its own variables. I'm sorry I can't explain it better. Firstable you need to know Object-Oriented Paradigm knowledge. Please comment my answer if you have doubts & I'll answer you or give a link where it comes explained better.
You can perfectly create a program without it. But then you'd be missing one of the key features of classes. If you can do without self, I'd argue you can do without classes and just do something purely with functions :)
Classes allow you to create objects which have a PROPERTY associated to them, and self allows you to access those values. So say you have a square.
g code:
class Square(object):
def __init__ (self, length, height):
self.length = length # THIS square's length, not others
self.height = height # THIS square's height, not other
def print_length_and_height(self):
print(self.length, self.height) # THIS square's length and height
square1 = Square(2,2)
square2 = Square(4,4)
square1.print_length_and_height() # 2 2
square2.print_length_and_height() # 4 4
Now, this example is quite silly, of course, but i think it shows what SELF specifically is for: it refers to the particular instance of an object.
By all means, if you don't see the point to it, just do away with classes and just use functions, there nothing wrong with that.

Bind the instance argument of a descriptor method to the calling object instance

In a descriptor, the second argument to __get__ and __set__ is bound to the calling object instance (and the third argument to __get__ is bound to the calling owner class object):
class Desc():
def __get__(self,instance,owner):
print("I was called by",str(instance),"and am owned by",str(owner))
return self
class Test():
desc = Desc()
t = Test()
How would I go about creating a decorator to bind the second argument of another descriptor method (other than __get__, __set__, or __delete__) to the instance object?
Example (just an example; not something I'm actually trying to do):
class Length(object):
'''Descriptor used to manage a basic unit system for length'''
conversion = {'inches':1,'centimeters':2.54,'feet':1/12,'meters':2.54/100}
def __set__(self,instance,length):
'''length argument is a tuple of (magnitude,unit)'''
instance.__value = length[0]
instance.__units = length[1]
def __get__(self,instance,owner):
return self
def get_in(self, instance, unit): #second argument is bound to instance object
'''Returns the value converted to the requested units'''
return instance.__value * (self.conversion[units] / self.conversion[instance.__units])
class Circle(object):
diameter = Length()
def __init__(self,diameter,units):
c = Circle(12,'inches')
assert c.diameter.get_in('feet') == 1
c.diameter = (1,'meters')
assert c.diameter.get_in('centimeters') == 100
One way I have considered trying is wrapping the get_in method with a decorator. Something similar is done using the #classmethod decorator, where the first argument of a class method is bound to the class object instead of the class instance object:
class Test():
def myclassmethod(klass):
t = Test()
However, I'm unsure how to apply this to the case above.
A way to avoid the whole problem would be to pass the instance object to the descriptor method explicitly:
c = Circle(12,'inches')
assert c.diameter.get_in(c,'feet') == 1
c.diameter = (1,'meters')
assert c.diameter.get_in(c,'centimeters') == 100
However, this seems to violate D.R.Y., and is really ugly to boot.
There is a hook left in the Descriptor protocol for this sort of thing -- namely, when the Descriptor object is accessed from the class level, the value of instance will be None.
It's useful to think about this in the reverse direction. Let's start with Circle:
class Circle(object):
diameter = Length()
def __init__(self, diameter, units):
self.diameter = (diameter, units)
Notice that instead of trying to manually call __set__ or call things from the class level (e.g. by invoking from Circle directly) -- I am just using the descriptor as it is intended, simply setting a value.
Now, for the descriptor, virtually everything will be the same. I cleaned up the code style for the conversion dict.
But for __get__ I add the extra check for whenever instance == None. This will be the case whenever Circle.diameter is accessed, as opposed to c.diameter for some c that is an instance of Circle. Make sure you feel comfortable with the difference.
class Length(object):
conversion = {'inches':1.0,
def __set__(self, instance, length):
instance.__value = length[0]
instance.__units = length[1]
def __get__(self, instance, owner):
if instance is None:
return self
return (instance.__value, instance.__units)
def get_in(self, instance, units):
c_factor = self.conversion[units] / self.conversion[instance.__units]
return (c_factor * instance.__value, units)
Now, we can get a hold of the actual Length instance that lives inside of .diameter ... but only if we access .diameter hanging off of Circle (the class itself) and not any instances of that class.
# This works and prints the conversion for `c`.
c = Circle(12, 'inches')
Circle.diameter.get_in(c, 'feet')
# This won't work because you short-circuit as soon as you type `c.diameter`
One option to avoid needing to go outside of the instance is to monkey-patch a function that utilizes the __class__ attribute:
class Circle(object):
diameter = Length()
def __init__(self, diameter, units):
self.diameter = (diameter, units)
self.convert = lambda attr, units: (
getattr(self.__class__, attr).get_in(self, units)
Now the instance c can work like this:
>>> c.convert('diameter', 'feet')
(1.0, 'feet')
You could instead define convert as an instance method (e.g. with the usual self first argument), or you could do it with decorators, or metaclasses, ... etc.
But at the end of the day, you still need to be very careful. On the surface this looks attractive, but really you are adding a lot of coupling between your objects. It superficially might look like you're separating the concerns about unit conversion away from the object's concerns about "being a Circle" -- but really you're adding layers of complexity that other programmers will have to sort out. And you're marrying your class to this particular Descriptor. If someone determines in a refactoring that diameter conversion is better as a function wholly outside of the Circle object, they now suddenly have to worry about accurately accounting for all of the moving parts of Length when they do the refactoring.
At the end of the day, you also have to ask what this buys you. As far as I can tell, in your example it doesn't buy anything except the very minor convenience of being able to induce conversion calculation as part of the so-called "fluent interface" design style ... e.g. side-effects and function calls appear like they are merely attribute accesses.
Personally, I dislike this kind of syntax. I'd much rather use a style like
convert(c.diameter, 'feet')
Functions like the first version usually live at a module level, and they can be generalized over the types which they will operate on. They can be extended to handle new types more easily (and you can encapsulate them into their own separate classes if you want inheritance on the functions). Usually, they are also easier to test because vastly less machinery is needed to invoke them, and the testing mock objects can be simpler. In fact, in a dynamically typed language like Python, allowing a function like convert to work based on duck typing is typically one of the major virtues of the language.
This is not to say one way is definitely better than the other. A good designer could find merits in either approach. A bad designer could make a mess out of either approach. But in general, I find that when these exceptional corners of Python are used to solve unexceptional, regular problems, it often leads to a confused mess.
Thanks to prpl.mnky.dshwshr's help, I was able to vastly improve this entire approach (and learn a lot about descriptors in the process).
class Measurement():
'''A basic measurement'''
def __new__(klass,measurement=None,cls_attr=None,inst_attr=None,conversion_dict=None):
'''Optionally provide a unit conversion dictionary.'''
if conversion_dict is not None:
klass.conversion_dict = conversion_dict
return super().__new__(klass)
def __init__(self,measurement=None,cls_attr=None,inst_attr=None,conversion_dict=None):
'''If object is acting as a descriptor, the name of class and
instance attributes associated with descriptor data are stored
in the object instance. If object is not acting as a descriptor,
measurement data is stored in the object instance.'''
if cls_attr is None and inst_attr is None and measurement is not None:
#not acting as a descriptor
self.__measurement = measurement
elif cls_attr is not None and inst_attr is not None and measurement is None:
#acting as a descriptor
self.__cls_attr = cls_attr
self.__inst_attr = inst_attr
#make sure class and instance attributes don't share a name
if cls_attr == inst_attr:
raise ValueError('Class and Instance attribute names cannot be the same.')
raise ValueError('BOTH or NEITHER the class and instance attribute name must be or not be provided. If they are not provided, a measurement argument is required.')
##Descriptor only methods
def __get__(self,instance,owner):
'''The measurement is returned; the descriptor itself is
returned when no instance supplied'''
if instance is not None:
return getattr(instance,self.__inst_attr)
return self
def __set__(self,instance,measurement):
'''The measurement argument is stored in inst_attr field of instance'''
##Other methods
def get_in(self,units,instance=None):
'''The magnitude of the measurement in the target units'''
#If Measurement is not acting as a descriptor, convert stored measurement data
return convert( self.__measurement,
except AttributeError:
#If Measurement is acting as a descriptor, convert associated instance data
return convert( getattr(instance,self.__inst_attr),
except Exception:
def to_tuple(self,instance=None):
return self.__measurement
except AttributeError:
return getattr(instance,self.inst_attr)
class Length(Measurement):
conversion_dict = {
class Mass(Measurement):
conversion_dict = {
def convert(measurement, units, dimension_conversion = None):
'''Returns the magnitude converted to the requested units
using the conversion dictionary in the provide dimension_conversion
object, or using the provided dimension_conversion dictionary.
The dimension_conversion argument can be either one.'''
#If a Measurement object is provided get measurement tuple
if isinstance(measurement,Measurement):
#And if no conversion dictionary, use the one in measurement object
if dimension_conversion is None:
dimension_conversion = measurement.conversion_dict
measurement = measurement.to_tuple()
#Use the dimension member [2] of measurement tuple for conversion if it's there
if dimension_conversion is None:
dimension_conversion = measurement[2]
except IndexError:
#Get designated conversion dictionary
conversion_dict = dimension_conversion.conversion_dict
except AttributeError:
conversion_dict = dimension_conversion
#Get magnitude and units from measurement tuple
meas_mag = measurement[0]
meas_units = measurement[1]
except (IndexError,TypeError):
raise TypeError('measurement argument should be indexed type with magnitude in measurement[0], units in measurement[1]') from None
#Finally perform and return the conversion
return meas_mag * (conversion_dict[units] / conversion_dict[meas_units])
except IndexError:
raise IndexError('Starting and ending units must appear in dimension conversion dictionary.') from None
class Circle():
diameter = Length(cls_attr='diameter',inst_attr='_diameter')
def __init__(self,diameter):
self.diameter = diameter
class Car():
mass = Mass(cls_attr='mass',inst_attr='_mass')
def __init__(self,mass):
self.mass = mass
c = Circle((12,'inches'))
assert convert(c.diameter,'feet',Length) == 1
assert Circle.diameter.get_in('feet',c) == 1
assert c.diameter == (12,'inches')
d = Circle((100,'centimeters',Length))
assert convert(d.diameter,'meters') == 1
assert Circle.diameter.get_in('meters',d) == 1
assert d.diameter == (100,'centimeters',Length)
x = Length((12,'inches'))
assert x.get_in('feet') == 1
assert convert(x,'feet') == 1

Python class Inheritance Initialization

I have the following example setup:
class Feet:
def __init__ (self, value = 0.0):
self.value = value
self.units = "f"
def feet(self):
return self.value
class Meters:
def __init__(self, value = 0.0):
self.value = value
self.units = "m"
def feet(self):
# This is probably not an accurate conversion.
return self.value * 2.54 * 10
class Distance (Feet, Meters):
def __init__(self, type = Feet()):
print type.feet() -- Prints 254.0
self = type
print self.feet() -- Prints 254.0
dist = Distance(Meters(10.0))
print dist.units -- Prints = "m"
print dist.value -- Prints = 0.0
print dist.feet() -- Prints = 0.0
I can't seem to understand why when I initialize the class to a Meters Class type, and assign it 10.0, I don't keep the 10.0. However the Units seem to have stayed correct. Am I missing something about how this is being setup?
My understanding is that I'm creating an "instance" of Meters, and assigning it to the "self" variable of Distance. If the self value couldn't be modified I could understand if my units was "f", but my units is "m" so it's obviously assigning the Meters class to self, but it's not taking the instantiated values, which I find quite odd.
To be honest I don't even know what I would google in this case, so I apologize I haven't done a whole lot of googling, most of what I found didn't apply at all to this type of problem.
Additionally, my plan was to basically "cast" it to the same type no matter what you passed in, for example for feet I would return the self instance for the Feet class, and in the Meters class I would return Feet(self.Value * 2.54 * 10) so I would always have my distance in Feet.
so for Feet feet becomes
def feet(self):
return self
for Meters feet becomes
def feet(self):
return Feet(self.value * 2.54 * 10)
To Recap, is there a reason that I'm able to pass in 1 of 2 classes as part of initialization, but it doesn't take my initialization parameters for that class?
It's really unclear to me why I can assign "self" in the distance class, and before it returns it appears to have the right initialization but upon returning it doesn't work right.
The thing is that you are inheriting from 2 classes Feet and Meters. Both classes have the same methods. In your Distance.__init__() method, you are overriding Feet's methods with Meters' methods when doing this:
What I would have done differently:
class Distance(object):
def __init__(self, meters=None, feet=None):
self.feet = feet
self.meters = meters
Then you can do something like:
distance = Distance(meters=Meters(12))
print distance.meters.value
print distance.meters.type
# Here do whatever you want with them
You can pass in the two objects at the same time. And do some other stuff with
the two objects if the are both different than None.
There's absolutely no reason to inherit from either Feet or Meters here, let alone both. This is a classic case of composition, rather than inheritance, especially since you are passing the units class as a parameter. Remove that subclassing, and in __init__ you can do self.type = type.
Other answers cover the problems you have with inheriting, but haven't covered your rebinding of self.
Inside a method (such as __init__), self is simply a local name bound to the instance. You are perfectly at liberty to rebind the name, but that simply makes self refer to something else. It doesn't affect the instance.
In this case, when __init__ returns the self name goes out of scope, but the original instance is assigned to dist just as though you hadn't rebound the name self.
Note that __init__ is an initializer, not a constructor. Python does also allow you to define a custom constructor for a class (__new__), and the constructor can change the object that is returned. However you don't need to use it here.
This line:
self = type
doesn't do what you think it does. You think this is an assignment statement, in which the object refered to by self takes on the attributes of type, a la C++.
Python doesn't have assignments in the same sense that other languages have.
What that line does is to bind the local name self to the object to which type is currently bound. It has absolutely no effect outside of Distance.__init__(), and virtually no effect on the object to which self was previously bound.

storing list/tuples in sqlite database with sqlalchemy

I have a class that holds the size and position of something I draw to the screen. I am using sqlalchemy with a sqlite database to persist these objects. However, the position is a 2D value (x and y) and I'd like to have a convienent way to access this as
MyObject.pos # preferred, simpler interface
# instead of:
MyObject.y # inconvenient
I can use properties but this solution isn't optimal since I cannot query based on the properties
Is there some way to use collections or association proxies to get the behavior I want?
If you are using PostGIS (Geometry extended version of postgres), you can take advantage of that using GeoAlchemy, which allows you to define Column types in terms of geometric primitives available in PostGIS. One such data type is Point, which is just what it sounds like.
PostGIS is a bit more difficult to set up than vanilla PostgreSQL, but if you actually intend to do queries based on actual geometric terms, it's well worth the extra (mostly one time) trouble.
Another solution, using plain SQLAlchemy is to define your own column types with the desired semantics, and translate them at compile time to more primitive types supported by your database.
Actually, you could use a property, but not with the builtin property decorator. You'd have to have to work a little harder and create your own, custom descriptor.
You probably want a point class. A decent option is actually to use
a namedtuple, since you don't have to worry about proxying assignment
of individual coordinates. The property gets assigned all or nothing
Point = collections.namedtuple('Point', 'x y')
This would let us at least compare point values. The next step in
writing the descriptor is to work through its methods. There are two methods to think about, __get__
and __set__, and with get, two situations, when called on
an instance, and you should handle actual point values, and when
called on the class, and you should turn it into a column expression.
What to return in that last case is a bit tricky. What we want is something
that will, when compared to a point, returns a column expression that equates
the individual columns with the individual coordinates. well make one more
class for that.
class PointColumnProxy(object):
def __init__(self, x, y):
''' these x and y's are the actual sqlalchemy columns '''
self.x, self.y = x, y
def __eq__(self, pos):
return sqlalchemy.and_(self.x == pos.x,
self.y == pos.y)
All that's left is to define the actual descriptor class.
class PointProperty(object):
def __init__(self, x, y):
''' x and y are the names of the coordinate attributes '''
self.x = x
self.y = y
def __set__(self, instance, value):
assert type(value) == Point
setattr(instance, self.x, value.x)
setattr(instance, self.y, value.y)
def __get__(self, instance, owner):
if instance is not None:
return Point(x=getattr(instance, self.x),
y=getattr(instance, self.y))
else: # called on the Class
return PointColumnProxy(getattr(owner, self.x),
getattr(owner, self.y))
which could be used thusly:
Base = sqlalchemy.ext.declarative.declarative_base()
class MyObject(Base):
x = Column(Float)
y = Column(Float)
pos = PointProperty('x', 'y')
Define your table with a PickleType column type. It will then automatically persist Python objects, as long as they are pickleable. A tuple is pickleable.
mytable = Table("mytable", metadata,
Column('pos', PickleType(),