using __class__ to change python class, Heap Error - python

I am trying to make an class = that extends from list return a slice of itself instead of a list type. The reason I want to do this is because I have many other methods to manipulate the instance of A.
I am running python 2.7.3
Say I have:
class B():
def __init__(self, t, p):
self.t = t
self.p = p
class Alist(list):
def __init__(self, a_list_of_times = []):
for a_time in a_list_of_times:
self.append(a_time )
def __getslice__(self, i, j):
return super(Alist, self).__getslice__(i,j)
def plot_me(self):
pass
# other code goes here!
alist1 = Alist()
for i in range(0, 1000000):
alist1.append(B(i, i)) # yes ten million, very large list!
alist = alist1[1000:200000] # will return a list!
alist2 = Alist(alist) # will return Alist istance
The problem is that remaking the entire list as seen in making variable b is VERY VERY SLOW (comparative to the slice). What I want to do is simply change the class of alist (currently of type list)to Alist
When I try:
alist.__class__ = Alist
>>>> TypeError: __class__ assignment: only for heap types.
Which is very sad since I can do this for my own object types.
I understand that it is not standard, but it is done.
Reclassing an instance in Python.
Is there a way around this? Also I have obviously simplified the problem, where my objects a bit more complex. Mainly what I am finding is that remaking the list into my Alist version is slow. And I need to do this operation a lot (unavoidable). Is there a way to remake A? or a solution to this to make it speed up?
In my version, I can do about a 10,000 (size of my slice) slice in 0.07 seconds, and converting it to my version of Alist takes 3 seconds.

The UserList class (moved to collections in Python 3) is perfectly designed for this. It is a list by all other means but has a data attribute that you can store an underlying list in without copying.
from UserList import UserList
class Alist(UserList):
def __init__(self, iterable, copy=True):
if copy:
super(Alist, self).__init__(iterable)
else:
self.data = iterable
def plot_me(self):
pass

Related

How do I read a list that is located within another class?

In Python I have a for loop which calls a class, which in turn calls another class and so on, with classes manipulating data, performing sql inserts etc. The final class contains a list of all the files which have been created. I want to access this list from outside the class but I cannot work out how to!
(I know there is also a loop issue-will explain more below!)
A basic example is:
#A class to create the list
class Create_list():
def list(self,j):
l=j+1
#pass this variable to another class, get_list
Get_list().input(l)
#class get_list receives the number from create_list and appends it to mylist
class Get_list():
def input(self,l):
mylist=[]
mylist.append(l)
#print mylist
# loop through a list of numbers and feed them into the create_list class
j=10
for k in range(j):
Create_list().list(k)
#I want to access the list here. I have tried all of the below
readlist=Get_list().input().mylist # with ()
readlist=Get_list.input.mylist # without ()
x=Create_list() # create an object with class name
mylist=x.list().mylist #use above object
I have tried all the approaches in the last block of code.
I can't use the first two as the function list requires an input, which comes from the preceding class. (the error says that list() requires two arguments, only one is provided (self I assume)).
I have tried assigning the class to an object but this too does not work.
I realise that the for loop means that if I were to print mylist within def input there is only the value from that value of j.
I basically would like to access mylist, which has a list of values (l) from all of the values in j after that for loop has run.
Lots of stuff is wrong here so I'll just show a simple way to do it:
class Create_list(object):
def __init__(self):
self.list = []
def input_list(self, x):
l = x + 1
self.list.append(l)
j=10
cl = Create_list()
for k in xrange(j):
cl.input_list(k)
print cl.list
Another possibility is to return the list:
def add_one_to(j):
l=j+1
return(l)
def store(mylist, l):
mylist.append(l)
return(mylist)
Usage:
>>> mylist = []
>>> myintegerplusone = add_one_to(1)
>>> store(mylist, myintegerplusone)
>>> print(mylist)
[2]
In that case you could imagine a function as a craftsman, you give him something to fix/manipulate and he then returns the fixed/manipulated good back to you.
I think what you want is to store inside the class object the list using the "self" method and then access it from outside.
Try this code:
class CreateList():
def __init__(self):
self.list = []
if __name__ == "__main__":
c = CreateList()
c.list.append(4)
print c.list

