Python - create a class as index for 2-dimension numpy array - python-3.x

I have some code of index class TwoDimIndex. I wanna use it to indexes of numpy 2-dimension array like arr[idx]. Below is code of that class.
import numpy as np
class TwoDimIndex:
def __init__(self, i1, i2):
self.i1 = i1
self.i2 = i2
pass
def __index__(self):
return self.i1, self.i2
# return np.array([self.i1, self.i2]) - Tried this too
def __eq__(self, other):
return self.i1 == other
def __int__(self):
return self.i1
def __hash__(self):
return hash(self.__int__())
# Don't edit code of this function please
def useful_func():
idx = TwoDimIndex(1, 1) # Can edit create instance
arr_two_dim = np.array([[0, 1], [2, 3]])
print(idx.__index__() == (1, 1))
print(arr_two_dim[1, 1], arr_two_dim[idx.__index__()]) # Success
print(arr_two_dim[idx]) # Crash here
# But I want this code work!!!
useful_func()
Class TwoDimIndex is use to be index, for example arr[TwoDimIndex()].
All code for Jupyter Notebook and Python 3.8. But I get error when execute this code.
IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices
Is there any ways to make an instance of a class TwoDimIndex an numpy 2-d array index?

I find short solution with inherit from tuple.
class TwoDimIndex(tuple):
def __init__(self, tup):
self.tup = tuple(tup)
pass
def __index__(self):
return self.tup
def useful_func():
idx = TwoDimIndex([1, 1]) # Edit at create class
arr_two_dim = np.array([[0, 1], [2, 3]])
print(idx.__index__() == (1, 1))
print(arr_two_dim[1, 1], arr_two_dim[idx.__index__()]) # Success
print(arr_two_dim[idx]) # Success now
useful_func()
Not sure it is right way but it work.

Related

Python: __eq__(self, other): len(self.sensor_data) ok, but len(other.senor_data) => AttributeError

I have a class named CAN_MSG for which I want to define the __eq__ method so that I can check two classes for equality.
Input_CAN_Sorter.py:
class CAN_MSG:
def __init__(self, first_sensor_id, timestamp, sensor_data):
self.first_sensor_id = first_sensor_id
self.sensor_data = sensor_data
self.timestamp = timestamp
def __eq__(self, other):
result = self.first_sensor_id == other.first_sensor_id
n = len(self.sensor_data) # no Error
i = len(other.senor_data) # AttributeError: 'CAN_MSG' object has no attribute 'senor_data'.
result = result and len(self.sensor_data) == len(other.senor_data)
for i in range(len(self.sensor_data)):
result = result and self.sensor_data[i] == other.senor_data[i]
result = result and self.timestamp == other.timestamp
return result
The class has a list of ints called sensor_data. When I compare using __eq__(self, other):
There is no problem with len(self.sensor_data), but with len(other.sensor_data) I get the following error:
AttributeError: 'CAN_MSG' object has no attribute 'senor_data'.
I don't understand why I can access self.sensor_data but not other.sensor_data.
test.py:
from Input_CAN_Sorter import CAN_MSG
list_temp = [1, 2, 3, 4, 5, 6, 7]
list_temp2 = [1, 2, 3, 4, 5, 6, 7]
CAN_MSG_1 = CAN_MSG(1, "TIME", list_temp)
CAN_MSG_2 = CAN_MSG(1, "TIME", list_temp2)
if CAN_MSG_1 == CAN_MSG_2:
print("=")
In C++ I would have done a check for the class type before and maybe a cast afterwards so that the compiler knows for sure that it is the same class, but in Python this is not possible/necessary if I understand correctly.
Probably this is a completely stupid mistake but I'm not 100% familiar with Python and can't come up with a reasonable explanation.
You misspelled your variable name.
AttributeError: 'CAN_MSG' object has no attribute 'senor_data'.
i = len(other.senor_data)
You meant to write:
i = len(other.sensor_data)

Write class such that calling instance returns all instance variables

