Найти - Пользователи
Полная версия: Самодельный внешний модуль не выполняет инструкцию "tkinter" ".bell()"
Начало » Python для новичков » Самодельный внешний модуль не выполняет инструкцию "tkinter" ".bell()"
1 2 3 4 5 6 7 8
Olezhka
Здравствуйте, знатоки! Опять написал внешний модуль. Вот он:
 import sys
import tkinter as tk
from tkinter import *
def txttagtolist(tags):
    tag_test = repr(tags[0])
    if '<string object: ' in tag_test:
        clear_tags = []
        for i in range(1, len(tags), 2):
            z = repr(tags[i])
            z = z.split(": '")[1]
            z = z.split("'")[0]
            clear_tags.append(z)
        return clear_tags
    else:
        
        # ПРОБЛЕМА ТУТ!
        #bell() # NameError: name 'bell' is not defined
        #root.bell() # NameError: name 'root' is not defined
        tk.bell() # AttributeError: module 'tkinter' has no attribute 'bell'
        # ПРОБЛЕМА ТУТ!
        
        color = sys.stdout.shell
        color.write("ERROR!\n", "console")
        try:
            root.destroy()
        except:
            pass
        sys.exit()
Модуль вызывается из основной программы. В основной программе уже прописан импорт:
 from tkinter import *
Я повторно прописал этот же импорт и в самом модуле. Не помогло! Инструкция “.bell()” никак не хочет вызываться из модуля! Почему? Где я напортачил? Подскажите, пожалуйста, специалисты! И еще вопрос. Вопрос по самому механизму подключения внешних модулей. Как я понял, при импорте модуля в основную программу весь код модуля выполняется и подключается к основной программе. То есть код модуля как бы внедряется в код основной программы. Я правильно понял? Но почему тогда модуль, будучи внедренным в основную программу, не видит, какие еще другие модули подключены в основной программе, не видит переменные, используемые в основной программе, и не может ими пользоваться?
py.user.next
Вот пример
  
>>> import tkinter
>>> 
>>> root = tkinter.Tk()
>>> root.bell()
>>> root.mainloop()
>>> 
У меня он ничего не выдаёт. Может, у тебя выдаст. Но всё работает, как видишь.

А в твоём коде корневого окна нет.

Olezhka
Как я понял, при импорте модуля в основную программу весь код модуля выполняется и подключается к основной программе.
При импорте модуля весь импортированный модуль выполняется и всё. А сама инструкция import создаёт имя, к которому привязан этот импортированный модуль в качестве объекта.

  
>>> import tkinter
>>> tkinter
<module 'tkinter' from '/usr/lib64/python3.6/tkinter/__init__.py'>
>>> 
>>> import math
>>> math
<module 'math' from '/usr/lib64/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so'>
>>> 
>>> id(math)
140241028221432
>>> 
>>> math.__doc__
'This module is always available.  It provides access to the\nmathematical functions defined by the C standard.'
>>>
>>> type(math)
<class 'module'>
>>>

То есть любой модуль после импортирования становится объектом класса module. И потом в этом объекте хранятся поля и методы, как у обычных объектов.

