Only class variables and methods are inherited. The only relationship between instance variables and the class is that something executed code that created an instance variable.
class Things:
favorite_things = ['Raindrops on roses'] # Class variable
def do_something(self):
self.favorite_things = ['Bright copper kettles'] # instance variable
a = Things()
b = Things()
b.do_something()
c = Things()
c.favorite_things = ['Warm wollen mittens']
print('Things', Things.favorite_things)
print('a', a.favorite_things)
print('b', b.favorite_things)
print('c', c.favorite_things)
Output:
Things ['Raindrops on roses']
a ['Raindrops on roses']
b ['Bright copper kettles']
c ['Warm wollen mittens']
In this example, "a" has a class variable and no instance variables. "b" and "c" have a class variable and an instance variable. For "b" the instance variable is defined in a method of Things, but the instance variable for "c" is defined outside the scope of the class. The instance variable "favorite_things" is obviously not inherited, and relies on code that is executed after the instance is created.
When I first started writing classes with inheritance I ran into the "X is not defined" errors all the time. I would look at the code and see the instance variable created in the __init__, but setting a breakpoint before the error I would inspect the instance and there was no instance variable! My problem was that the instance variable was not defined yet. Even though it was defined inside __init__ of the base class, it was used before the base class __init__ was called, or before the base class __init__ had completed.
A linter will complain about instance variables defined outside the __init__ method. Listen to the linter and make you code complient. It is also a good idea to call __init__ for all superclass(es) at the top of the __init__ method.
As for typos, learn how to write unit tests and test everything. The compiler safety net is gone