Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
105 views
in Technique[技术] by (71.8m points)

python - Explanation about TypeError and AttributeError with classes

I am not so new to python, used classes for the last two projects, but there are two concepts that are not so clear for me. I'm writing a compiler, and my code is 1K+ lines so I made a simple code that sum up it where I get the two errors I don't understand:

class A:
    def __init__(self):
        self.var = 15

    def methodA(self):
        self.var = 0

class B:
    def __init__(self):
        self.a = A()

    def methodB(self):
        self.a.methodA()

    def run(self):
        self.methodB()

B.run()

The errors I get are:

AttributeError: type object 'B' has no attribute 'a'

and

TypeError: run() missing 1 required positional argument: 'self'

I know that I can fix the code as follows

class A:
    def __init__(self):
        self.var = 15

    def methodA(self):
        self.var = 0

class B:
    def __init__(self):
        pass

    def methodB(self):
        A.methodA(A)

    def run(self):
        B.methodB(B)

A.__init__(A)
B.run(B)

But I can't understand why I can't create A class instance as B attribute, and why I can't use self.method instead of B.method(B).

question from:https://stackoverflow.com/questions/65641169/explanation-about-typeerror-and-attributeerror-with-classes

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are calling the method with a class, not an object. You need to call it like this:

B().run()

Don't confuse between B and B(). One is the instance of B's metaclass, i.e. a class while the second one is an instance of class B. Since the method is not declared as a classmethod, you need an instance of class B to call it.

Your second code snippet works because in doing A.__init__(A), you basically add a class attribute A.var = 15. When you call B.run(B), you basically do A.method(A), which simply sets A.var = 0 (which you set as 15 before). You are mixing up classes with instances here, but it still works anyway since in the end, both are essentially objects.

For example, from here

>>> class A:
...     def f(self):
...         print(1)
>>> A().f
<bound method A.f of <__main__.A object at 0x10b641b50>>
>>> A.f
<function A.f at 0x10b759c10>

The first case clearly shows that it is a bound method to A's instance that doesn’t need an argument when called with A(), while in the second case, A.f is not treated as a method but as a function, which would need an argument in order to be invoked. So you can call it in any way like a plain function accepting one absolute argument (well as long as you don’t do something like print(self.some_attribute) or self.some_attribute = some_val inside):

>>> A.f(123123)
1
>>> A.f(33234)
1

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...