I am writing a class for a lazy square root, allowing me to use it in fractions for linear algebra without getting a messy float. I've run into two specific problems both related to pythons 'private' class attributes. The first is that I am getting a soft error from pycharm for accessing an unresolved class attribute. My constructor looks something like this:
class SquareRoot(Real):
def __new__(cls, operand, coefficient=None):
self = super().__new__(cls)
self._value = (here i parse the value of operand)
self._scalar = (here i parse the value of the coefficient if there is one)
return self
Obviously a lot more happens with handling the input, and in the case that I get a non-integer, I try to return just sqrt(operand), throwing an error if this doesn't work, so my __new__()
function will sometimes not return a SquareRoot object, but most often will.
My first problem is with my properties:
@property
def radicand(self):
return self._value
Here I get a soft error about an unresolved attribute to SquareRoot._value. When I change the method to
@property
def radicand(self: 'SquareRoot'):
return self._value
with the type hint, the error goes away. If I change the constructor so that it always returns SquareRoot types this does not change the error, so there shouldn't be a problem with the construction. From what I understand of 'private' attributes in Python, I should expect PyCharm (or any IDE) to throw a soft error if I do this:
x = SquareRoot(2)
x._value
but that I should be able to reference self._value
anywhere within my class without any warnings. I have a .pyi stub file and whenever I let PyCharm try to correct my 'unresolved attribute' it tries to put an __init__()
method in the stub with self._value
initialized inside, so I'm wondering if somehow my stub file (which has absolutely nothing but type hints for methods) is making my .py file think its missing an attribute initialization.
My second problem is more of a concern that I have done something wrong. When I create an instance of SquareRoot like this:
x = SquareRoot(2)
print(x) # 'sqrt(2)'
SquareRoot._value = 5
print(x) # 'sqrt(5)'
I am somehow able to change the value of x._value
like this, but from my understanding of class attributes, I should only be able to do this if value was a class attribute, shared across all instances, but it is created only within my __new__()
method. My question here is more of: is this expected and if so, why?