Python nested Classes - returning multiple values

I'm fairly new to classes in python, so please be gentle. My script is a tad more complicated than this, but this is essentially what it boils down to:
class primary_state:
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
self.substates=[]
def add_substate(self,i,j,k):
self.substates.append(self.substate(i,j,k))
class substate:
def __init__(self,i,j,k):
self.i = i
self.j = j
self.k = k
state = primary_state(1,2,3)
state.add_substate(4,5,6)
state.add_substate(7,8,9)
Now my question is: is it possible to return an array of values from each object? So for example I'd like to do:
state.substates[:].i
and have it return the values of 4 and 7, but alas substates is a list so it can't handle it. There also must be a more efficient way to do this but I haven't quite figured that out yet. Any advice/thoughts would be greatly appreciated! Thanks.
Use a list comprehension.
[sub.i for sub in state.substates]
This is roughly equivalent to the following:
x = []
for sub in state.substates:
x.append(sub.i)
except shorter, and it's an expression that you can embed in other expressions instead of a series of statements.
You can get the list of substates by calling:
[substate.i for substate in self.substates]
list comprehensions are the way to do it as the other answers point out.
If the only job of the primary state class is to hold subclasses, you can make your class behave like an iterable. In the example you give this is mostly syntactic sugar, but it can be useful. Complete instructions on how to do it are here but it's pretty simple:
class PrimaryState(object): #always use "new style" classes! its 2013!
def __init__(self,x,y,z):
self.x = x
self.y = y
self.z = z
self.substates=[]
def __len__(self):
return len(self.substates)
def __getitem__(self, index):
return self.substates[index]
def __iter__(self):
for sub in substates: yield sub
def __contains__(self, item):
return item in self.substates
def add(self, item):
self.substates.append(item)
This way you can do:
primary = PrimaryState(1,2,3)
primary.add(SubState(4,5,6))
primary.add(SubState(7,8,9))
for item in primary:
print item
# Substate 4,5,6
# Substate 7,8,9
PS: Check out PEP-8, the standard python style guide for naming classes and so on. And use new style classes (inheriting from object). Down the road it's important!

Python inspect iterable in __new__ method

