Does Python have class prototypes (or forward declarations)?

前端 未结 6 1732
不思量自难忘°
不思量自难忘° 2020-11-28 10:06

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         


        
相关标签:
6条回答
  • 2020-11-28 10:08

    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.

    0 讨论(0)
  • 2020-11-28 10:09

    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.

    0 讨论(0)
  • 2020-11-28 10:12

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

    0 讨论(0)
  • 2020-11-28 10:14

    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()
    
    0 讨论(0)
  • 2020-11-28 10:21

    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>
    
    0 讨论(0)
  • 2020-11-28 10:22

    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()
    
    0 讨论(0)
提交回复
热议问题