Subclassing a numpy ndarray is not working properly - python

I am just trying to subclass ndarray to create a special 2x1 vector with attributes x and y.
class Vec(np.ndarray):
def __new__(cls, x:int, y:int):
# print('In __new__ with class %s' % cls)
obj = super().__new__(cls, (2,), np.int16,
np.asarray((x,y)), offset=0, strides=None, order=None)
obj.x = x
obj.y = y
return obj
def __array_finalize__(self, obj):
if obj is None: return
self.x = getattr(obj, 'x', None)
self.y = getattr(obj, 'y', None)
a = Vec(1,2)
b = Vec(3,4)
c = a + b
print(c.x, c.y) # results 1 2
what is going wrong?

The problem is that your x and y are just another fields of the Vec object alongside your 2d array. And numpy doesn't know about them, hence doesn't do anything when calling the __add__ a.k.a. +. So x and y should be values in the array, and you can make properties out of them:
class Vec(np.ndarray):
def __new__(cls, x:int, y:int):
obj = super().__new__(cls, (2,), np.int16, np.asarray((x,y)),
offset=0, strides=None, order=None)
obj.x = x
obj.y = y
return obj
#property
def x(self):
return self[0]
#property
def y(self):
return self[1]
#x.setter
def x(self, x):
self[0] = x
#y.setter
def y(self, y):
self[1] = y
a = Vec(1,2)
b = Vec(3,4)
c = a + b
print(c.x, c.y) # results 4 6

Related

Simple python inheritance with singleton class failing with no stack trace

class B:
#property
def x(self):
print('x getter')
return self.x
#x.setter
def x(self, x) -> None:
print('x setter')
self.x = x + 1
class A(B):
__instance = None
def __new__(self):
''' Virtually private constructor '''
if not A.__instance:
A.__instance = object.__new__(self)
A.__instance.__setup()
return A.__instance
def __setup(self):
self.x = 10
def minus(self):
self.x -= 3
a1 = A()
Class A is a singleton class.
I'm not sure what is causing the program to fail as there is no stack trace and it just fails.
You are not using #property and setter correctly. You need a different name for the actual underlying property:
class B:
#property
def x(self):
print('x getter')
return self._x
#x.setter
def x(self, x) -> None:
print('x setter')
self._x = x + 1

Changing variables from one module doesn't affect the variables passed to another class

I have a class in one file1, which uses variables (that are constantly changing) from file2 but the changes are not being applied in the original class:
class element():
def __init__(self, x, y)
animations = [pic1, pic2, pic3]
self.x = x
self.y = y
self.pos = pos
self.atts = atts
def update()
...
file2:
x = 100
y = 100
pos = 10
atts = ['red', '#122']
el1 = element(x,y)
...
Value types such as the parameters used in x and y are copied when passed as an attribute so if you change them in your second module, the change will not be applied in your object, so you will need to either update them again:
x = 100
y = 100
pos = 10
atts = ['red', '#122']
el1 = element(x, y, pos, atts)
x = 50
el1.x = x
Or you can use a reference type (another object) that you can share between the two files to wrap the value types:
class ElementConfig():
def __init__(self, x, y, pos, atts):
self._x = x
self._y = y
self._pos = pos
self._atts = atts
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y = value
#property
def pos(self):
return self._pos
#pos.setter
def pos(self, value):
self._pos = value
#property
def atts(self):
return self._atts
#atts.setter
def atts(self, value):
self._atts = value
class Element():
def __init__(self, config: ElementConfig):
self._config = config
#property
def config(self):
return self._config
And in the other module:
from file1 import ElementConfig, Element
elementConfig = ElementConfig(100, 100, 10, ['red', '#122'])
el1 = Element(elementConfig)
print(el1.config.x)
The result is 100
elementConfig.x = 200
print(el1.config.x)
Now the result is 200

How do I use the python __get__ descriptor to output values of list elements?