I have answered my own question - see answer below
I'm writing a class, and I want this behavior:
a = f(10,20)
some_funct(a.row) # some_function is given 10
some_funct(a.col) # some_function is given 20
some_funct(a) # some_function is given a tuple of 10, 20 <-- THIS ONE :)
The last behavior is stumping me. I have not seen any examples that cover this.
Thus far:
class f(object):
"""Simple 2d object"""
row: int
col: int
def __init__(self, row, col):
self.row = row
self.col = col
Explictly I do not want another method, say, self.both = row, col.
I just want to 'call' the instance
I'm new to classes, so any improvements are welcome. Properties, setters, getters etc.
EDIT 1:
Replaced "print" with "some_function" in the question, and modified title
You can do like this
class f(object):
"""Simple 2d object"""
row: int
col: int
def __init__(self, row, col):
self.row = row
self.col = col
def __str__(self):
return f"row = {row}, col = {col}"
and print like this
a = f(10,20)
print(a) # row = 10, col = 20
This might help
class f(object):
"""Simple 2d object"""
row: int
col: int
def __init__(self, row, col):
self.row = row
self.col = col
def some_funct(self):
return (self.row, self.col)
You can access like
a = f(10,20)
a.some_funct() # (10, 20)
# or
row, col = a.some_funct()
From python 3.7 dataclasses have been introduced and their goal is to create classes that mainly contains data. Dataclasses comes with some helper function that extract the class attributes dict/tuples. e.g.
from dataclasses import dataclass,asdict,astuple
#dataclass
class f:
x: int
y: int
f_instance = f(10,20)
asdict(f_instance) # --> {'x': 10, 'y': 20}
astuple(f_instance) # -> (10,20)
EDIT I : Another technique would be to use namedtuple e.g.:
from collections import namedtuple
f = namedtuple('p',['row','col'])
a =f(10,20)
a.row #-> 10
a.col #-> 20
class f(tuple):
"""Simple 2d object"""
def __new__(cls, x, y):
return tuple.__new__(f, (x, y))
def __init__(self, x, y):
self.col = x
self.row = y
foo = f(1,2)
print(foo.col)
>>>1
print(foo.row)
>>>2
print(foo)
>>>(1, 2)
Importantly:
If you want it to behave like a tuple then make it a subclass of tuple.
Much stuffing around but stumbled upon an external site which gave me clues about the keywords to search on here. The SO question is here but I have modified that answer slightly.
I'm still a little confused because the other site says to use new in the init as well but does not give a clear example.

How to operate on a string while keep track of each char's score?

Problem
I have a string and scores for each char in the string
text = 'text'
scores = [0.99, 0.98, 0.97, 0.96]
I would like to do many string operations to text, like re, +, slice or split, after do these operations, I want to keep correspond scores. For example, if I do a slice operation I want get sliced_text and sliced_scores as result:
sliced_text = text[0:2]
sliced_scores = scores[0:2]
Python3 has UserString class, for some simple operations like slice or add, it's very useful.
from collections import UserString
from typing import List
class ScoreString(UserString):
def __init__(self, text: str, scores: List[float]):
super().__init__(text)
assert len(text) == len(scores)
self.scores = scores
def __getitem__(self, index) -> 'ScoreString':
return self.__class__(self.data[index], self.scores[index])
def __add__(self, other) -> 'ScoreString':
return self.__class__(self.data + other.data, self.scores + other.scores)
score_str = ScoreString('Test123', [1, 2, 3, 4, 5, 6, 7])
a = score_str[0:2] + score_str[4:]
print(a.data) # Te123
print(a.scores) # [1, 2, 5, 6, 7]
But split or re not work.
print(score_str.split('12')) # return string list ['Test', '3'], lose scores
import re
re.sub('123', '', score_str) # TypeError: expected string or bytes-like object
Any suggestion?
Actually what you are trying to do in split function
score_str.split('12')
--> Here score_str is a class object which is inheriting UserString, so when you apply split function it will call the function of base class and you will get a normal output as str.split().
import re
re.sub('123', '', score_str)
--> Here when you are trying to implement regular expression, Then sub functions have arguments sub(pattern, repl, string, count=0, flags=0), but here in third argument you are passing score_str, which is an object of ScoreString. That is why you are getting error.
If you will re-write as below,
re.sub('123', '', score_str.data)
It should work..
I hope this will help.

