Python class forward declaration [duplicate] - python

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.

Related

How can I refer to the currently being defined class? [duplicate]

For a recursive function we can do:
def f(i):
if i<0: return
print i
f(i-1)
f(10)
However is there a way to do the following thing?
class A:
# do something
some_func(A)
# ...
If I understand your question correctly, you should be able to reference class A within class A by putting the type annotation in quotes. This is called forward reference.
class A:
# do something
def some_func(self, a: 'A')
# ...
See ref below
https://github.com/python/mypy/issues/3661
https://www.youtube.com/watch?v=AJsrxBkV3kc
In Python you cannot reference the class in the class body, although in languages like Ruby you can do it.
In Python instead you can use a class decorator but that will be called once the class has initialized. Another way could be to use metaclass but it depends on what you are trying to achieve.
You can't with the specific syntax you're describing due to the time at which they are evaluated. The reason the example function given works is that the call to f(i-1) within the function body is because the name resolution of f is not performed until the function is actually called. At this point f exists within the scope of execution since the function has already been evaluated. In the case of the class example, the reference to the class name is looked up during while the class definition is still being evaluated. As such, it does not yet exist in the local scope.
Alternatively, the desired behavior can be accomplished using a metaclass like such:
class MetaA(type):
def __init__(cls):
some_func(cls)
class A(object):
__metaclass__=MetaA
# do something
# ...
Using this approach you can perform arbitrary operations on the class object at the time that the class is evaluated.
Maybe you could try calling __class__.
Right now I'm writing a code that calls a class method from within the same class.
It is working well so far.
I'm creating the class methods using something like:
#classmethod
def my_class_method(cls):
return None
And calling then by using:
x = __class__.my_class_method()
It seems most of the answers here are outdated. From python3.7:
from __future__ import annotations
Example:
$ cat rec.py
from __future__ import annotations
class MyList:
def __init__(self,e):
self.data = [e]
def add(self, e):
self.data.append(e)
return self
def score(self, other:MyList):
return len([e
for e in self.data
if e in other.data])
print(MyList(8).add(3).add(4).score(MyList(4).add(9).add(3)))
$ python3.7 rec.py
2
Nope. It works in a function because the function contents are executed at call-time. But the class contents are executed at define-time, at which point the class doesn't exist yet.
It's not normally a problem because you can hack further members into the class after defining it, so you can split up a class definition into multiple parts:
class A(object):
spam= 1
some_func(A)
A.eggs= 2
def _A_scramble(self):
self.spam=self.eggs= 0
A.scramble= _A_scramble
It is, however, pretty unusual to want to call a function on the class in the middle of its own definition. It's not clear what you're trying to do, but chances are you'd be better off with decorators (or the relatively new class decorators).
There isn't a way to do that within the class scope, not unless A was defined to be something else first (and then some_func(A) will do something entirely different from what you expect)
Unless you're doing some sort of stack inspection to add bits to the class, it seems odd why you'd want to do that. Why not just:
class A:
# do something
pass
some_func(A)
That is, run some_func on A after it's been made. Alternately, you could use a class decorator (syntax for it was added in 2.6) or metaclass if you wanted to modify class A somehow. Could you clarify your use case?
If you want to do just a little hacky thing do
class A(object):
...
some_func(A)
If you want to do something more sophisticated you can use a metaclass. A metaclass is responsible for manipulating the class object before it gets fully created. A template would be:
class AType(type):
def __new__(meta, name, bases, dct):
cls = super(AType, meta).__new__(meta, name, bases, dct)
some_func(cls)
return cls
class A(object):
__metaclass__ = AType
...
type is the default metaclass. Instances of metaclasses are classes so __new__ returns a modified instance of (in this case) A.
For more on metaclasses, see http://docs.python.org/reference/datamodel.html#customizing-class-creation.
If the goal is to call a function some_func with the class as an argument, one answer is to declare some_func as a class decorator. Note that the class decorator is called after the class is initialized. It will be passed the class that is being decorated as an argument.
def some_func(cls):
# Do something
print(f"The answer is {cls.x}")
return cls # Don't forget to return the class
#some_func
class A:
x = 1
If you want to pass additional arguments to some_func you have to return a function from the decorator:
def some_other_func(prefix, suffix):
def inner(cls):
print(f"{prefix} {cls.__name__} {suffix}")
return cls
return inner
#some_other_func("Hello", " and goodbye!")
class B:
x = 2
Class decorators can be composed, which results in them being called in the reverse order they are declared:
#some_func
#some_other_func("Hello", "and goodbye!")
class C:
x = 42
The result of which is:
# Hello C and goodbye!
# The answer is 42
What do you want to achieve? It's possible to access a class to tweak its definition using a metaclass, but it's not recommended.
Your code sample can be written simply as:
class A(object):
pass
some_func(A)
If you want to refer to the same object, just use 'self':
class A:
def some_func(self):
another_func(self)
If you want to create a new object of the same class, just do it:
class A:
def some_func(self):
foo = A()
If you want to have access to the metaclass class object (most likely not what you want), again, just do it:
class A:
def some_func(self):
another_func(A) # note that it reads A, not A()
Do remember that in Python, type hinting is just for auto-code completion therefore it helps IDE to infer types and warn user before runtime. In runtime, type hints almost never used(except in some cases) so you can do something like this:
from typing import Any, Optional, NewType
LinkListType = NewType("LinkList", object)
class LinkList:
value: Any
_next: LinkListType
def set_next(self, ll: LinkListType):
self._next = ll
if __name__ == '__main__':
r = LinkList()
r.value = 1
r.set_next(ll=LinkList())
print(r.value)
And as you can see IDE successfully infers it's type as LinkList:
Note: Since the next can be None, hinting this in the type would be better, I just didn't want to confuse OP.
class LinkList:
value: Any
next: Optional[LinkListType]
It's ok to reference the name of the class inside its body (like inside method definitions) if it's actually in scope... Which it will be if it's defined at top level. (In other cases probably not, due to Python scoping quirks!).
For on illustration of the scoping gotcha, try to instantiate Foo:
class Foo(object):
class Bar(object):
def __init__(self):
self.baz = Bar.baz
baz = 15
def __init__(self):
self.bar = Foo.Bar()
(It's going to complain about the global name 'Bar' not being defined.)
Also, something tells me you may want to look into class methods: docs on the classmethod function (to be used as a decorator), a relevant SO question. Edit: Ok, so this suggestion may not be appropriate at all... It's just that the first thing I thought about when reading your question was stuff like alternative constructors etc. If something simpler suits your needs, steer clear of #classmethod weirdness. :-)
Most code in the class will be inside method definitions, in which case you can simply use the name A.

Inheritance: getting the attributes of __init__

In the following example, is there any way the a attribute in A can be accessed by the B class or C inner class?
class A:
def __init__(self, a):
self.a = a
def C_test(self):
for i in range(4):
c = self.C()
class C:
print(self.a)
class B(A):
def __init__(self):
print(self.a)
How come I get this error?
Traceback (most recent call last):
File "/Users/home/Desktop/Pygame/test.py", line 1, in <module>
class A:
File "/Users/home/Desktop/Pygame/test.py", line 10, in A
class C:
File "/Users/home/Desktop/Pygame/test.py", line 11, in C
print(self.a)
NameError: name 'self' is not defined
self is not a special variable name in Python - it's just the name that is typically given to the first argument of a method, which is bound to the object calling that method.
Your self.a in class C doesn't appear inside a method definition where self is listed as an argument, so self has no meaning there.
For your B example, this general idea does work, just not automatically. Python does Python does have broadly similar rules to Java when it comes to single inheritance. The reason it doesn't work automatically here is because of Python's data model - member variables are attached to each unique instance, rather than being an intrinsic part of the class. They're usually, as in your examples, attached to the instance when __init__ runs. So, for your B to have an a, it would need to be attached by A.__init__. Python will automatically run that for you if you don't write a B.__init__, but if you do have that, you need to call up explicitly. The easiest way is this:
class B(A):
def __init__(self):
super().__init__()
Again, you might recognise this idea of explicitly chaining up using super from other languages - although the spelling is a bit different here. But the only major technical difference between Python and Java in this respect is that Python needs the parent constructor to be called for the instance variables to even exist (in Java, they will still exist, but might not have the right value, or even be initialised).
For your C example, Python is very different from Java here. Python doesn't usually use the term 'inner class', although you can define a class inside another class (note that you haven't in your code sample, though) - but instances of the inner class won't be associated with an instance of the outer class. So, they behave a bit more like Java inner static classes. You could associate them explicitly by doing something like this:
class A:
def __init__(self, a):
self.a = a
self.my_C = A.C(self)
class C:
def __init__(self, A_self):
print(A_self.a)
But this isn't exactly common, and depending on exactly what your problem is, there is almost always a better way to solve it than trying to shoehorn Java idioms into Python code.
If you derive a class from your own base-class, you have to call the constructor of the base-class with super to inherit the base-classes attributes:
class A(object):
def __init__(self, a):
self.a = a
class B(A):
def __init__(self):
super(B, self).__init__(self)
After running this you can do this for example:
a = A(1)
b = B()
b.a = a.a
b has declared no attribute a, but inherits it from class A by calling the constructor of A via super in class B.
Now b.a evaluates 1 cause it is set to the value of a.a.

