【问题标题】:Calling a class method from another class causes metaclass conflict从另一个类调用类方法会导致元类冲突
【发布时间】:2017-09-01 16:51:00
【问题描述】:

我有一个 Python Web 应用程序,我想定义一个通用类或函数来处理网页,并从更具体的类中调用它以用于特定的页面实例。

错误:

元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类

我检查了有关该错误消息的所有 StackOverflow 问题和答案,但不理解给出的解释(我发现了一篇关于元类的文章,但我不理解 - OOP 不是我真正的东西)。我还查看了有关从另一个类调用类方法的所有 StackOverflow 问题和答案(也没有理解它们)。

代码:

import webapp2
from datetime import datetime, timedelta

from google.appengine.ext import ndb
from google.appengine.api import users

import admin_templates
import authenticate

class myPage(webapp2.RequestHandler):
    def get(pageInstance):
        pageInstance.outputHtml()

    def outputHtml(pageInstance,pageTitle,pageContent):
        adminLink = authenticate.get_adminlink()
        authMessage = authenticate.get_authmessage()
        adminNav = authenticate.get_adminnav()
        pageInstance.response.headers['Content-Type'] = 'text/html'
        html = admin_templates.base
        html = html.replace('#title#', pageTitle)
        html = html.replace('#authmessage#', authMessage)
        html = html.replace('#adminlink#', adminLink)
        html = html.replace('#adminnav#', adminNav)
        html = html.replace('#content#', pageContent)
        pageInstance.response.out.write(html)
        pageInstance.response.out.write(admin_templates.footer)

class AuditorsPage(webapp2.RequestHandler, myPage.outputHtml):
    def get(self):
        self.output_auditors()

    def output_auditors(self):
        self.outputHtml(admin_templates.auditors_title, admin_templates.auditors_content)

如何从AuditorsPage 类调用myPage 类中的outputHtml 方法而不出现元类错误?

【问题讨论】:

  • 为什么AuditorsPage 试图从myPage方法 继承?
  • 无特殊原因!只是我无能!
  • 感谢@bruntime 的编辑,这是一个改进

标签: python metaclass


【解决方案1】:

试试这个:

myPage.outputHtml()

代替:

self.outputHtml()

【讨论】:

    【解决方案2】:

    根据您的问题,我猜您想从 myPage 继承方法。如果是这样,而不是:

    class AuditorsPage(webapp2.RequestHandler, myPage.outputHtml):
    

    试试:

    class AuditorsPage(webapp2.RequestHandler, myPage):
    

    【讨论】:

    • 我试过这个并得到以下错误:TypeError: Error when calling the metaclass bases Cannot create a consistent method resolution order (MRO) for bases myPage, RequestHandler
    • 这无济于事,因为 myPage 类中的方法没有 self 作为第一个参数,因此 Python 无法为它们找出 MRO。
    【解决方案3】:

    AuditorsPage 类可以继承自 myPage

    import webapp2
    from datetime import datetime, timedelta
    
    from google.appengine.ext import ndb
    from google.appengine.api import users
    
    import admin_templates
    import authenticate
    
    class myPage(webapp2.RequestHandler):
        def get(pageInstance):
            pageInstance.outputHtml()
    
        def outputHtml(pageInstance,pageTitle,pageContent):
            adminLink = authenticate.get_adminlink()
            authMessage = authenticate.get_authmessage()
            adminNav = authenticate.get_adminnav()
            pageInstance.response.headers['Content-Type'] = 'text/html'
            html = admin_templates.base
            html = html.replace('#title#', pageTitle)
            html = html.replace('#authmessage#', authMessage)
            html = html.replace('#adminlink#', adminLink)
            html = html.replace('#adminnav#', adminNav)
            html = html.replace('#content#', pageContent)
            pageInstance.response.out.write(html)
            pageInstance.response.out.write(admin_templates.footer)
    
    class AuditorsPage(myPage):
        def get(self):
            self.output_auditors()
    

    然后就可以实例化 AuditorsPage() 直接调用outputHtml

    foo = AuditorsPage()
    
    foo.outputHtml(admin_templates.auditors_title, admin_templates.auditors_content)
    

    【讨论】:

    • 这非常接近,但它仍然抛出错误,我认为因为你需要一个方法,而不是一个属性。
    【解决方案4】:

    好的,所以您不会为 AuditorsPage 调用 super:

    class myPage():
    
        def __init__(self):
            pass
    
        def outputHtml(self):
            print("outputHTML")
    
    
    class AuditorsPage(myPage):
    
        def __init__(self):
            super().__init__()
    
        def output(self):
            print("AuditorsPage")
    

    我正在使用一个非常精简的版本来解释发生了什么。如您所见,我们有您的 myClass 类。从 AuditorsPage 创建对象时,我们现在可以按预期访问方法 outputHTML。希望这可以帮助。

    【讨论】:

      【解决方案5】:

      错误来自您从通用类中的方法继承类的事实,这是无法完成的。实际上,您的代码是错误的,至少有两种方法可以修复它:

      1) 改为从 myPage 继承:在这种情况下,它将不起作用并且会带来 MRO 错误,因为您的方法不是该类的任何实例的一部分,因为它们没有使用 self 链接到对象作为第一个参数。

      在这种情况下,这是您的代码的修复方法:

      from google.appengine.ext import ndb
      from google.appengine.api import users
      
      import admin_templates
      import authenticate
      
      class myPage(webapp2.RequestHandler):
          def get(self, pageInstance):
              pageInstance.outputHtml()
      
          def outputHtml(self, pageInstance,pageTitle,pageContent):
              adminLink = authenticate.get_adminlink()
              authMessage = authenticate.get_authmessage()
              adminNav = authenticate.get_adminnav()
              pageInstance.response.headers['Content-Type'] = 'text/html'
              html = admin_templates.base
              html = html.replace('#title#', pageTitle)
              html = html.replace('#authmessage#', authMessage)
              html = html.replace('#adminlink#', adminLink)
              html = html.replace('#adminnav#', adminNav)
              html = html.replace('#content#', pageContent)
              pageInstance.response.out.write(html)
              pageInstance.response.out.write(admin_templates.footer)
      
      class AuditorsPage(myPage):
          def get(self):
              self.output_auditors()
      

      2) 只需将m​​yPage类中的两个方法作为没有类的普通方法获取,然后直接从你的类中调用。实际上,您只需要create outputHtml() 方法,然后在您的RequestHandler 子类中的方法中直接调用它(无需self.)。

      【讨论】:

      • 谢谢 - 我使用了你的第一个建议
      猜你喜欢
      • 2015-03-15
      • 1970-01-01
      • 1970-01-01
      • 2016-10-12
      • 2014-02-07
      • 1970-01-01
      • 2012-06-30
      • 1970-01-01
      • 2011-09-09
      相关资源
      最近更新 更多