Python overloading multiple getitems / index requests - python

I have a Grid class which I want to access using myGrid[1][2]. I know I can overload the first set of square brackets with the __getitem__() method, but what about the second.
I thought I could achieve this by having a helper class which also implements __getitem__ and then:
class Grid:
def __init__(self)
self.list = A TWO DIMENSIONAL LIST
...
def __getitem__(self, index):
return GridIndexHelper(self, index)
class GridIndexHelper:
def __init__(self, grid, index1):
self.grid = grid
self.index1 = index1
....
def __getitem__(self, index):
return self.grid.list[self.index1][index]
This seems a little too homebrewed... What is the python way to achieve this?

class Grid:
def __init__(self):
self.list = [[1,2], [3,4]]
def __getitem__(self, index):
return self.list[index]
g = Grid();
print g[0]
print g[1]
print g[0][1]
prints
[1, 2]
[3, 4]
2

As far as I know the way anajem mentions is the only way.
example:
class Grid(object):
def __init__(self):
self.list = [[1, 2], [3, 4]]
def __getitem__(self, index):
return self.list[index[0]][index[1]]
if __name__ == '__main__':
mygrid = Grid()
mygrid[1, 1] #How a call would look
Prints:
4
Does not operate exactly as you want it to but does the trick in my eyes.

you could make the index into a tuple:
def getitem(self,indexTuple):
x, y = indexTuple
...
and access the object override:
instance[[2,3]]
or
instance[(2,3)]

This question is quite old, but I'll add my answer anyway for newcomers.
I ran into this need myself, and here's a solution that worked for me:
class Grid:
def __init__(self):
self.matrix = [[0,1,2],[3,4,5],[6,7,8]]
self.second_access = False
def __getitem__(self, key):
if not self.second_access:
self.first_key = key
self.second_access = True
return self
else:
self.second_access = False
return self.matrix[self.first_key][key]
g = Grid()
print(g[1][2]) # 5
print(g[0][1]) # 1
print(g[2][0]) # 6
Notice that this will not work for single access!
So, for example, if you want to use something of the form g[0] to get [0,1,2] it will not work, and instead you'll get nonsensical result (the object itself).

Related

Can I write this as a wrapper?

