storing list/tuples in sqlite database with sqlalchemy - python

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.x
MyObject.y # inconvenient
I can use properties but this solution isn't optimal since I cannot query based on the properties
session.query(MyObject).filter(MyObject.pos==some_pos).all()
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(),
...
)

Related

Modify an attribute of an already defined class in Python (and run its definition again)

I am trying to modify an already defined class by changing an attribute's value. Importantly, I want this change to propagate internally.
For example, consider this class:
class Base:
x = 1
y = 2 * x
# Other attributes and methods might follow
assert Base.x == 1
assert Base.y == 2
I would like to change x to 2, making it equivalent to this.
class Base:
x = 2
y = 2 * x
assert Base.x == 2
assert Base.y == 4
But I would like to make it in the following way:
Base = injector(Base, x=2)
Is there a way to achieve this WITHOUT recompile the original class source code?
The effect you want to achieve belongs to the realm of "reactive programing" - a programing paradigm (from were the now ubiquitous Javascript library got its name as an inspiration).
While Python has a lot of mechanisms to allow that, one needs to write his code to actually make use of these mechanisms.
By default, plain Python code as the one you put in your example, uses the Imperative paradigm, which is eager: whenever an expression is encoutered, it is executed, and the result of that expression is used (in this case, the result is stored in the class attribute).
Python's advantages also can make it so that once you write a codebase that will allow some reactive code to take place, users of your codebase don't have to be aware of that, and things work more or less "magically".
But, as stated above, that is not free. For the case of being able to redefine y when x changes in
class Base:
x = 1
y = 2 * x
There are a couple paths that can be followed - the most important is that, at the time the "*" operator is executed (and that happens when Python is parsing the class body), at least one side of the operation is not a plain number anymore, but a special object which implements a custom __mul__ method (or __rmul__) in this case. Then, instead of storing a resulting number in y, the expression is stored somewhere, and when y is retrieved either as a class attribute, other mechanisms force the expression to resolve.
If you want this at instance level, rather than at class level, it would be easier to implement. But keep in mind that you'd have to define each operator on your special "source" class for primitive values.
Also, both this and the easier, instance descriptor approach using property are "lazily evaluated": that means, the value for y is calcualted when it is to be used (it can be cached if it will be used more than once). If you want to evaluate it whenever x is assigned (and not when y is consumed), that will require other mechanisms. Although caching the lazy approach can mitigate the need for eager evaluation to the point it should not be needed.
1 - Before digging there
Python's easiest way to do code like this is simply to write the expressions to be calculated as functions - and use the property built-in as a descriptor to retrieve these values. The drawback is small:
you just have to wrap your expressions in a function (and then, that function
in something that will add the descriptor properties to it, such as property). The gain is huge: you are free to use any Python code inside your expression, including function calls, object instantiation, I/O, and the like. (Note that the other approach requires wiring up each desired operator, just to get started).
The plain "101" approach to have what you want working for instances of Base is:
class Base:
x = 1
#property
def y(self):
return self.x * 2
b = Base()
b.y
-> 2
Base.x = 3
b.y
-> 6
The work of property can be rewritten so that retrieving y from the class, instead of an instance, achieves the effect as well (this is still easier than the other approach).
If this will work for you somehow, I'd recommend doing it. If you need to cache y's value until x actually changes, that can be done with normal coding
2 - Exactly what you asked for, with a metaclass
as stated above, Python'd need to know about the special status of your y attribute when calculcating its expression 2 * x. At assignment time, it would be already too late.
Fortunately Python 3 allow class bodies to run in a custom namespace for the attribute assignment by implementing the __prepare__ method in a metaclass, and then recording all that takes place, and replacing primitive attributes of interest by special crafted objects implementing __mul__ and other special methods.
Going this way could even allow values to be eagerly calculated, so they can work as plain Python objects, but register information so that a special injector function could recreate the class redoing all the attributes that depend on expressions. It could also implement lazy evaluation, somewhat as described above.
from collections import UserDict
import operator
class Reactive:
def __init__(self, value):
self._initial_value = value
self.values = {}
def __set_name__(self, owner, name):
self.name = name
self.values[owner] = self._initial_value
def __get__(self, instance, owner):
return self.values[owner]
def __set__(self, instance, value):
raise AttributeError("value can't be set directly - call 'injector' to change this value")
def value(self, cls=None):
return self.values.get(cls, self._initial_value)
op1 = value
#property
def result(self):
return self.value
# dynamically populate magic methods for operation overloading:
for name in "mul add sub truediv pow contains".split():
op = getattr(operator, name)
locals()[f"__{name}__"] = (lambda operator: (lambda self, other: ReactiveExpr(self, other, operator)))(op)
locals()[f"__r{name}__"] = (lambda operator: (lambda self, other: ReactiveExpr(other, self, operator)))(op)
class ReactiveExpr(Reactive):
def __init__(self, value, op2, operator):
self.op2 = op2
self.operator = operator
super().__init__(value)
def result(self, cls):
op1, op2 = self.op1(cls), self.op2
if isinstance(op1, Reactive):
op1 = op1.result(cls)
if isinstance(op2, Reactive):
op2 = op2.result(cls)
return self.operator(op1, op2)
def __get__(self, instance, owner):
return self.result(owner)
class AuxDict(UserDict):
def __init__(self, *args, _parent, **kwargs):
self.parent = _parent
super().__init__(*args, **kwargs)
def __setitem__(self, item, value):
if isinstance(value, self.parent.reacttypes) and not item.startswith("_"):
value = Reactive(value)
super().__setitem__(item, value)
class MetaReact(type):
reacttypes = (int, float, str, bytes, list, tuple, dict)
def __prepare__(*args, **kwargs):
return AuxDict(_parent=__class__)
def __new__(mcls, name, bases, ns, **kwargs):
pre_registry = {}
cls = super().__new__(mcls, name, bases, ns.data, **kwargs)
#for name, obj in ns.items():
#if isinstance(obj, ReactiveExpr):
#pre_registry[name] = obj
#setattr(cls, name, obj.result()
for name, reactive in pre_registry.items():
_registry[cls, name] = reactive
return cls
def injector(cls, inplace=False, **kwargs):
original = cls
if not inplace:
cls = type(cls.__name__, (cls.__bases__), dict(cls.__dict__))
for name, attr in cls.__dict__.items():
if isinstance(attr, Reactive):
if isinstance(attr, ReactiveExpr) and name in kwargs:
raise AttributeError("Expression attributes can't be modified by injector")
attr.values[cls] = kwargs.get(name, attr.values[original])
return cls
class Base(metaclass=MetaReact):
x = 1
y = 2 * x
And, after pasting the snippet above in a REPL, here is the
result of using injector:
In [97]: Base2 = injector(Base, x=5)
In [98]: Base2.y
Out[98]: 10
The idea is complicated with that aspect that Base class is declared with dependent dynamically evaluated attributes. While we can inspect class's static attributes, I think there's no other way of getting dynamic expression except for parsing the class's sourcecode, find and replace the "injected" attribute name with its value and exec/eval the definition again. But that's the way you wanted to avoid. (moreover: if you expected injector to be unified for all classes).
If you want to proceed to rely on dynamically evaluated attributes define the dependent attribute as a lambda function.
class Base:
x = 1
y = lambda: 2 * Base.x
Base.x = 2
print(Base.y()) # 4