Add two vectors using python's operator overloading feauture

I want to add two vectors with n dimensions using the add method operator overloading . The elements of the 2 vectors will be input by the user. I don't understand how to define the vector as a single object.
In my example code vectors s1 and s2 have 2 defined values.I want the vectors to take input from the user having N dimensions and then add them using class and the add method.I can do it using only functions without using class and object but it is for a homework and the use of class is required.For example :
s1 = [float(x) for x in input().split()]
s2= [float(x) for x in input().split()]
s3=s1+s2
I am clueless on what to do and any help will be appreciated.
class Student :
def __init__(self,m1,m2) :
self.m1=m1
self.m2=m2
def __add__(self,other) :
m1=self.m1+other.m1
m2=self.m2+other.m2
s3=Student(m1,m2)
return s3
s1=Student(58,69)
s2=Student(60,65)
s3=s1+s2
print(s3.m1,s3.m2)
If you are allowed to use numpy following solution will work:
import numpy as np
x = np.array([float(x) for x in "1 2 3".split()])
y = np.array([float(x) for x in "3 4 5".split()])
print(x)
# [1. 2. 3.]
print(y)
# [3. 4. 5.]
print(x+y)
# [4. 6. 8.]
class Student:
def __init__(self, data):
self.data = data
def __add__(self, other):
return Student(self.data+other.data)
student_x = Student(x)
student_y = Student(y)
print((student_x+student_y).data)
# [4. 6. 8.]

python error where __str__ returns a NoneType

class Pixel:
"""Representing a 'pixel' aka one character on the screen
is mostly gonne be used in Map using a tuple location and a
character that can be changed"""
def __init__(self, char='#', location=(0,0)):
assert type(char) == str
assert type(location[0]) == int and type(location[1]) == int
self.location = location
self.x = self.location[0]
self.y = self.location[1]
self.char = char
def __str__(self):
return(self.char)
class Map:
"""Representing a map by having diffferent characters
on different lines and being able to manipulate the
characters, thus playing a game"""
def __init__(self, file=None):
self.pixels = {}
if not file:
self.rows = 3
self.colls = 3
for r in range(self.rows):
for c in range(self.colls):
self.pixels[(r, c)] = Pixel('#', (r, c))
def __str__(self):
print(self.pixels)
for c in range(self.colls):
print('')
for r in range(self.rows):
print(self.pixels[(r, c)], end='')
a = Map()
print(a)
I am trying to make a class that defines a grid where each place in the grid has a character, but when I run the code I get an error that tells me that __str__ returns a NoneType. I know I am not yet handeling file imput when initiating Map but that isn't the problem here, here is the output I got.
{(0, 1): <__main__.Pixel object at 0x7f31612a3080>,
(1, 2): <__main__.Pixel object at 0x7f31612a3470>,
(0, 0): <__main__.Pixel object at 0x7f31612a3048>,
(2, 0): <__main__.Pixel object at 0x7f31612a34a8>,
(1, 0): <__main__.Pixel object at 0x7f31612a32b0>,
(2, 2): <__main__.Pixel object at 0x7f31612a3390>,
(0, 2): <__main__.Pixel object at 0x7f31612a30b8>,
(2, 1): <__main__.Pixel object at 0x7f31612a3358>,
(1, 1): <__main__.Pixel object at 0x7f31612a32e8>}
###
###
###Traceback (most recent call last):
File "main.py", line 45, in <module>
print(a)
TypeError: __str__ returned non-string (type NoneType)
exited with non-zero status
I am also confused why the print in __str__ from Map refered me to the __main__.Pixel objects instead of using they __str__ method, but that is probably just my lack of knowlage
what am I missing?
You should use __repr__. Also in Map.__str__, you are not returning anything.For ex
In [10]: class Test:
....: def __str__(self):
....: return "str"
....: def __repr__(self):
....: return "repr"
....:
In [11]: t=Test()
In [12]: t
Out[12]: repr
In [13]: print(t)
str
I forgot to returnanything, i had the __str__print everything i needed but i didn't return anything for my print(a), thus i got a NoneType error.

Resources