How can I use the get descriptor to output values of list elements?
class X(object):
def __init__(self,value):
self.value = value
def __get__(self,obj,objtype):
return self.value
class Y(object):
a = X(1)
b = X(2)
c = [X(3),X(4)]
y = Y()
print(y.a)
print(y.b)
print(y.c[0])
Output:
1
2
<__main__.X object at ...>
Desired Output:
1
2
3
This snippet could bring you closer, but it's not the same. Z subclasses a list and defines __get__ for acting as a descriptor.
class X(object):
def __init__(self, value):
self.value = value
def __get__(self, obj, objtype):
return self.value
def __repr__(self):
return "X(%r)" % self.value
class Z(list):
def __get__(self, obj, objtype):
return self
def __getitem__(self, index):
"""override brackets operator, suggested by Azat Ibrakov"""
list_item = super(Z, self).__getitem__(index)
try:
return list_item.value
except AttributeError:
return list_item
class _LiteralForContainerDescriptorZ(object):
def __getitem__(self, keys):
"""override brackets operator, basing on https://stackoverflow.com/a/37259917/2823074"""
if not isinstance(keys, tuple):
keys = (keys,)
assert not any(isinstance(key, slice) for key in keys) # avoid e.g. ZL[11:value, key:23, key2:value2]
return Z(keys)
ZL = _LiteralForContainerDescriptorZ()
Using _LiteralForContainerDescriptorZ is optional, it gives a bit nicer syntax.
class Y(object):
a = X(1)
b = X(2)
c = Z([X(3.14), X(4)]) # define 'c' using constructor of Z class inherited from list
d = ZL[X(3.14), X(4)] # define 'd' using custom literal
y = Y()
for statement_to_print in [
"y.a", "y.b", "y.c","y.d", "y.c[0]", "y.c[1]", "y.d[0]",
]:
value = eval(statement_to_print)
print("{st:9} = {ev:<16} # type: {tp}".format(
st=statement_to_print, ev=value, tp=type(value).__name__))
Calling it, the prints are:
y.a = 1 # type: int
y.b = 2 # type: int
y.c = [X(3.14), X(4)] # type: Z
y.d = [X(3.14), X(4)] # type: Z
y.c[0] = 3.14 # type: float
y.c[1] = 4 # type: int
y.d[0] = 3.14 # type: float

How can i implement __add__ method in parent class?

I have object-oriented programming modelling for geometric shapes. I have add method in each classes if i want to add up two geometric shapes but I have defined in each subclass.
How can i implement the add method in the parent class , so that i don't to defined it for every subclasses?
import numpy as np
class Shape(object):
def __repr__(self):
return type(self).__name__
def __str__(self):
return type(self).__name__
class Circle(Shape):
"""
"""
# constructor
def __init__(self, radius):
self.radius = radius
def __add__(self, other):
if type(other) == int:
self.radius = self.radius + other
else:
newRadius = self.radius + other.radius
return Circle(newRadius)
def __radd__(self, other):
return self.__add__(other)
def area(self):
return np.pi * self.radius**2
class Rectangle(Shape):
# constructor
def __init__(self, width,height):
self.width , self.height = width, height
def __add__(self, other):
if type(other) == int:
self.width = self.width + other
self.height = self.height + other
else:
newWidth = self.width + other.width
newHeight = self.Height + other.Height
return Rectangle(newWidth,newHeight)
def __radd__(self, other):
return self.__add__(other)
def area(self):
"""
Function to compute the area of triangle.
"""
return self.width * self.height
This is a strange question, because it doesn't really make sense to add two circles and have the result be a new circle with the sum of the radiuses. You also have odd behaviour for adding with an int because you are changing the state of the object instead of creating a new one, like you do when adding an object.
But there is in fact a way to do this with just one method in the parent class, using some Python-specific features:
cls = self.__class__ is the class of the current object, which can be used to create a new object of the same class, and test if other is the right type.
d = self.__dict__ is a dictionary of the object's attributes.
The **{ ... } unpacking operator allows calling the cls constructor using a dictionary comprehension to compute the arguments.
I've also written a generic __repr__ which shows the state of the object, for conveniently testing examples in the REPL.
Here's an example:
class Shape:
def __add__(self, other):
cls = self.__class__
d = self.__dict__
if isinstance(other, int):
return cls(**{ k: v + other for k, v in d.items() })
elif isinstance(other, cls):
return cls(**{ k: v + other.__dict__[k] for k, v in d.items() })
else:
raise TypeError()
def __radd__(self, other):
return self.__add__(other)
def __repr__(self):
d = self.__dict__
return '{0}({1})'.format(
self.__class__.__name__,
', '.join('{0}={1!r}'.format(k, v) for k, v in d.items())
)
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
class Rectangle(Shape):
def __init__(self, width, height):
self.width, self.height = width, height
Examples:
>>> Circle(4) + Circle(5)
Circle(radius=9)
>>> Circle(6) + 2
Circle(radius=8)
>>> 3 + Circle(2)
Circle(radius=5)
>>> Rectangle(2, 3) + Rectangle(4, 5)
Rectangle(width=6, height=8)
>>> Rectangle(2, 3) + 1
Rectangle(width=3, height=4)
>>> 5 + Rectangle(2, 3)
Rectangle(width=7, height=8)
Note that I've changed the behaviour to always return a new object, instead of mutating the existing one.