python: changing object class in multi-level inheritance

I have looked at many questions posted here to find an answer to my problem, but I wasn't successful. The problem might be, that I just don't know for what keywords I should look. So my problem is the following:
I've got a program, that has a multi-level inheritance and I am trying to figure out how the best way would be to change the class of an object to a subclass. Let's say I have the following code:
class A(object):
def __init(self, filename, ..)
super(A, self).__init__()
...some assignments here
class B(A):
def __init(self, filename, ..)
super(B, self).__init__()
...some assignments here
class C(A):
def __init(self, filename, ..)
super(C, self).__init__()
...some assignments here
and so on...
I always want to start initialising an object of class A. Depending on the type of the file that is used, the assignments may differ and depending on those assignments I can determine what kind of file it is. So now I want to change the class of the object to whatever class is suitable..
I know I could pass the A object to B or C and use copy or deepcopy, but in A i am assigning an object of which the reference should not change and some others where it should change. Also I would need to delete that object of A, after initialising B or C.
class B(A):
def __init__(self, filename, objA = None):
if objA is not None:
self.__dict__ = copy.deepcopy(objA.__dict__)
del(objA)
else:
super(B, self).__init__(filename)
Also there is another possibility by changing the _class attribute to another class and use some kind of update method of the new class.
I would like to know, which of the two approaches is recommended or is there even a better one. Thanks in advance.
What you want is a factory: a function that opens the file, reads the stuff it needs to read to figure out what kind of file it is, and then initializes and returns an object of the appropriate class.
If you want to keep it a class, you'd want to override __new__() and then return an object of the desired class instead of its own class. (You could also do it using a metaclass and overriding __call__() on that.)
You can change an instance's class after instantiating it as well, by changing its __class__ attribute to point to the desired class. That'll work, but the factory is going to be more familiar to other programmers who will read your code.
This code will explain what you want to do
class B(object):
def x(self):
print 'b'
class A(object):
def x(self):
print 'a'
Now we create two objects
a = a()
b = b()
a.x()
a
b.x()
b
now if you want 'a' to become a B object
a.__class__ = type(b)
or
a.__class__ = B
now the x attribute is from the B class.
a.x()
b

