0

What is the bug in the following source code?
I am unable to find it myself.

ShapeBase.py

from abc import ABC

class ShapeBase(ABC):
    def __init__(self, idd: str):
        self.id_: str = idd
        self.cx_: float = 0.0
        self.cy_: float = 0.0

    @property
    def cx_(self) -> float:
        return self.cx_

    @cx_.setter
    def cx_(self, cx: float):
        self.cx_ = cx

    @property
    def cy_(self) -> float:
        return self.cy_

    @cy_.setter
    def cy_(self, cy: float):
        self.cy_ = cy

    def id(self) -> str:
        return self.id_

    def area(self) -> float:
        pass

Square.py

from shapes.ShapeBase import ShapeBase

class Square(ShapeBase):
    def __init__(self, idd: str, a: float):
        super().__init__(idd)
        self.a_ = a

    def area(self) -> float:
        return self.a_ * self.a_

    def width(self) -> float:
        return self.a_

main.py

from shapes.Square import Square

if __name__ == '__main__':
    s1 = Square('S1', 4.0)
    print("Area = " + str(s1.area()))
    

Output

C:\Users\pc\AppData\Local\Microsoft\WindowsApps\python3.7.exe C:/Users/pc/source/repos/Shapes/main.py

Process finished with exit code -1073741571 (0xC00000FD)

By the way, this problem is not about the name of the attributes.

This problem is related to inheritance.

tripleee
  • 175,061
  • 34
  • 275
  • 318
user366312
  • 16,949
  • 65
  • 235
  • 452
  • The implication from the duplicate is that you have ended up with an endless loop in recursion. Try to find out where something is calling itself (perhaps by way of calling something else which ends up calling the original object). – tripleee May 04 '21 at 07:08
  • try to reconfigure your python interpreter in pycharm and set it to python.exe. You can get location of python.exe by usine `where python` command – Amit Nanaware May 04 '21 at 07:08
  • 2
    I get another exception, `E RecursionError: maximum recursion depth exceeded !!! Recursion detected (same locals & position)`. `in __init__ super().__init__(idd) in __init__ self.cx_: float = 0.0 in cx_ self.cx_ = cx in cx_ self.cx_ = cx` – Guy May 04 '21 at 07:09
  • So from @Guy's comment, you have a problem where `self.cx_` ends up calling itself, over and over. – tripleee May 04 '21 at 07:12
  • The problem is with setters and getters. when inside cx_.setter, you are calling the same cx_.setter again and again which leads to recursion error – AmaanK May 04 '21 at 07:13
  • because of this statement `self.cx_ = cx` which calls itself – AmaanK May 04 '21 at 07:14
  • cx is a parameter – AmaanK May 04 '21 at 07:16
  • you need to rename the property or remove it because the property will do exactly the same – AmaanK May 04 '21 at 07:16
  • @xcodz-dot "Someone" reopened it again. For the record, the duplicate was https://stackoverflow.com/questions/20629027/process-finished-with-exit-code-1073741571 – tripleee May 04 '21 at 07:24

3 Answers3

1

Your cx_ property is calling cx_.setter when you call self.cx_ = cx inside the same setter function. To fix this you need to rename the property inside __init__ or remove the property declarations because your property does the same thing as normal python defaults would have done.

Here is the code with internal properties renamed

from abc import ABC

class ShapeBase(ABC):
    def __init__(self, idd: str):
        self.id_: str = idd
        self._cx_: float = 0.0
        self._cy_: float = 0.0

    @property
    def cx_(self) -> float:
        return self._cx_

    @cx_.setter
    def cx_(self, cx: float):
        self._cx_ = cx

    @property
    def cy_(self) -> float:
        return self._cy_

    @cy_.setter
    def cy_(self, cy: float):
        self._cy_ = cy

    def id(self) -> str:
        return self.id_

    def area(self) -> float:
        pass
AmaanK
  • 1,032
  • 5
  • 25
  • How are `self.cx_` and `cx` same names? – user366312 May 04 '21 at 07:32
  • I am unable to understand what you want to do. the name of property is `cx_` and that is conflicting with the name defined in `__init__` which is also `cx_` so I renamed the one inside `__init__` to `_cx_`. `cx` is a parameter to the function and it has nothing to do with error – AmaanK May 04 '21 at 07:35
1

https://pythonguide.readthedocs.io/en/latest/python/property.html#managing-attributes

Read the important box:

"If we use ‘return self.radius’ instead of ‘return self._radius’, then the @property will result in infinite loop as self.property will call the property method, which will return self.property, which results in calling the @property again."

Here the loop:

@property
def cx_(self) -> float:
    return self.cx_

@cx_.setter
def cx_(self, cx: float):
    self.cx_ = cx
Yuri
  • 511
  • 3
  • 6
  • Ok. but, why is that? – user366312 May 04 '21 at 07:35
  • because things are not working as you want them. It is calling the property read method. and not the variable that you setup inside `__init__` – AmaanK May 04 '21 at 07:37
  • because self.cx_ = value -> calls property setter cx_.setter -> property setter calls self.cx_ which calls the setter again. self.cx_ = value -> setter cx_.setter -> self.cx_ = value -> setter cx_.setter and so on. The same when you read: self.cx_ call the getter which does self.cx_ again which calls the getter and so on. – Yuri May 04 '21 at 07:41
0

I can see inside "ShapeBase" class you didn't inherited constructor of ABC class, although you've inherited ABC class from ShapeBase class.

You should inherit the base class constructor like the following code block.

super().__init__()

or,

ABC.__init__(self)

Also need to pass the ABC constructor arguments.

Md. Mehedi Hasan
  • 196
  • 2
  • 14