Python超级方法:未定义类名

时间:2016-02-02 09:18:14

标签: python django namespaces

我在另一个类中定义了一个类。基本上我试图覆盖db.Model中的save方法 - 它实际上只是django.db.models.Model。但是当我运行这段代码时,我看到了NameError

class GameCenterDB:
    class GameCenterDBConfig:
        class Config:
            db_for_read = "game_center_db.slave"
            db_for_write = "default"

    class PublisherTab(GameCenterDBConfig, db.Model):
        publisher_id = db.PositiveIntegerField(primary_key=True)
        name = db.CharField(max_length=100)
        create_time = db.PositiveIntegerField()
        update_time = db.PositiveIntegerField()

        class Meta:
            db_table = u'publisher_tab'

        def save(self, *args, **kwargs):
            curr_time = int(time.time())
            if not self.create_time:
                self.create_time = curr_time
            self.update_time = curr_time
            # See the line below, this triggers an error
            # NameError: global name 'PublisherTab' is not defined
            super(PublisherTab, self).save(*args, **kwargs)

根据我的理解,当它在GameCenterDB中时,我应该可以直接使用PublisherTab吗?

NameError: global name 'PublisherTab' is not defined

像这样改变save方法将解决错误。但我只是不明白为什么。

def save(self, *args, **kwargs):
     curr_time = int(time.time())
     if not self.create_time:
         self.create_time = curr_time
     self.update_time = curr_time
     super(GameCenterDB.PublisherTab, self).save(*args, **kwargs)

此外,似乎class PublisherTab(GameCenterDBConfig, db.Model):被解释没有任何错误,并且mixin工作。为什么GameCenterDBConfig可以毫无问题地使用?

2 个答案:

答案 0 :(得分:2)

“根据我的理解,当它在GameCenterDB中时,我应该可以直接使用PublisherTab吗?”

错误。 Python要求使用类或变量(通常为“self”)前缀对类成员进行完全限定。对于在类中声明的任何成员变量都是如此。 E.g:

class Foo:
    class Bar:
        quux = 1
    def f(self):
        print "Foo.Bar.quux: %d" % Foo.Bar.quux
        print "self.Bar.quux: %d" % self.Bar.quux
foo = Foo()
foo.f()

现在考虑这个例子:

# scope is top-level module
class Foo:
   # scope is Foo
    class Bar:
        # scope is Foo.Bar
        quux = 1
    # scope is Foo
    Bar.quux = 2 # [A]
    try:
        print "x: %d" % x
    except NameError:
        print "x gave an error because it is outside scope"
    def f(self):
        # scope is Foo when we are defining but not when we are running!
        try:
            print "Bar.quux: %d" % Bar.quux
        except NameError:
            print "Bar.quux gave us an error because it is outside scope"
        print "Foo.Bar.quux: %d" % Foo.Bar.quux
        print "self.Bar.quux: %d" % self.Bar.quux
        print "x is in scope: %d" % x
# scope is top-level module again
x = 456
foo = Foo()
foo.f()

我在[A]添加了代码。程序现在打印“2”而不是“1”。

为什么你不需要在[A]中对Bar.quux进行限定,但是你在f()中做了什么?

因为运行[A]时,脚本位于类Foo的范围内。

但是当运行foo.f()时,脚本位于模块的范围内,因为这是您从中调用它的位置。这就是为什么你需要在方法定义中明确声明self,而foo.f()Foo.f(foo)的语法糖。

这是Python不太令人满意的部分之一。这很有道理很难理解。

答案 1 :(得分:0)

你想这样做:

class GameCenterDB(object):
    class GameCenterDBConfig(object):
        class Config(object):
            pass

    class PublisherTab(GameCenterDB.GameCenterDBConfig, db.Model):
        pass

        class Meta:
            pass

        def save(self, *args, **kwargs):
            super(GameCenterDB.PublisherTab, self).save(*args, **kwargs)

您需要从全局范围引用这些类名。