I'm trying to write a python (2.7) matrix module. (I know about numpy, this is just for fun.)
My Code:
from numbers import Number
import itertools
test2DMat = [[1,2,3],[4,5,6],[7,8,9]]
test3DMat = [[[1,2,3],[4,5,6],[7,8,9]],[[2,3,4],[5,6,7],[8,9,0]],[[9,8,7],[6,5,4],[3,2,1]]]
class Dim(list):
def __new__(cls,inDim):
# If every item in inDim is a number create a Vec
if all(isinstance(item,Number) for item in inDim):
#return Vec(inDim)
return Vec.__new__(cls,inDim)
# Otherwise create a Dim
return list.__new__(cls,inDim)
def __init__(self,inDim):
# Make sure every item in inDim is iterable
try:
for item in inDim: iter(item)
except TypeError:
raise TypeError('All items in a Dim must be iterable')
# Make sure every item in inDim has the same length
# or that there are zero items in the list
if len(set(len(item) for item in inDim)) > 1:
raise ValueError('All lists in a Dim must be the same length')
inDim = map(Dim,inDim)
list.__init__(self,inDim)
class Vec(Dim):
def __new__(cls,inDim):
if cls.__name__ not in [Vec.__name__,Dim.__name__]:
newMat = list.__new__(Vec,inDim)
newMat.__init__(inDim)
return newMat
return list.__new__(Vec,inDim)
def __init__(self,inDim):
list.__init__(self,inDim)
class Matrix(Dim):
def __new__(cls,inMat):
return Dim.__new__(cls,inMat)
def __init__(self,inMat):
super(Matrix,self).__init__(inMat)
Current Functionality:
So far I have written a few classes, Matrix, Dim, and Vec. Matrix and Vec are both subclasses of Dim. When creating a matrix, one would first start out with a list of lists and they would create a matrix like:
>>> startingList = [[1,2,3],[4,5,6],[7,8,9]]
>>> matrix.Matrix(startingList)
[[1,2,3],[4,5,6],[7,8,9]]
This should create a Matrix. The created Matrix should contain multiple Dims all of the same length. Each of these Dims should contain multiple Dims all of the same length, etc. The last Dim, the one that contains numbers, should contain only numbers and should be a Vec instead of a Dim.
The Problem:
All of this works, for lists. If I were however, to use an iterator object instead (such as that returned by iter()) this does not function as I want it to.
For example:
>>> startingList = [[1,2,3],[4,5,6],[7,8,9]]
>>> matrix.Matrix(iter(startingList))
[]
My Thoughts:
I'm fairly certain that this is happening because in Dim.__new__ I iterate over the input iterable which, when the same iterable is then passed to Matrix.__init__ it has already been iterated over and will therefore appear to be empty, resulting in the empty matrix that I get.
I have tried copying the iterator using itertools.tee(), but this also doesn't work because I don't actually call Matrix.__init__ it gets called implicitly when Matrix.__new__ returns and I therefore cannot call it with different parameters than those passed to Matrix.__init__. Everything I have thought of to do comes up against this same problem.
Is there any way for me to preserve the existing functionality and also allow matrix.Matrix() to be called with an iterator object?
The key is that Vec.__init__ is getting called twice; once inside your __new__ method and once when you return it from the __new__ method. So if you mark it as already initialised and return early from Vec.__init__ if it is already initialised, then you can ignore the second call:
class A(object):
def __new__(cls, param):
return B.__new__(cls, param + 100)
class B(A):
def __new__(cls, param):
b = object.__new__(B)
b.__init__(param)
return b
def __init__(self, param):
if hasattr(self, 'param'):
print "skipping __init__", self
return
self.param = param
print A(5).param
What you would need to do is check if the variable that is passed in is a tuple or list. If it is then you can use it directly, otherwise you need to convert the iterator into a list/tuple.
if isinstance(inDim, collections.Sequence):
pass
elif hastattr(inDim, '__iter__'): # this is better than using iter()
inDim = tuple(inDim)
else:
# item is not iterable
There is also a better way of checking that the length of all the lists are the same:
if len(inDim) > 0:
len_iter = (len(item) for item in inDim)
first_len = len_iter.next()
for other_len in len_iter:
if other_len != first_len:
raise ValueError('All lists in a Dim must be the same length')

Returning an lvalue from a function in python

