Python TypeError:super(type,obj)在使用exec()时

Python TypeError:super(type,obj)在使用exec()时,python,kivy,Python,Kivy,下面是用Kivy编写的整个(测试)应用程序。 这类似于应用程序预览应用程序: 用户输入kv标记文本(参见变量self.kv)和类文本(参见变量self.text)。然后他单击“预览”按钮,并在应用程序的右侧看到结果。 加载kv是使用kivy Builder.load_string()实现的。类加载是使用exec(,globals()实现的 主要问题是,由于某些原因,当我第三次单击“预览”按钮时(前两次单击没有错误): TypeError:super(type,obj):obj必须是type的实例

下面是用Kivy编写的整个(测试)应用程序。 这类似于应用程序预览应用程序: 用户输入kv标记文本(参见变量self.kv)和类文本(参见变量self.text)。然后他单击“预览”按钮,并在应用程序的右侧看到结果。 加载kv是使用kivy Builder.load_string()实现的。类加载是使用exec(,globals()实现的

主要问题是,由于某些原因,当我第三次单击“预览”按钮时(前两次单击没有错误):

TypeError:super(type,obj):obj必须是type的实例或子类型

该错误可能是由于exec(),(如果没有exec,我不会出现此错误)

从kivy.app导入应用
从kivy.lang导入生成器
从kivy.uix.button导入按钮
KV='''
盒子布局:
盒子布局:
方向:“垂直”
编码
代码编辑器
按钮:
文本:“预览”
发布时:app.preview()
预览:
id:预览区
文本:app.text
'''
类别MyApp(应用程序):
def生成(自):
self.\u kv\u文件名='KvEditor\u internal.'+str(self.uid)
self.text=“”
类MyButton(按钮):
def on_触控向下(自身,触控):
如果自碰撞点(*touch.pos):
印刷品(333)
超级(MyButton,self)。打开/按下(触摸)
'''
self.kv='MyButton'
self.root=Builder.load\u串(KV)
def预览(自我):
预览\u区域=self.root.ids.preview\u区域
#如果globals()中的“MyButton”:
#del globals()['MyButton']
#打印('=========================')
#打印([dict(globals())]中的i代表i])
尝试:
exec(self.text,globals())
除:
print('执行类'时出现一些错误)
Builder.unload_文件(self._kv_文件名)
尝试:
预览\u区域。添加\u小部件(Builder.load\u字符串(self.kv,filename=self.\u-kv\u文件名))
例外情况除外,如e:
打印(如getattr(e,r“message”,None)则为message,否则为str(e))
MyApp().run()
如何解决此问题?

问题-预览区域相对较窄
这似乎是可行的,但你能编辑或添加一个例子,请?我愿意 不需要增加预览区域中的按钮数量。我只是 想每次按“预览”后,在预览区我都有 仅反映self.kv和self.text当前文本的内容

例子 下面的示例应用了大多数增强功能,
预览
区域是一个
相对性窗口

main.py 例子 下面的示例演示了一个代码编辑器,它支持对
MyButton
类进行代码更改,并将
MyButton
小部件添加到
GridLayout

main.py
从kivy.app导入应用
从kivy.lang导入生成器
从kivy.properties导入NumericProperty、StringProperty
从kivy.uix.button导入按钮
从kivy.logger导入记录器
来自kivy工厂进口工厂
KV='''
盒子布局:
盒子布局:
方向:“垂直”
编码
代码编辑器
按钮:
文本:“预览”
发布时:app.preview()
预览:
id:预览区
:
文本:app.text
:
科尔斯:3
'''
类别MyApp(应用程序):
i=数值属性(0)
text=StringProperty(“”)
previous_text=StringProperty(“”)
def生成(自):
self.\u kv\u文件名='KvEditor\u internal.'+str(self.uid)
self.text=“”
类MyButton(按钮):
def on_触控向下(自身,触控):
如果自碰撞点(*touch.pos):
打印(f“touch.pos={touch.pos}”)
打印(f“Button.text={self.text}”)
返回真值#触地时消耗并不传播
#返回错误
返回超级(按钮,自我)。打开触摸向下(触摸)
'''
self.previous_text=self.text
self.kv='MyButton'
self.root=Builder.load\u串(KV)
def预览(自我):
预览\u区域=self.root.ids.preview\u区域
self.text=self.root.ids.code\u editor.text
尝试:
#类加载是使用exec(,globals()实现的
exec(self.text,globals())
例外情况除外,如消息:
打印('\n异常:当执行类''
Logger.error(“KivyApp:Exception:执行类时出现一些错误”)
打印(msg)
退出
Builder.unload_文件(self._kv_文件名)
尝试:
#检查代码更改
如果self.text!=self.previous_文本:
工厂。未注册(self.kv)
Factory.register(self.kv,cls=globals()['MyButton']))
总计\u children=len(预览\u area.children)
预览\u区域。清除\u小部件()
对于范围内的子项(总子项):
btn=Builder.load\u字符串(self.kv,filename=self.\u kv\u filename)
btn.text=str(子项+1)
预览\区域。添加\小部件(btn)
self.previous_text=self.text
self.i+=1
btn=Builder.load\u字符串(self.kv,filename=self.\u kv\u filename)
btn.text=str(self.i)
预览\区域。添加\小部件(btn)
例外情况除外,如e:
打印(如getattr(e,r“message”,None)则为message,否则为str(e))
MyApp().run()
输出

您能显示stacktrace吗?现在你有了
,除了:
s,这会阻止它显示出来,就我所知?,同样没有try/ecxeptWhat if MyButton类存在,但我想对这个类进行更改,例如更改它的一些方法,等等?我认为有必要删除以前创建的MyButton,每次我都尝试使用del(它保留在代码中),但由于某些原因,它没有删除work@me2beats:请查看更新的帖子以支持代码更改。它似乎可以工作,但您可以
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button

KV = '''
BoxLayout:
    BoxLayout:
        orientation: 'vertical'

        CodeEd
            id: code_editor

        Button:
            text: 'Preview'
            on_release: app.preview()

    Preview:
        id: preview_area

<CodeEd@TextInput>
    text: app.text

<Preview@RelativeLayout>
'''

class MyApp(App):
    def build(self):
        self._kv_filename = 'KvEditor_internal.' + str(self.uid)

        self.text = '''
class MyButton(Button):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print (333)
        super(MyButton, self).on_touch_down(touch)


'''
        self.kv = 'MyButton'

        self.root = Builder.load_string(KV)


    def preview(self):
        preview_area = self.root.ids.preview_area

        #if 'MyButton' in globals():
        #    del globals()['MyButton']

        #print ('===================')
        #print ([i for i in dict(globals())])

        try:
            exec(self.text, globals())
        except:
            print ('some error when exec class ')

        Builder.unload_file(self._kv_filename)

        try:

            preview_area.add_widget(Builder.load_string(self.kv, filename=self._kv_filename))

        except Exception as e:
            print (e.message if getattr(e, r"message", None) else str(e))


MyApp().run()
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.properties import NumericProperty, StringProperty
from kivy.factory import Factory

KV = '''
BoxLayout:
    BoxLayout:
        orientation: 'vertical'

        CodeEd
            id: code_editor

        Button:
            text: 'Preview'
            on_release: app.preview()

    Preview:
        id: preview_area

<CodeEd@TextInput>
    text: app.text

<Preview@RelativeLayout>
'''


class MyApp(App):
    text = StringProperty('')
    previous_text = StringProperty('')

    def build(self):
        self._kv_filename = 'KvEditor_internal.' + str(self.uid)

        self.text = '''
class MyButton(Button):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print (333)
        return super(Button, self).on_touch_down(touch)
'''

        self.previous_text = self.text
        self.kv = 'MyButton'

        self.root = Builder.load_string(KV)

    def preview(self):
        preview_area = self.root.ids.preview_area
        self.text = self.root.ids.code_editor.text

        try:
            # Class loading is implemented using exec(, globals())
            exec(self.text, globals())
        except:
            print('some error when exec class ')

        Builder.unload_file(self._kv_filename)

        try:
            # check for code changes
            if self.text != self.previous_text:
                Factory.unregister(self.kv)
                Factory.register(self.kv, cls=globals()[self.kv])
                total_children = len(preview_area.children)
                preview_area.clear_widgets()
                for child in range(total_children):
                    preview_area.add_widget(Builder.load_string(self.kv, filename=self._kv_filename))
                self.previous_text = self.text

            preview_area.add_widget(Builder.load_string(self.kv, filename=self._kv_filename))

        except Exception as e:
            print(e.message if getattr(e, r"message", None) else str(e))


MyApp().run()
from kivy.properties import NumericProperty, StringProperty
from kivy.factory import Factory
from kivy.logger import Logger
...
class MyApp(App):
    i = NumericProperty(0)
    text = StringProperty('')
    previous_text = StringProperty('')

    def build(self):
        ...
        self.text = '''
        ...
            return True    # consumed on_touch_down & don't propagate
        # return False
        return super(Button, self).on_touch_down(touch)
'''

        self.previous_text = self.text
        ...

    def preview(self):
        preview_area = self.root.ids.preview_area

        self.text = self.root.ids.code_editor.text
        ...
        try:
            # check for code changes
            if self.text != self.previous_text:
                Factory.unregister(self.kv)
                Factory.register(self.kv, cls=globals()[self.kv])
                total_children = len(preview_area.children)
                preview_area.clear_widgets()
                for child in range(total_children):
                    btn = Builder.load_string(self.kv, filename=self._kv_filename)
                    btn.text = str(child + 1)
                    preview_area.add_widget(btn)
                self.previous_text = self.text
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty, StringProperty
from kivy.uix.button import Button
from kivy.logger import Logger
from kivy.factory import Factory

KV = '''
BoxLayout:
    BoxLayout:
        orientation: 'vertical'

        CodeEd
            id: code_editor

        Button:
            text: 'Preview'
            on_release: app.preview()

    Preview:
        id: preview_area

<CodeEd@TextInput>:
    text: app.text

<Preview@GridLayout>:
    cols: 3
'''


class MyApp(App):
    i = NumericProperty(0)
    text = StringProperty('')
    previous_text = StringProperty('')

    def build(self):
        self._kv_filename = 'KvEditor_internal.' + str(self.uid)

        self.text = '''
class MyButton(Button):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            print(f"touch.pos={touch.pos}")
            print(f"Button.text={self.text}")
            return True    # consumed on_touch_down & don't propagate
        # return False
        return super(Button, self).on_touch_down(touch)
'''

        self.previous_text = self.text
        self.kv = 'MyButton'

        self.root = Builder.load_string(KV)

    def preview(self):
        preview_area = self.root.ids.preview_area

        self.text = self.root.ids.code_editor.text

        try:
            # Class loading is implemented using exec(, globals())
            exec(self.text, globals())
        except Exception as msg:
            print('\nException: some error when exec class ')
            Logger.error("KivyApp: Exception: some error when exec class")
            print(msg)
            quit()

        Builder.unload_file(self._kv_filename)

        try:
            # check for code changes
            if self.text != self.previous_text:
                Factory.unregister(self.kv)
                Factory.register(self.kv, cls=globals()['MyButton'])
                total_children = len(preview_area.children)
                preview_area.clear_widgets()
                for child in range(total_children):
                    btn = Builder.load_string(self.kv, filename=self._kv_filename)
                    btn.text = str(child + 1)
                    preview_area.add_widget(btn)
                self.previous_text = self.text

            self.i += 1
            btn = Builder.load_string(self.kv, filename=self._kv_filename)
            btn.text = str(self.i)
            preview_area.add_widget(btn)

        except Exception as e:
            print(e.message if getattr(e, r"message", None) else str(e))


MyApp().run()