Defining Python class instance attributes

Given a class definition that allows 3 possible inputs:
class FooBar(object):
def __init__(self, x=None, y=None, z=None):
if x is not None:
self.x = x
elif if y is not None:
self.y = y
elif if z is not None:
self.z = z
else:
raise ValueError('Please supply either x,y or z')
This 3 inputs are related each other, lets say:
x = .5*y = .25*z
This also implies:
y = .5*z = 2*x
and
z = 2*y = 4*x
When creating a instance of FooBar(), the user need to supply one of those and the __init__ takes care of it.
Now I would like to do the following
If any one of the 3 variables are changed the others change following the relationship.
To try to accomplish that I did:
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
self._y = 2*self._x
self._z = 4*self._x
And to the others:
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y = value
self._x = .5*self._y
self._z = 2*self._y
#property
def z(self):
return self._z
#z.setter
def z(self, value):
self._z = value
self._x = .25*self._z
self._y = .5*self._z
Is this the correct approach?
I think you make this more complicated than you have to. If the variables are related, and one can fully be determined by the other, there is no need to store three variables. You can store one variable, and dynamically calculate the others. Like:
class Foo(object):
def __init__(self, x=None, y=None, z=None):
if x is not None:
self.x = x
elif x is not None:
self.y = y
elif z is not None:
self.z = z
else:
raise ValueError('Provide an x, y, or z value.')
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = x
#property
def y(self):
return self._x / 2.0
#y.setter
def y(self, value):
self._x = 2 * value
#property
def z(self):
return self._x / 4.0
#z.setter
def z(self, value):
self._x = 4 * value
We thus store only a _x attribute on the class, and all the rest of the getters and setters, use the _x attribute (we can of course use _y or _z instead).
Furthermore something that is not very elegant is that a programmer can instantiate a Foo(x=1, y=425). As you can see, that means that it contains inconsistency. Perhaps it is worth raising an error in that case.
You can ensure that you only have one parameter provided by adding the following check in the init module:
class Foo(object):
def __init__(self, x=None, y=None, z=None):
data = [i for i in [x, y, z] if i is not None]
if len(data) > 1:
raise ValueError('Multiple parameters provided.')
if x is not None:
self.x = x
elif x is not None:
self.y = y
elif z is not None:
self.z = z
else:
raise ValueError('Provide an x, y, or z value.')
# ...
Here we thus construct a list of all non-None values, if there is more than one, the programmer provided two or more values, and then it is better to raise an exception.

Categories