Python multiple inheritance: Whats wrong doing it dynamically?

Based on this answer, of how __new__ and __init__ are supposed to work in Python,
I wrote this code to dynamically define and create a new class and object.
class A(object):
def __new__(cls):
class C(cls, B):
pass
self = C()
return self
def foo(self):
print 'foo'
class B(object):
def bar(self):
print 'bar'
a = A()
a.foo()
a.bar()
Basically, because the __new__ of A returns a dynamically created C that inherits A and B, it should have an attribute bar.
Why does C not have a bar attribute?
Resolve the infinite recursion:
class A(object):
def __new__(cls):
class C(cls, B):
pass
self = object.__new__(C)
return self
(Thanks to balpha for pointing out the actual question.)
Since there is no actual question in the question, I am going to take it literally:
Whats wrong doing it dynamically?
Well, it is practically unreadable, extremely opaque and non-obvious to the user of your code (that includes you in a month :P).
From my experience (quite limited, I must admit, unfortunately I don't have 20 years of programming under the belt), a need for such solutions indicates, that the class structure is not well defined, - means, there's almost always a better, more readable and less arcane way to do such things.
For example, if you really want to define base classes on the fly, you are better off using a factory function, that will return appropriate classes according to your needs.
Another take on the question:
Whats wrong doing it dynamically?
In your current implementation, it gives me a "maximum recursion depth exceeded" error. That happens, because A.__new__ calls itself from within itself indefinitely (since it inherits from itself and from B).
10: Inside A.__new__, "cls" is set to <class '.A'>. Inside the constructor you define a class C, which inherits from cls (which is actually A) and another class B. Upon instantiating C, its __new__ is called. Since it doesn't define its own __new__, its base class' __new__ is called. The base class just happens to be A.
20: GOTO 10
If your question is "How can I accomplish this" – this works:
class A(object):
#classmethod
def get_with_B(cls):
class C(B, cls):
pass
return C()
def foo(self):
print 'foo'
class B(object):
def bar(self):
print 'bar'
a = A.get_with_B()
a.foo()
a.bar()
If your question is "Why doesn't it work" – that's because you run into an infinite recursion when you call C(), which leads to A.__new__ being called, which again calls C() etc.

Does Python have class prototypes (or forward declarations)?

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.

Categories