Olezhka
Но почему тогда модуль, будучи внедренным в основную программу, не видит, какие еще другие модули подключены в основной программе, не видит переменные, используемые в основной программе, и не может ими пользоваться?
Модуль просто становится объектом и этот объект привязывается к имени, которое определяется в инструкции import. Имя модуля ничем от других имён не отличается. Ты его можешь добавить в список даже.

  
>>> lst = [math, tkinter]
>>> lst
[<module 'math' from '/usr/lib64/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so'>, <module 'tkinter' from '/usr/lib64/python3.6/tkinter/__init__.py'>]
>>> 
>>> out = [i.__doc__ for i in lst]
>>> out
['This module is always available.  It provides access to the\nmathematical functions defined by the C standard.', 'Wrapper functions for Tcl/Tk.\n\nTkinter provides classes which allow the display, positioning and\ncontrol of widgets. Toplevel widgets are Tk and Toplevel. Other\nwidgets are Frame, Label, Entry, Text, Canvas, Button, Radiobutton,\nCheckbutton, Scale, Listbox, Scrollbar, OptionMenu, Spinbox\nLabelFrame and PanedWindow.\n\nProperties of the widgets are specified with keyword arguments.\nKeyword arguments have the same name as the corresponding resource\nunder Tk.\n\nWidgets are positioned with one of the geometry managers Place, Pack\nor Grid. These managers can be called with methods place, pack, grid\navailable in every Widget.\n\nActions are bound to events by resources (e.g. keyword argument\ncommand) or with the method bind.\n\nExample (Hello, World):\nimport tkinter\nfrom tkinter.constants import *\ntk = tkinter.Tk()\nframe = tkinter.Frame(tk, relief=RIDGE, borderwidth=2)\nframe.pack(fill=BOTH,expand=1)\nlabel = tkinter.Label(frame, text="Hello, World")\nlabel.pack(fill=X, expand=1)\nbutton = tkinter.Button(frame,text="Exit",command=tk.destroy)\nbutton.pack(side=BOTTOM)\ntk.mainloop()\n']
>>>
Olezhka
py.user.next
А в твоём коде корневого окна нет.
Так корневое окно у меня в основной программе есть!
py.user.next
Olezhka
Опять написал внешний модуль.
В этом модуле нет никакого окна вообще.

Olezhka
Так корневое окно у меня в основной программе есть!
root в основной программе и root в модуле - это абсолютно разные root'ы. Модуль определяет свою систему имён. А имена в модулях могут быть вообще одинаковыми, но при этом связаны с полностью различными объектами.

Из-за этого как раз и нельзя импортировать модули через звёздочку типа
  
from tkinter import *
Потому что если в одном модуле будет класс Button и в другом модуле будет класс Button, то ты не сможешь к ним двоим доступ иметь. Поэтому ты сначала импортируешь имя одного модуля, потом импортируешь имя другого модуля, а потом через их имена получаешь доступ через точку к их подименам.

Вот пример правильных импортов
  
>>> import math
>>> import tkinter
>>> 
>>> math.__name__
'math'
>>> 
>>> tkinter.__name__
'tkinter'
>>> 
>>> 
>>> import tkinter as tk
>>> 
>>> tk.__name__
'tkinter'
>>>
Здесь демонстрируется одно и то же имя __name__, которое в каждом модуле привязано к конкретной строке внутри этого модуля.
Olezhka
py.user.next
__doc__
Ух ты! Спасибо! Не знал! А еще прикольную инфу выдает имя “__all__”
Olezhka
py.user.next
root в основной программе и root в модуле - это абсолютно разные root'ы. Модуль определяет свою систему имён. А имена в модулях могут быть вообще одинаковыми, но при этом связаны с полностью различными объектами
Правда? А я тут провел эксперимент. Я написал модуль “module_test”:
 import tkinter as ttk
print('2 = ', id(ttk))
root = ttk.Tk()
root.title('2')
root.mainloop()
Далее создал основную программу и вызвал из нее ранее созданный модуль “module_test”:
 import tkinter as tk
print('1 = ', id(tk))
root = tk.Tk()
root.title('1')
import module_test
root.mainloop()
Создалось 2 окна, а на выходе в консоли я получил:
1 = 2181376353328
2 = 2181376353328

Как же так? Вы утверждаете, что “рут” в основной программе и “рут” в модуле - это 2 разных “рута”… но “ID”-то одинаковые!
Пардон! Ошибся! Я переделал на “print(id(root))” и получил разные “ID”. Но тогда вопрос! Значит из вызванного модуля нельзя уничтожить методом “destroy()” окно основной программы, из которой модуль был вызван? Значит остается только метод “sys.exit()”? Но проблема в том, что после выполнения “sys.exit()” само окно так и остается висеть. Как так? Вот - сами попробуйте:
 from tkinter import *
import sys
root = Tk()
root.after(5000, lambda: sys.exit())
root.mainloop()
py.user.next
Olezhka
Но проблема в том, что после выполнения “sys.exit()” само окно так и остается висеть. Как так? Вот - сами попробуйте:
  
from tkinter import *
import sys
 