[Sorry, I'm new in Python. Although it seems to be a very basic question, I did my share of due diligence before asking this audience, trying to avoid really stupid questions].
I'm trying to figure out the correct idiom for returning an l-value from a function. Assume I've a container of 64 objects, and I want to be able to return a reference to these objects.
class ChessBoard:
def __init__(self):
self.squares = [None for x in range(64)]
square( row, col ):
return self.squares(row*8+col) <---- I'd like this to be l-value
Then, from outside the class I want to:
board = ChessBoard()
board.square(0,0) = Piece( Shapes.ROOK, Colors.White ) <-- I'm getting an error here
board.square(0,1) = Piece( Shapes.BISHOP, Colors.White )
... etc.
So, I would like the function 'at' to return a lvalue (Something like a reference in C++), but I can't find anything resembling a reference or a pointer in the language. If I stored a list in each square containing one Piece, it is possible I could do something like: board.square(0,0)[0] = Piece - but it seems crazy (or maybe not - as I said, I'm new to the language).
How would you approach this data structure?
In Python, everything is a reference. The only problem is that None is immutable, so you can't use the returned reference to change the value.
You also can't override the assignment operator, so you won't get this particular kind of behaviour. However, a good and very flexible solution would be to override the __setitem__ and __getitem__ methods to implement the subscription operator ([]) for the class:
class ChessBoard(object):
def __init__(self):
self.squares = [None] * 64
def __setitem__(self, key, value):
row, col = key
self.squares[row*8 + col] = value
def __getitem__(self, key):
row, col = key
return self.squares[row*8 + col]
Usage:
>>> c = ChessBoard()
>>> c[1,2] = 5
>>> c[1,2]
5
You can try something like this, at the cost of having to put bogus [:] indexers around:
class Board:
def __init__(self):
self.squares=[None for x in range(64)]
def square(self, row, col):
squares=self.squares
class Prox:
def __getitem__(self, i):
return squares[row*8+col]
def __setitem__(self, i, v):
squares[row*8+col]=v
return Prox()
Then you can do
b=Board()
b.square(2,3)[:]=Piece('Knight')
if b.square(x,y)[:] == Piece('King') ...
And so on. It doesn't actually matter what you put in the []s, it just has to be something.
(Got the idea from the Proxies Perl6 uses to do this)
As Niklas points out, you can't return an l-value.
However, in addition to overriding subscription, you can also use properties (an application of descriptors: http://docs.python.org/howto/descriptor.html) to create an object attribute, which when read from, or assigned to, runs code.
(Not answering your question in the title, but your "How would you approach this data structure?" question:) A more pythonic solution for your data structure would be using a list of lists:
# define a function that generates an empty chess board
make_chess_board = lambda : [[None for x in xrange(8)] for y in xrange(8)]
# grab an instance
b = make_chess_board()
# play the game!
b[0][0] = Piece(Shapes.ROOK, Colors.White)
b[0][1] = Piece(Shapes.BISHOP, Colors.White)
# Or use tuples:
b[0][0] = (Shapes.ROOK, Colors.White)
b[0][1] = (Shapes.BISHOP, Colors.White)

How to subclass Python list without type problems?

I want to implement a custom list class in Python as a subclass of list. What is the minimal set of methods I need to override from the base list class in order to get full type compatibility for all list operations?
This question suggest that at least __getslice__ needs to be overridden. From further research, also __add__ and __mul__ will be required. So I have this code:
class CustomList(list):
def __getslice__(self,i,j):
return CustomList(list.__getslice__(self, i, j))
def __add__(self,other):
return CustomList(list.__add__(self,other))
def __mul__(self,other):
return CustomList(list.__mul__(self,other))
The following statements work as desired, even without the overriding methods:
l = CustomList((1,2,3))
l.append(4)
l[0] = -1
l[0:2] = CustomList((10,11)) # type(l) is CustomList
These statements work only with the overriding methods in the above class definition:
l3 = l + CustomList((4,5,6)) # type(l3) is CustomList
l4 = 3*l # type(l4) is CustomList
l5 = l[0:2] # type(l5) is CustomList
The only thing I don't know how to achieve is making extended slicing return the right type:
l6 = l[0:2:2] # type(l6) is list
What do I need to add to my class definition in order to get CustomList as type of l6?
Also, are there other list operations other than extended slicing, where the result will be of list type instead of CustomList?
Firstly, I recommend you follow Björn Pollex's advice (+1).
To get past this particular problem (type(l2 + l3) == CustomList), you need to implement a custom __add__():
def __add__(self, rhs):
return CustomList(list.__add__(self, rhs))
And for extended slicing:
def __getitem__(self, item):
result = list.__getitem__(self, item)
try:
return CustomList(result)
except TypeError:
return result
I also recommend...
pydoc list
...at your command prompt. You'll see which methods list exposes and this will give you a good indication as to which ones you need to override.
You should probably read these two sections from the documentation:
Emulating container types
Additional methods for emulating sequence types (Python 2 only)
Edit: In order to handle extended slicing, you should make your __getitem__-method handle slice-objects (see here, a little further down).
Possible cut-the-gordian-knot solution: subclass UserList instead of list. (Worked for me.) That is what UserList is there for.
As a slight modification to Johnsywebs answer. I would only convert to a CustomList if item is a slice. Otherwise CustomList(["ab"])[0] would give you CustomList(["a", "b"]) which is not what you want. Like this:
def __getitem__(self, item):
result = list.__getitem__(self, item)
if type(item) is slice:
return CustomList(result)
else:
return result

Categories