Python: Modifying an object by assigning it to another object

I'm new to Python (coming from C++), and understand that roughly speaking, all variables (names) are references to Python objects. Some of these objects are mutable (lists), while others aren't (tuples, although you can change its elements if they themselves are mutable).
For mutable objects, I can modify them by accessing their modifier functions (such as .append()) through the name(s) they're bound to. For example:
myList = [1,2,3,4]
myList.append(5)
However, I know that simply assigning myList to a second list just instantiates this second list and reassigns myList to it; The original list [1,2,3,4] still exists, until garbage collection cleans it up (or not if another name is assigned to it).
MY QUESTION:
Lets say I have a Point class:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p1 = Point(1,1)
p1.x = 2
p1.y = 2
How can I replace p1.x = 2 and p1.y = 2 with a single command that just assigns my Point(1,1) object to a Point(2,2) object? Clearly, p1 = Point(2,2) doesn't work as this just reassigns the p1 name to a new and different Point(2,2) object (which is not what I need!).
Is there a built-in way to do this or do I need to define an additional modifier function in Point:
def changePoint(self, newPoint):
self.x = newPoint.x
self.y = newPoint.y
in order to do this in a single command (i.e. via p1.changePoint(Point(2,2)))? In C++ you can often just use a class' implicitly defined overloaded assignment operator (operator=) and accomplish this in a single command:
SimpleNameClass* objectPtr = new SimpleNameClass("Bob");
//Dereferencing objectPtr and assigning new object:
*objectPtr = SimpleNameClass("Jim");
//Now objectPtr still points to (references) the same address in memory,
//but the underlying object is completely different.
Overall, it seems tedious to have to change every attribute individually when I want to transform my object into a new one, especially if my object contains many attributes!
EDIT:
Adding to Jainil's answer, it turns out I don't even need to change the definition of init at all, I can just use the above version. Then, you can transform a Point object to another one with a single command, like so:
p1.__init__(2,2) #Replaces p1.x = 2, p1.y = 2
It works since the original init takes to 2 args. So a standard, vanilla init method basically already enables changing the underlying object, in addition to instantiating it (at least in this case). Yipee.
one way would be to assign using tuple unpacking:
p1.x, p1.y = 2, 2
or you could implement a setter method in your class:
def set_xy(self, x, y):
self.x, self.y = x, y
but creating a new instance (for a class this simple) may make more sense:
p1 = Point(2, 2)
in python you can not override the assignment operator =.
class Point:
def __init__(self, *args):
if(len(args)==2):
self.x = args[0]
self.y = args[1]
elif(len(args)==1):
self.x=args[0].x
self.y=args[0].y
p1 = Point(1,1)
p1.x = 2
p1.y = 2
p1.__init__(Point(3,3))
print(p1.x," ",p1.y)
it is just what you want , but in python way.
in python = can't be overloaded and it is not an operator in python, it is delimeter in python. see https://docs.python.org/3/reference/lexical_analysis.html#delimiters
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def change_point(self, new_x, new_y):
self.x = new_x
self.y = new_y
I'm not sure this is necessarily encouraged, but you can directly modify the __dict__ attribute of the object to modify it. That leads to a solution like:
def assign_to(obj_one, obj_two) -> None:
fields = obj_one.__dict__ # Grab the field/value dictionary of the object
for field_name, field_value in fields.items():
obj_two.__dict__[field_name] = field_value # Loop over obj_one's fields and assign them to obj_two
Then its use:
p1 = Point(1, 2)
p2 = Point(8, 9)
assign_to(p1, p2)
p2.x, p2.y # To show that they were modified
# Prints (1, 2)
id(p1), id(p2) # To show that they're both still distinct objects
# Prints (69029648, 69029296)
This may have drawbacks though, as honestly I've never played around with __dict__ before. You may want to do further research into it before relying on it too heavily.
I'd honestly just write a custom assigning function as the other answers show. Writing an extra line per field shouldn't be too big of a deal; especially given most classes likely won't need such functionality anyways. You're likely just going to be copying PODs like this.