root = Tk()
root.after(5000, lambda: sys.exit())
root.mainloop()
У меня закрылось это окно.

Olezhka
Далее создал основную программу и вызвал из нее ранее созданный модуль “module_test”:
Все модули должны импортироваться в самом верху скрипта. Нельзя делать import посередине скрипта.

А делать посередине тебе его приходится потому, что ты не знаешь, как правильно оформлять модули.
Вот так должно быть:
mod1.py
  
import math
import tkinter
 
def main():
    print('hello')
    print('sin(pi/2) =', math.sin(math.pi / 2))
    print('id of tkinter =', id(tkinter))
 
if __name__ == '__main__':
    main()

Ты можешь вызвать этот модуль напрямую. Но также ты можешь импортировать этот модуль в другом модуле и сделать это сверху исходника, где все import'ы расположены.
mod2.py
  
import mod1
 
def main():
    mod1.main()
 
if __name__ == '__main__':
    main()
Тут модуль mod1 симпортировался в модуле mod2, но ничего из модуля mod1 не выполнилось при этом, потому что стоят ворота внизу модуля mod1, которые определяют, он был запущен как модуль или он был импортирован в другом модуле. Если он был запущен как модуль, то из него выполнится главная функция. Если он был импортирован в другом модуле, то главная функция не будет выполняться, а только определится. Кстати, сам модуль mod2 точно так же можно будет импортировать в модуле mod3 и благодаря воротам он так же не будет ничего выполнять при импортировании.

Тут я приложил архив с двумя модулями. Запусти только первый модуль. Потом запусти только второй модуль. При запуске второго модуля ты увидишь, что у него внутри запускается главная функция из первого модуля. Поэтому во втором модуле ты можешь ничего не вычислять, а просто импортировать первый модуль и запустить главную функцию из первого модуля, которая и выполнит все вычисления.
Olezhka
py.user.next
У меня закрылось это окно.
А у меня нет. Как так? У меня Win 11. И еще заметил, что все скомпилированные в “PYINSTALLER” “EXE” создают у меня два процесса в “Диспетчере задач”. Почему?
py.user.next
И ты разберись отдельно с модулями, отдельно с функциями, отдельно с tkinter, потому что они друг к другу вообще отношения не имеют. Это разные независимые друг от друга вещи. Твои проблемы с модулями происходят из того, что ты ничего не читал про модули сами. А tkinter к этому вообще никак не относится. Твои проблемы с окнами происходят из того, что ты ничего не читал по tkinter'у. С модулями эти окна вообще никак не связаны. А с функциями тебе нужно разбираться потому, что ты даже не знаешь, что такое пространства имён. Есть пространство имён функции, есть пространство имён модуля, есть пространство имён класса, есть пространство имён объекта. Имена в разных пространствах могут быть абсолютно одинаковыми, но означать абсолютно разные вещи. Ты можешь найти пространство имён на диске, например. Когда ты создаёшь в одной папке файл file.txt и пишешь в него “привет”, а потом создаёшь в другой папке файл file.txt и пишешь в него “пока”, эти оба файла имеют одно и то же имя, но содержат разное содержимое, а пространствами имён здесь являются папки, в которых эти файлы лежат. Так одни папки можно вкладывать в другие папки. Это и есть принцип пространств имён.

Вот пример тебе
  
#!/usr/bin/env python3
 
class A:
    a = '1a'
    b = '1b'
 
class B:
    a = '2a'
    b = A()
 
class C:
    a = '3a'
    b = '3b'
    c = B()
    
obj = C()
 
print(obj.a)
print(obj.b)
print(obj.c)
 
print(obj.c.a)
print(obj.c.b)
 
print(obj.c.b.a)
print(obj.c.b.b)
Вывод
[guest@localhost py]$ ./mod.py 
3a
3b
<__main__.B object at 0x7fcfb57f1a58>
2a
<__main__.A object at 0x7fcfb57f1940>
1a
1b
[guest@localhost py]$
Olezhka
Olezhka
if __name__ == ‘__main__’:
А вот это имя “__main__” модуль берет из основной программы? Оно для модуля и для основной программы общее?
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB