Does Python have class prototypes (or forward decl

2019-08-19 01:00发布

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).

6条回答
趁早两清
2楼-- · 2019-08-19 01:35

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>
查看更多
走好不送
3楼-- · 2019-08-19 01:38

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?"

查看更多
地球回转人心会变
4楼-- · 2019-08-19 01:39

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.

查看更多
Anthone
5楼-- · 2019-08-19 01:45

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()
查看更多
爷、活的狠高调
6楼-- · 2019-08-19 01:53

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()
查看更多
Fickle 薄情
7楼-- · 2019-08-19 01:53

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.

查看更多
登录 后发表回答