Home > Back-end >  Why pycharm can not find this attributes and methods reference?
Why pycharm can not find this attributes and methods reference?

Time:06-26

Why pycharm can not find this attributes and methods reference?

class A:
    def __init__(self):
        print("A.__init__")

        self.method_need_B()
        self.method_need_C()

        print(self.attr_need_B)
        print(self.attr_need_C)

class B(A):
    def __init__(self):
        print("B.__init__")
        self.attr_need_B = "I am 'attribute' and A need me, but live in B"
        A.__init__(self)

    def method_need_B(self):
        print("I am 'method' and A need me, but live in B")

class C(B):
    def __init__(self):
        print("C.__init__")
        self.attr_need_C = "I am 'attribute' and A need me, but live in C"
        B.__init__(self)

    def method_need_C(self):
        print("I am 'method' and A need me, but live in C")

c = C()

this code on picture, i am not undestand why pycharm not visible this attrs and methods outputs without errors:

C.__init__
B.__init__
A.__init__
I am 'method' and A need me, but live in B
I am 'method' and A need me, but live in C
I am 'attribute' and A need me, but live in B
I am 'attribute' and A need me, but live in C

CodePudding user response:

Because they do not exist inside A class.

Not only pycharm cannot find references. The python interpreter would not be able to find it as well. If you will try such instruction:

a = A()

you will get error.

Why your code sample works though? You are calling inside C.__init__ such instruction: B.__init__(self), the self object does have the method_need_C, and going down, you add second method the same way in the B class. So the self in the A class does have those two methods.

CodePudding user response:

The script works without errors but it is very situational: it only works for the case displayed on your question.

What if, for instance, you call c = B()?

That's the output:

B.__init__
A.__init__
I am 'method' and A need me, but live in B
Traceback (most recent call last):
  File "C:\Users\xxx\Documents\test.py", line 29, in <module>
    c = B()
  File "C:\Users\xxx\Documents\test.py", line 15, in __init__
    A.__init__(self)
  File "C:\Users\xxx\Documents\test.py", line 6, in __init__
    self.method_need_C()
AttributeError: 'B' object has no attribute 'method_need_C'. Did you mean: 'method_need_B'?

Why it didn't worked on c = B(), but it worked on c = C()?

When you assign c an instance of class C, the class constructor calls B.__init__(self), which inside B constructor, it calls A.__init__(self).

So, c is an object with A, B and C methods and properties. As all of them have different function and variable names, they do not get overwritten once you inherit each parent's data.

Now, why does c = B() does not work?

It's because that on class A, you're trying to access class C methods and properties, and class C was never initialized inside class B instance. So basically, as C.__init__(self) is never called on this instance, then self.method_need_C() and self.attr_need_C are not allocated.

Now, you asked, why on c = C() these methods are visible? It's because that on python, self refers to the instance of the class that you created, which in this case is C.

Sure, the script being executed is inside class A, but have you tried to print self to see what is its type inside class A's constructor?

# By modifying your script, we now print self to see its type:
class A:
    def __init__(self):
        print("A.__init__: ", self)

        self.method_need_B()
        self.method_need_C()

        print(self.attr_need_B)
        print(self.attr_need_C)

This is the output:

C.__init__
B.__init__
A.__init__:  <__main__.C object at 0x0000029641A27B80>
I am 'method' and A need me, but live in B
I am 'method' and A need me, but live in C
I am 'attribute' and A need me, but live in B
I am 'attribute' and A need me, but live in C

As self refers to a class C instance, even inside class A it contains class B and class C methods and properties. So they are visible as long as you use self on the script.

Again, this only works because you're creating a class C instance. Instantiating another class type will get you lots of errors.

One thing you can do, if you really need to call class C and class B methods inside class A, is to use isinstance() function, as displayed below:

class A:
    def __init__(self):
        print("A.__init__: ", self)

        if (isinstance(self, B)):
            self.method_need_B()

        if (isinstance(self, C)):
            self.method_need_C()

        if (isinstance(self, B)):
            print(self.attr_need_B)

        if (isinstance(self, C)):
            print(self.attr_need_C)

class B(A):
    def __init__(self):
        print("B.__init__")
        self.attr_need_B = "I am 'attribute' and A need me, but live in B"
        A.__init__(self)

    def method_need_B(self):
        print("I am 'method' and A need me, but live in B")

class C(B):
    def __init__(self):
        print("C.__init__")
        self.attr_need_C = "I am 'attribute' and A need me, but live in C"
        B.__init__(self)

    def method_need_C(self):
        print("I am 'method' and A need me, but live in C")

c = B()

The output now does not give you any errors:

B.__init__
A.__init__:  <__main__.B object at 0x000001F82AA57F70>
I am 'method' and A need me, but live in B
I am 'attribute' and A need me, but live in B

That's because you're testing to see if self is an instance of class C or class B and prevent accessing methods and properties that do not exist, in case they are not instances of those classes.

  • Related