I have two classes in the same file. I am trying to call ClassB from ClassB but receive the following error:
NameError: name 'ClassB' is not defined
class A:
var = B();
class B:
def foo(self):
Class attributes (like A.var that you're trying to define) are evaluated when their class is parsed and created, so B() won't exist when you're trying to reference it in the definition of class A.
Fortunately, you can just add it afterwards and it will have the same effect:
class A:
pass
class B:
def foo(self): pass
A.var = B()
If appropriate, you could also define it as an instance attribute instead:
class A:
def __init__(self):
self.var = B()
class B:
def foo(self): pass
The classes are "seen" in the order in which they are written. Therefore if you have a statement in the first class it will be evaluated directly, on the spot, before going any further in the file.
Your statement var = B() is therefore executed when class B does not exist yet for the Python interpreter.
There are 2 ways to fix this:
define the class B before the class A
OR put the statement var = B() in the constructor of class A as shown below
Your class A will look like this
class A:
def __init__(self):
self.var = B()
This means that the self.var = B will only be evaluated when you create your instance of the class A.
This topic has already been seen several times on Stack Overflow, I would suggest you take a look into one of them in the link below if you have any further questions.
Python class defined in the same file as another class - how do you get access to the one defined later in the file?
I have made a little program on repl.it to show you as an example if you want. It's here.
Related
Class A instantiates an object from Class B as a member variable. How can this class B object call methods from the Class A object? When I execute the program below I would expect to get a "Hello" printed, but I get an error instead saying "name 'a' is not defined"
What is the issue here and how can I fix it?
class B:
def __init__(self):
a.say_hello()
class A:
other = None
def __init__(self):
self.other = B()
def say_hello():
print("Helo")
a = A()
Python references are one-way. You'll need to retain a reference in the reverse direction for this to work.
class B:
def __init__(self, outer):
outer.say_hello()
class A:
# other = None # (see below)
def __init__(self):
self.other = B(self)
def say_hello():
print("Helo")
a = A()
If you need outer for more than just the constructor, you can store it in an instance variable.
You also don't need the other = None line. In Python, you don't need to declare your instance variables at the top of the class like you do in Java or C++. Instead, you just use self. to assign to them and they start existing. other = None in that scope makes a class variable, similar to static variable in Java, that can be referenced by A.other (Note the capital A; this is the class itself, not an instance of it).
There are situations where you might want to declare instance variables at the top of the class in some form or another (__slots__ and PEP 484 annotations are the main two), but for simple classes when you're starting out, it's not necessary, and an assignment like that will not do what you expect.
Pretty much what the title says but I will put some example code to clarify.
I would like to know why I can assign Repair, a reference to the class, to an instance variable but not to a class variable
class NotWorkingDefinitions:
# This will give unresolved reference
a = Repair
class WorkingDefitinions:
def __init__(self):
# This is fine
self.a = Repair
class Repair():
def __init__(self):
whatever = 10
def dosmt(self):
print("staring at a wall")
EDIT: The full answer is given over the different comments. It wasn't about not being able to assign to a class variable. It is just that class variables are immediately resolved and instance variables are not. The latter makes that defining Repair() class after WorkingDefinitions is not an issue.
The above code works if you move Repair to the top. The content of a class is evaluated from top to bottom, so any referenced classes must be defined before actually referencing them.
An example that explores this a bit more in terms of runtime and load-time could be:
# this will not work because the B class is referenced before definition
class A(object):
b_class = B
class B(object):
pass
Alternatively,
# this will work because B is defined first and used later
class B(object):
pass
class A(object):
b_class = B
But both of the examples above do not have a runtime-specific behavior. If instead you wanted A to use B and you had a really good reason to define A first, then you could get away with
class A(object):
def __init__(self):
# bind the B class to each instance of A
self.b_class = B
class B(object):
pass
a = A()
a.b_class
> __main__.B
But the short answer is you must define a variable before using it and when you bind a variable directly to a class (in the class definition, not a method) it must be defined.
The full answer is given over the different comments. It is not about not being able to assign to a class variable. It is that class variables are immediately evaluated and instance variables are not. Instance variables will be evaluated during initiation. The latter makes that defining Repair() class after WorkingDefinitions is not an issue.
I have a series of Python classes in a file. Some classes reference others.
My code is something like this:
class A():
pass
class B():
c = C()
class C():
pass
Trying to run that, I get NameError: name 'C' is not defined. Fair enough, but is there any way to make it work, or do I have to manually re-order my classes to accommodate? In C++, I can create a class prototype. Does Python have an equivalent?
(I'm actually playing with Django models, but I tried not complicate matters).
Actually, all of the above are great observations about Python, but none of them will solve your problem.
Django needs to introspect stuff.
The right way to do what you want is the following:
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# ...
class Manufacturer(models.Model):
# ...
Note the use of the class name as a string rather than the literal class reference. Django offers this alternative to deal with exactly the problem that Python doesn't provide forward declarations.
This question reminds me of the classic support question that you should always ask any customer with an issue: "What are you really trying to do?"
In Python you don't create a prototype per se, but you do need to understand the difference between "class attributes" and instance-level attributes. In the example you've shown above, you are declaring a class attribute on class B, not an instance-level attribute.
This is what you are looking for:
class B():
def __init__(self):
self.c = C()
This would solve your problem as presented (but I think you are really looking for an instance attribute as jholloway7 responded):
class A:
pass
class B:
pass
class C:
pass
B.c = C()
Python doesn't have prototypes or Ruby-style open classes. But if you really need them, you can write a metaclass that overloads new so that it does a lookup in the current namespace to see if the class already exists, and if it does returns the existing type object rather than creating a new one. I did something like this on a ORM I write a while back and it's worked very well.
A decade after the question is asked, I have encountered the same problem. While people suggest that the referencing should be done inside the init method, there are times when you need to access the data as a "class attribute" before the class is actually instantiated. For that reason, I have come up with a simple solution using a descriptor.
class A():
pass
class B():
class D(object):
def __init__(self):
self.c = None
def __get__(self, instance, owner):
if not self.c:
self.c = C()
return self.c
c = D()
class C():
pass
>>> B.c
>>> <__main__.C object at 0x10cc385f8>
All correct answers about class vs instance attributes. However, the reason you have an error is just the order of defining your classes. Of course class C has not yet been defined (as class-level code is executed immediately on import):
class A():
pass
class C():
pass
class B():
c = C()
Will work.
I am writing some code and had a general question about python
If I have something like this:
class A():
def __init__(self):
self.name
...
def doSomething(self):
class B():
def __init__(self):
self.name
...
c = B()
c.whatever()
Does that mean that class B is private to that function only or can it be called from an instance of class A? On that note if I had some code like this:
class A():
class B():
def __init__(self):
self.name
def __init__(self):
self.name
...
def doSomething(self):
...
I can call it by doing this d = A.B() right?
The thing to realize is that the class statement just creates a variable whose value is a class. The way the resulting class's scope works is the same the way a variable's scope would work if you just did a normal variable assignment like x = 2.
Any variables you create inside a function are local to that function unless you specify otherwise. So using a class statement inside a function just creates a local variable whose value is a class. It can't be accessed from outside the function.
In other words, this:
def foo():
class A(object):
pass
is not really different from this:
def foo():
A = 2
In both cases you create a local variable A inside the function. In one case its value is a class and in the other its value is an integer, but in both cases it's a local variable and has no existence outside the function.
In your second example, the class is created inside the enclosing class. Variables created inside a class namespace are class attributes, so yes, you can access it as you describe. (Why you'd want to do this is another question.) In other words, as above, this:
class A(object):
class B(object):
pass
is not that different from this:
class A(object):
B = 2
In both cases you create a class A that has a class attribute B.
I have a series of Python classes in a file. Some classes reference others.
My code is something like this:
class A():
pass
class B():
c = C()
class C():
pass
Trying to run that, I get NameError: name 'C' is not defined. Fair enough, but is there any way to make it work, or do I have to manually re-order my classes to accommodate? In C++, I can create a class prototype. Does Python have an equivalent?
(I'm actually playing with Django models, but I tried not complicate matters).
Actually, all of the above are great observations about Python, but none of them will solve your problem.
Django needs to introspect stuff.
The right way to do what you want is the following:
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# ...
class Manufacturer(models.Model):
# ...
Note the use of the class name as a string rather than the literal class reference. Django offers this alternative to deal with exactly the problem that Python doesn't provide forward declarations.
This question reminds me of the classic support question that you should always ask any customer with an issue: "What are you really trying to do?"
In Python you don't create a prototype per se, but you do need to understand the difference between "class attributes" and instance-level attributes. In the example you've shown above, you are declaring a class attribute on class B, not an instance-level attribute.
This is what you are looking for:
class B():
def __init__(self):
self.c = C()
This would solve your problem as presented (but I think you are really looking for an instance attribute as jholloway7 responded):
class A:
pass
class B:
pass
class C:
pass
B.c = C()
Python doesn't have prototypes or Ruby-style open classes. But if you really need them, you can write a metaclass that overloads new so that it does a lookup in the current namespace to see if the class already exists, and if it does returns the existing type object rather than creating a new one. I did something like this on a ORM I write a while back and it's worked very well.
A decade after the question is asked, I have encountered the same problem. While people suggest that the referencing should be done inside the init method, there are times when you need to access the data as a "class attribute" before the class is actually instantiated. For that reason, I have come up with a simple solution using a descriptor.
class A():
pass
class B():
class D(object):
def __init__(self):
self.c = None
def __get__(self, instance, owner):
if not self.c:
self.c = C()
return self.c
c = D()
class C():
pass
>>> B.c
>>> <__main__.C object at 0x10cc385f8>
All correct answers about class vs instance attributes. However, the reason you have an error is just the order of defining your classes. Of course class C has not yet been defined (as class-level code is executed immediately on import):
class A():
pass
class C():
pass
class B():
c = C()
Will work.