Dynamic Object Naming and Class Calling in Python

I'm developing a programming language in Python where you can program a simulation of simple machines. I have written a function that takes some input, parses it, and finds out what the first word is.
Now, for the first word insert, I need to take the next words obj, name, x, and y.
obj: what type of simple machine it is
name: what you want to call the object
x: X coordinate on the graph
y: Y coordinate on the graph
I have already made a function nextword that iterates through the rest of the code and defines each variable as those words, so with the following code:
insert pulley JohnThePulley 3 4
It sees first word is insert, and calls my insert function.
Then, it sets obj to pulley, name to JohnThePulley, and so on.
However, now I need to make an object in the daughter class pulley, under the mother class simple_machines, that has the name JohnThePulley, etc.
The situation I'm in is that for the first word insert, for example, I don't know at all what the next word will be, from all the choices of daughter classes that they can call. I need to create the specified object along with the provided name, the provided X coordinate and the provided Y coordinate.
I have tried doing simple formatting in python using '{}'.format(name) or .format(obj), but those don't work.
# Insert function
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
objc += 1
return
# Nextword function, code_array[0] is insert, syntax is an array that
# contains all the variables that need to be defined for any function
def nextword(code_array, syntax, c):
assert len(code_array) == c + 1, "Too Many Words!"
for m in range(0, c):
syntax[m] = code_array[m + 1]
return
# Mother Class simple_machines with properties
class simple_machines:
def __init__(self, obj, name, x, y, coords):
self.obj = (
obj
) # what type of obj, in this case, pulley
self.name = name # name, JohnThePulley
self.x = x # 3 in this case
self.y = y # 4 in this case
self.coords = (x, y) # (3,4) in this case
return
# Pulley Class, here so I can later define special properties for a pulley
class pulley(simple_machines):
def __init__(self, name, x, y):
super(simple_machines, self).__init__()
return
# Code that I tried
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
"{}".format(name) = "{}".format(obj)(
name, x, y
) # this is what my
# instantiation would look like, formatting an object with name, then
# calling a class formatted with obj, and inserting their input of
# name,x,y as the properties
return
I expect an object in pulley to be created with the name JohnThePulley, and the coordinates X = 3 and Y = 4. What I'd like to result in, in simpler terms, is an object called name in a class called obj with the attributes name.x, name.y, etc
However, I get errors like:
NameError: name 'obj' is not defined
or:
SyntaxError: can't assign to function call
The first one apparently means that the word obj isn't being assigned, but the second one apparently means that I can't format a function name or format a variable name and define it as a function (even though I'm instantiating it as a class).
What am I doing wrong? How can I fix this?
name 'obj' is not defined is because obj is defined in another function. You have to use MYOBJECT.obj, not obj alone, and also keep a reference to MYOBJECT.
'{}'.format(obj)(name,x,y) doesn't mean anything, '{}'.format(obj) is a string and isn't callable.
SyntaxError: can't assign to function call is the actual problem you seem to be interested in. You could do globals()['{}'.format(name)] = stuff but it doesn't work for local variables and objects (and your linter is not going to like it).
If you want to do the same for objects you can use setattr(MYOBJECT, '{}'.format(name), '{}'.format(obj))
All of the solutions above are in technical terms considered "ugly" and what you're probably looking for is a dictionary, while it isn't OOP, dictionaries are used behind the scenes to handle exactly what you want to do with objects. An object without methods is essentially a just dictionary.
mydico = dict()
mydico[name] = obj
Also, if name is a string, then '{}'.format(name) is equivalent to name.

Purely static classes in Python - Use metaclass, class decorator, or something else?

In part of a program I'm developing I want to perform a linear regression with terms that are some function of a data set X. The exact model used is configurable by the user, particularly which terms (or sets of terms) to use. This involves generating the matrix X' where every row of X' is a function of the corresponding row of X. The columns of X' will be the predictors for my regression.
For example, say my data set is two-dimensional (X has 2 columns). If we denote x and x' as corresponding rows of X and X', then assuming x is two-dimensional x' might be something like
[ 1, x[0], x[1], x[0] * x[1], sqrt(x[0]), sqrt(x[1]), x[0]**2, x[1]**2 ]
You can see these terms come in groups. First is just a 1 (constant), then the untransformed data (linear), then the product of the two data elements (would be all pairwise products if x had more than two dimensions), then square roots and squares of the individual terms.
I need to define all these sets of terms somehow in python, such that each has a user-readable name, function to generate the terms, function to get the number of terms from the dimensions of the input, function to generate labels for the terms based on column labels for the data, etc. Conceptually these all feel like they should be instances of a TermSet class or something similar, but this doesn't quite work because their methods would need to differ. My first thought was to go with something like this:
termsets = {} # Keep track of sets
class SqrtTerms:
display = 'Square Roots' # user-readable name
#staticmethod
def size(d):
"""Number of terms based on input columns"""
return d
#staticmethod
def make(X):
"""Make the terms from the input data"""
return numpy.sqrt(X)
#staticmethod
def labels(columns):
"""List of term labels based off of data column labels"""
return ['sqrt(%s)' % c for c in columns]
termsets['sqrt'] = SqrtTerms # register class in dict
class PairwiseProductTerms:
display = 'Pairwise Products'
#staticmethod
def size(d):
return (d * (d-1)) / 2
#staticmethod
def make(X):
# Some more complicated code that spans multiple lines
...
#staticmethod
def labels(columns):
# Technically a one-liner but also more complicated
return ['(%s) * (%s)' % (columns[c1], columns[c2])
for c1 in range(len(columns)) for c2 in range(len(columns))
if c2 > c1]
termsets['pairprod'] = PairwiseProductTerms
This works: I can retrieve the classes from the dictionary, put the ones I want to use in a list, and call the appropriate methods on each. Still, creating classes with only static attributes and methods seems ugly and unpythonic. Another idea I came up with would be to create a class decorator that could be used like:
# Convert bound methods to static ones, assign "display" static
# attribute and add to dict with key "name"
#regression_terms(name='sqrt', display='Square Roots')
class SqrtTerms:
def size(d):
return d
def make(X):
return numpy.sqrt(X)
def labels(columns):
return ['sqrt(%s)' % c for c in columns]
This gives the same result but is cleaner and much nicer (for myself) to read and write (especially if I need a lot of these). However, the way things actually work under the hood is obscured and anyone else reading this might have a hard idea figuring out what is going on at first. I also thought of creating a metaclass for these but that sounds like overkill. Is there a better pattern I should use here?
Some people will always say that this is an abuse of the language. I say Python was designed to be abusable, and the ability to create DSLs that don't require parsers yet that don't look like lisp is one of its core strengths.
If you really have a lot of these, go with the metaclass. If you do that, in addition to having a term dictionary, you can have attributes that reference the terms, as well. It's really nice, because you can have code like this:
print Terms.termsets
print Terms.sqrt
print Terms.pairprod
print Terms.pairprod.size(5)
return results like this:
{'pairprod': <class '__main__.PairwiseProductTerms'>,
'sqrt': <class '__main__.SqrtTerms'>}
<class '__main__.SqrtTerms'>
<class '__main__.PairwiseProductTerms'>
10
The full code that can do that is here:
from types import FunctionType
class MetaTerms(type):
"""
This metaclass will let us create a Terms class.
Every subclass of the terms class will have its
methods auto-wrapped as static methods, and
will be added to the terms directory.
"""
def __new__(cls, name, bases, attr):
# Auto-wrap all methods as static methods
for key, value in attr.items():
if isinstance(value, FunctionType):
attr[key] = staticmethod(value)
# call types.__new__ to finish the job
return super(MetaTerms, cls).__new__(cls, name, bases, attr)
def __init__(cls, name, bases, attr):
# At __init__ time, the class has already been
# built, so any changes to the bases or attr
# will not be reflected in the cls.
# Call types.__init__ to finish the job
super(MetaTerms, cls).__init__(name, bases, attr)
# Add the class into the termsets.
if name != 'Terms':
cls.termsets[cls.shortname] = cls
def __getattr__(cls, name):
return cls.termsets[name]
class Terms(object):
__metaclass__ = MetaTerms
termsets = {} # Keep track of sets
class SqrtTerms(Terms):
display = 'Square Roots' # user-readable name
shortname = 'sqrt' # Used to find in Terms.termsets
def size(d):
"""Number of terms based on input columns"""
return d
def make(X):
"""Make the terms from the input data"""
return numpy.sqrt(X)
def labels(columns):
"""List of term labels based off of data column labels"""
return ['sqrt(%s)' % c for c in columns]
class PairwiseProductTerms(Terms):
display = 'Pairwise Products'
shortname = 'pairprod'
def size(d):
return (d * (d-1)) / 2
def make(X):
pass
def labels(columns):
# Technically a one-liner but also more complicated
return ['(%s) * (%s)' % (columns[c1], columns[c2])
for c1 in range(len(columns)) for c2 in range(len(columns))
if c2 > c1]
print Terms.termsets
print Terms.sqrt
print Terms.pairprod
print Terms.pairprod.size(5)
If you hide away the metaclass and the base Terms class in a separate module, then nobody has to look at it -- just from baseterm import Terms. You could also do some cool auto-discovery / auto-import where dumping modules in the right directory automatically adds them to your DSL.
With the metaclass, the feature set can easily grow organically as you find other things you would like your mini-language to do.

How do I downcast in python

I have two classes - one which inherits from the other. I want to know how to cast to (or create a new variable of) the sub class. I have searched around a bit and mostly 'downcasting' like this seems to be frowned upon, and there are some slightly dodgy workarounds like setting instance.class - though this doesn't seem like a nice way to go.
eg.
http://www.gossamer-threads.com/lists/python/python/871571
http://code.activestate.com/lists/python-list/311043/
sub question - is downcasting really that bad? If so why?
I have simplified code example below - basically i have some code that creates a Peak object after having done some analysis of x, y data. outside this code I know that the data is 'PSD' data power spectral density - so it has some extra attributes. How do i down cast from Peak, to Psd_Peak?
"""
Two classes
"""
import numpy as np
class Peak(object) :
"""
Object for holding information about a peak
"""
def __init__(self,
index,
xlowerbound = None,
xupperbound = None,
xvalue= None,
yvalue= None
):
self.index = index # peak index is index of x and y value in psd_array
self.xlowerbound = xlowerbound
self.xupperbound = xupperbound
self.xvalue = xvalue
self.yvalue = yvalue
class Psd_Peak(Peak) :
"""
Object for holding information about a peak in psd spectrum
Holds a few other values over and above the Peak object.
"""
def __init__(self,
index,
xlowerbound = None,
xupperbound = None,
xvalue= None,
yvalue= None,
depth = None,
ampest = None
):
super(Psd_Peak, self).__init__(index,
xlowerbound,
xupperbound,
xvalue,
yvalue)
self.depth = depth
self.ampest = ampest
self.depthresidual = None
self.depthrsquared = None
def peakfind(xdata,ydata) :
'''
Does some stuff.... returns a peak.
'''
return Peak(1,
0,
1,
.5,
10)
# Find a peak in the data.
p = peakfind(np.random.rand(10),np.random.rand(10))
# Actually the data i used was PSD -
# so I want to add some more values tot he object
p_psd = ????????????
edit
Thanks for the contributions.... I'm afraid I was feeling rather downcast(geddit?) since the answers thus far seem to suggest I spend time hard coding converters from one class type to another. I have come up with a more automatic way of doing this - basically looping through the attributes of the class and transfering them one to another. how does this smell to people - is it a reasonable thing to do - or does it spell trouble ahead?
def downcast_convert(ancestor, descendent):
"""
automatic downcast conversion.....
(NOTE - not type-safe -
if ancestor isn't a super class of descendent, it may well break)
"""
for name, value in vars(ancestor).iteritems():
#print "setting descendent", name, ": ", value, "ancestor", name
setattr(descendent, name, value)
return descendent
You don't actually "cast" objects in Python. Instead you generally convert them -- take the old object, create a new one, throw the old one away. For this to work, the class of the new object must be designed to take an instance of the old object in its __init__ method and do the appropriate thing (sometimes, if a class can accept more than one kind of object when creating it, it will have alternate constructors for that purpose).
You can indeed change the class of an instance by pointing its __class__ attribute to a different class, but that class may not work properly with the instance. Furthermore, this practice is IMHO a "smell" indicating that you should probably be taking a different approach.
In practice, you almost never need to worry about types in Python. (With obvious exceptions: for example, trying to add two objects. Even in such cases, the checks are as broad as possible; here, Python would check for a numeric type, or a type that can be converted to a number, rather than a specific type.) Thus it rarely matters what the actual class of an object is, as long as it has the attributes and methods that whatever code is using it needs.
See following example. Also, be sure to obey the LSP (Liskov Substitution Principle)
class ToBeCastedObj:
def __init__(self, *args, **kwargs):
pass # whatever you want to state
# original methods
# ...
class CastedObj(ToBeCastedObj):
def __init__(self, *args, **kwargs):
pass # whatever you want to state
#classmethod
def cast(cls, to_be_casted_obj):
casted_obj = cls()
casted_obj.__dict__ = to_be_casted_obj.__dict__
return casted_obj
# new methods you want to add
# ...
This isn't a downcasting problem (IMHO). peekfind() creates a Peak object - it can't be downcast because its not a Psd_Peak object - and later you want to create a Psd_Peak object from it. In something like C++, you'd likely rely on the default copy constructor - but that's not going to work, even in C++, because your Psd_Peak class requires more parameters in its constructor. In any case, python doesn't have a copy constructor, so you end up with the rather verbose (fred=fred, jane=jane) stuff.
A good solution may be to create an object factory and pass the type of Peak object you want to peekfind() and let it create the right one for you.
def peak_factory(peak_type, index, *args, **kw):
"""Create Peak objects
peak_type Type of peak object wanted
(you could list types)
index index
(you could list params for the various types)
"""
# optionally sanity check parameters here
# create object of desired type and return
return peak_type(index, *args, **kw)
def peakfind(peak_type, xdata, ydata, **kw) :
# do some stuff...
return peak_factory(peak_type,
1,
0,
1,
.5,
10,
**kw)
# Find a peak in the data.
p = peakfind(Psd_Peak, np.random.rand(10), np.random.rand(10), depth=111, ampest=222)

Categories

Resources