I have the following code:
import numpy as np
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
#property
def zerocoord(self):
return self.coord([0,0])
#property
def Dcoord(self):
return self.coord([1,0])
#property
def Tcoord(self):
return self.coord([0,1])
#property
def Xcoord(self):
return self.coord([1./np.sqrt(2), 1./np.sqrt(2)])
#property
def Ycoord(self):
return self.coord([-1./np.sqrt(2), 1./np.sqrt(2)])
where all the properties are basically each of the properties is calling the same method coord. This is because the actual array that I feed coord, [0,0], [1,0], [0,1] etc. is fixed, but might be extended depedning on the instance attribute dimension.
I am a bit new at Python, but intuitively (and maybe naively) I think this can be written as a wrapper... so something like:
#property
def coord(self)
and
#coord
def Dcoord(self)
Which would make the code a bit more elegant.
Could someone please help me out?
Define your own descriptor called Coord, instead of using property.
from __future__ import division
import numpy as np
class Coord(object):
def __init__(self, p1, p2):
self.foo = [p1, p2]
def __get__(self, obj, type=None):
if obj.dimension > 2:
return self.foo + [0 for x in range(2, obj.dimension)]
else:
return self.foo
class Basis(object):
def __init__(self, d):
self.dimension = d
zerocoord = Coord(0, 0)
dcoord = Coord(1, 0)
tcoord = Coord(0, 1)
xcoord = Coord(1/np.sqrt(2), 1/np.sqrt(2))
ycoord = Coord(-1/np.sqrt(2), -1/np.sqrt(2))
Now, the logic for determining the shape of each type of coordinate is embedded in the descriptor itself, rather than your class.
Some examples:
>>> Basis(1).dcoord
[1, 0]
>>> Basis(3).dcoord
[1, 0, 0]
>>> Basis(4).tcoord
[0, 1, 0, 0]
You can put the property names and their respective constant values to pass to the coord method in a sequence of tuples and then use a loop to set the properties accordingly:
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
for name, value in ('zerocoord', [0, 0]), ('Dcoord', [1, 0]), ('Tcoord', [0, 1]), ('Xcoord', [1./np.sqrt(2), 1./np.sqrt(2)]), ('Ycoord', [-1./np.sqrt(2), 1./np.sqrt(2)]):
setattr(Basis, name, property(lambda self, value=value: self.coord(value)))
You can use a decorator that wraps those methods by calling the coord method for them and turning them into properties, so that those methods only need to return the relevant constants instead:
def coord_property(func):
def wrapper(self):
return self.coord(func(self))
return property(wrapper)
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
#coord_property
def zerocoord(self):
return [0,0]
#coord_property
def Dcoord(self):
return [1,0]
#coord_property
def Tcoord(self):
return [0,1]
#coord_property
def Xcoord(self):
return [1./np.sqrt(2), 1./np.sqrt(2)]
#coord_property
def Ycoord(self):
return [-1./np.sqrt(2), 1./np.sqrt(2)]
You can't pass a value to a property getter, and decorators will get clunky in a hurry. If you're using at lease 3.4, then you can reduce your line count using functools.partialmethod.
However, it's probably better to just keep your code the way it is, since "Explicit is better than implicit".
from functools import partialmethod
class BasisWrapped(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
zerocoord = partialmethod(coord, [0, 0])
d_coord = partialmethod(coord, [1, 0])
t_coord = partialmethod(coord, [0, 1])
x_coord = partialmethod(coord, [1./np.sqrt(2), 1./np.sqrt(2)])
y_coord = partialmethod(coord, [-1./np.sqrt(2), 1./np.sqrt(2)])
You could get rid of a lot of the boilerplate code by doing things this way:
import numpy as np
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
return c if self.dimension <= 2 else (c + [0]*(self.dimension-2))
def _coord_prop(loc):
#property
def prop(self):
return self.coord(loc)
return prop
zerocoord = _coord_prop([0, 0])
Dcoord = _coord_prop([1, 0])
Tcoord = _coord_prop([0, 1])
Xcoord = _coord_prop([1./np.sqrt(2), 1./np.sqrt(2)])
Ycoord = _coord_prop([-1./np.sqrt(2), 1./np.sqrt(2)])
del _coord_prop # Only used inside class definition.
basis = Basis(2)
print(basis.zerocoord) # -> [0, 0]
print(basis.Dcoord) # -> [1, 0]
print(basis.Tcoord) # -> [0, 1]
print(basis.Xcoord) # -> [0.7071067811865475, 0.7071067811865475]
print(basis.Ycoord) # -> [-0.7071067811865475, 0.7071067811865475]
Personally, I think the code is already quite elegant. You shouldn't/can't make coord a property, because:
You won't be able to pass arguments to it, as a property is meant to be a "getter" for a (calculated?) field. coord behaves as a function and should hence be one.
If you are really just looking to reduce the size of your code, you can try an approach from the other answers, though I think it is not really necessary.
Aside: As I understand from your use case, you want to allow users to be able to call coord with a custom coordinate of their choice? If not, you can consider making it private by renaming it to _coord.

How can I define selection using [] for a new class?

I've created a new class and I'd like to define how to use [] to select things from it. Is there a way to do that?
class NewClass:
def __init__(self, list):
self.list_item = list
# def __indexer__(self, slice_object):
# return list[slice_object]
example = NewClass(range(0, 5))
print example[0:3]
Sure, it's called __getitem__.
class NewClass(object):
def __init__(self, list):
self.list_item = list
def __getitem__(self, slice_object):
return self.list_item[slice_object]
example = NewClass(range(0, 5))
print(example[0:3])

How to implement chain operations in Python?

class Array:
def __init__(self):
self.list = []
def add(self, num):
self.list.append(num)
a = Array()
a.add(1).add(2)
I would like to add number 1, 2 to self.list like this.
How can I implement?
After your insertion returns the instance itself for second operation, then you will have instance itself so you can perform add operation:
def add(self, num):
self.list.append(num)
return self
Return the object itself
def add(self, num):
self.list.append(num)
return self
As an alternative approach, why not just let your add method take a list of values as input? Seems like it would be easier to use like that
def add(self, vals):
self.list += vals
So now you can
a.add([1,2])
Instead of
a.add(1).add(2)

Python generic method scope

I've got a class that wraps functions with some metadata, in particular a parental relationship with other instances:
class Foo(object):
def __init__(self, func, parent):
self.func = func
self.parent = parent
self.parent_func = self.parent.func
In a few cases, I would like to use Foo to wrap a function that internally calls another Foo's function:
def f(x): return str(x).title()
def g(x): return self.parent_func(x)
a = Foo(f)
b = Foo(g, a)
print b.func("april is the cruellest month")
>>> April Is The Cruellest Month
Problem is that g isn't actually a method until b runs Foo.__init__, so it doesn't have a self.
I'm assuming there's something rather fundamental I'm missing about scoping, object methods, or functions' first-class citizenship status, and would greatly appreciate a point in the right direction.
EDIT: Looks like my above genericized example threw folks off, so I'm adding a more specific example below. The idea of this class is that each instance is an integer property (primality, perfection, its list of factors, etc), and contains a function that tests an integer for the property (returning a bool or an answer, as the case base be).
def f(n): # returns list of factors of n
def s(n): return len(self.parent_func(n))==2 # checks if n is semiprime
factors = Foo(f)
semiprime = Foo(s, factors)
It seems like your question boils down to "how can I dynamically add a method to an object", the the short answer is don't do it (1). Objects can have attributes which can be functions, and that's fine, but these functions do not become methods and don't behave like methods. For example if foo.attr is sum then foo.attr(x) is the same as sum(x) not sum(foo, x).
Your question has a certain functional "aroma" to it, if you wanted to drop the class/object stuff and go the fully functional route you could do something like this:
def identity(x):
return x
def f(n):
return [i for i in range(1, 10) if (n % i == 0)]
def s(factors):
return (len(factors) == 2)
def foo(func, helper=identity):
def innerfunc(n):
return func(helper(n))
return innerfunc
a = foo(f)
print a(6)
# [1, 2, 3, 6]
b = foo(s, a)
print b(5)
# True
If that doesn't appeal to you, I would suggest thinking of the func and parent attributes on your Foo class as data attached to your objects, not as methods, and work out the problem from there. The logic associated with your class should live inside proper methods. These methods can refer to the data as needed. Here's my very simple example:
class Foo(object):
def __init__(self, func, parent=None):
self.func = func
self.parent = parent
def run(self, n):
if self.parent is None:
return self.func(n)
else:
return self.func(self.parent.run(n))
a = Foo(f)
print a.run(6)
# [1, 2, 3, 6]
b = Foo(s, a)
print b.run(5)
# True
(1) Methods belong to a class not an object, so the question should really be how can I attach something to my object that behaves like a method.
As Matthew said, "parental relationship" would point to inheritance. But if you want/have to do it this way, you could use functools.partial:
from functools import partial
class Foo(object):
def __init__(self, func, parent=None):
self.func = partial(func, self)
self.parent = parent
self.parent_func = self.parent.func if parent is not None else None
def f(self, x):
return str(x).title()
def g(self, x):
return self.parent_func(x)
if __name__ == '__main__':
a = Foo(f)
b = Foo(g, a)
print b.func("april is the cruellest month")
When you call a object method, it is called with self as first parameter.
def f(self,x): return str(x).title()
def g(self,x): return self.parent_func(x)

Python class structure

I am trying to make my new code as user friendly as possible and what I would have in mind for the particular problem I am facing atm is this:
Suppose we have
import numpy as np
class TestClass:
def __init__(self, data):
self.data = data
#property
def method_a(self):
return np.median(self.data)
#property
def method_b(self):
return np.mean(self.data)
foo = TestClass([1, 2, 5, 7, 12, 6, 3, 37, 16])
print(foo.method_a)
print(foo.method_b)
Everything is fine so far. Method A gives me the median, method B the mean.
During processing I will switch depending on circumstances between both methods. So sometimes I will call method A, sometimes method B.
However, what I want is then to continue with a method C, that acts upon the result of either method A or B in such a way
final_result = foo.method_a.method_c
or
final_result = foo.method_b.method_c
I know it is possible to write method C as a function and do it like this:
final_result = method_c(foo.method_a)
final_result = method_c(foo.method_b)
but I think it would make the code easier to read if I could apply method C as stated above.
Is this possible somehow?
thanks
your statement is not quite clear, let's assume you want to add method C to the class. you can wrap your return value inside of the class again to achieve what you want:
import numpy as np
class TestClass:
def __init__(self, _data):
self._data = data
#property
def data(self): return self._data
#property
def method_a(self):
return TestClass(np.median(self.data))
#property
def method_b(self):
return TestClass(np.mean(self.data))
#property
def method_c(self):
return TestClass(np.whatever(self.data))
then you can chain however long you want:
final_result = foo.method_a.method_b.method_c.method_c.data
if the class is not what you plan to place, you put different one.
Following HuStmpHrrr's comment I changed my code like this
(Here I just assume that method C simply adds 1 to the results):
import numpy as np
class NewClass:
def __init__(self, data):
self.data = data
def method_c(self):
return self.data + 1
class TestClass:
def __init__(self, data):
self.data = data
#property
def method_a(self):
return NewClass(np.median(self.data))
#property
def method_b(self):
return NewClass(np.mean(self.data))
foo = TestClass([1, 2, 5, 7, 12, 6, 3, 37, 16])
result1 = foo.method_a
result2 = foo.method_b
print(result1.method_c())
print(result2.method_c())
I'm not sure why you want a property. Your code seems like it really just needs a simple method. Properties are for data that you would get and set that you want to manage.
class Test(Object):
def __init__(self, data):
super().__init__()
self.data = data
self.value = 0
# end Constructor
def method_a(self):
return np.median(self.data)
# end method_a
#property
def method_c(self):
return self.value
#method_c.setter
def method_c(self, value):
self.value = value
# self.method_a(value)
# end method_c
# end class Test
t = Test([1,2,3,4])
print(t.method_a())
t.method_c = 5 # This calls the method_c.setter and will make t.value = 5
print(t.method_c)
The property is typically used as a wrapper method to control the data.

Categories