exec()

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
здравствуйте, в exec() как можно сделать, чтобы не плодить много файлов, а чтобы было всё в одном файле, чтобы в нём было несколько процедур, как их оформить и как вызвать нужную? спасибо, пока, что у меня так:
Код:
with open('MsgBoxOK.py', 'r', encoding='utf-8') as f: module = f.read() # возможно любое текстовое расширение txt, py
exec(module)
файл MsgBoxOK.py вместе с проектом, его содержимое:
Код:
# MsgBox$ "Текст сообщения=Prompt",, "Заголовок=Title" 'VBA OK = 1
title = 'Сообщение' # title = заголовок;
prompt = 'Работа завершена' # prompt = подсказка, \n - абзац
from tkinter import *
def click_button(): root.destroy() # destroy = уничтожать, разрушать
root = Tk()
root.title(title)
root.geometry('300x200')  # ширина Х высота
# названия шрифта, размер, стиль bold=полужирное начертание, normal — нормальное начертание
Label1 = Label(text=prompt, font=('Arial', 12, 'bold'))
Label1.place(x=10, y=10)
# !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
# Label1.pack() # метод pack(), чтобы сделать элемент видимым
btn = Button(text="OK",  # текст кнопки
             background="#555",  # фоновый цвет кнопки
             foreground="#ccc",  # цвет текста
             padx="30",  # ширина
             pady="10",  # высота
             font="16",  # высота шрифта
             command=click_button)  # обработчик кнопки
btn.place(x=180, y=130)
# !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
# btn.pack() # метод pack(), чтобы сделать элемент видимым
root.mainloop()  # оставляем окно открытым
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 581
457
83
не нужно использовать exec
это потенциально опасная функция, так как она может выполнить любой код, в том числе без вашего ведома
то что вы хотите можно добиться другими способами, просто сделать модуль с функциями и импортировать их
но если уж вам необходимо exec (что вряд ли), можно просто погуглить, примеров куча, здесь не буду писать, так как это говнокод
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
понял, но импортируемый модуль это тоже палка о двух концах, что туда зальют прежде чем я pip'ом его установлю ХЗ
 

regnor

Модератор
Команда форума
Модератор
Июл 7, 2020
2 581
457
83
импортируемый модуль это тоже палка о двух концах, что туда зальют прежде чем я pip'ом его установлю ХЗ
причем тут pip?
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
а гуглить то как, я про то, что если exec python - много мусора
exec как разбить объект кода python - тоже не сахар...........
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
сейчас только дошло, что он не понадобится, ок, спасибо, тогда
Код:
# запуск:
import mymodule
mymodule.hello(title=11, prompt=22)
print(title, prompt)
# текст файла mymodule:
def hello(title, prompt):
    print('Hello, world!', title, prompt)
    title += 1
    prompt += 1
    return title, prompt
ошибка name 'title' is not defined. Did you mean: 'tuple'?=не определено
как не определено? указал ведь 11 и с импортируемого модуля мне подтвердило, что дошло до него, поясните плиз
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
как не определено? указал ведь 11 и с импортируемого модуля мне подтвердило, что дошло до него, поясните плиз
Не определено потому, что переменной title не было присвоено значение. title=11 это присвоение значения аргументу функции, а не локальной переменной.
Чтобы работало можно присвоить локальным переменным title, prompt результат выполнения функции hello:
Python:
# запуск:
import mymodule
title, prompt = mymodule.hello(title=11, prompt=22)
print(title, prompt)
# текст файла mymodule:
def hello(title, prompt):
    print('Hello, world!', title, prompt)
    title += 1
    prompt += 1
    return title, prompt
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
Чтобы работало можно присвоить локальным переменным title, prompt результат выполнения функции hello
спасибо конечно знал ответ, но так как редко пользуюсь функциями, вылетает с головы))
ну и теперь уже рабочий пример, то есть всё тоже самое, но чуть изменил, запускаю:
Код:
import MsgBox
title, prompt, btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
print(title, prompt, btn_text)
текст файла MsgBox.py:
Код:
def MsgBoxYesNo(title, prompt, btn_text):
    print('Hello, world!', title, prompt, btn_text)
и ошибка:
Traceback (most recent call last):
File "C:\pythonProject\sudrf.ru1.py", line 2, in <module>
import MsgBox
File "C:\pythonProject\MsgBox.py", line 1
def MsgBoxYesNo(title, prompt, btn_text):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: import * only allowed at module level
мне это: импорт * разрешен только на уровне модуля
ни о чём не говорит, подскажите в чём я ошибся? спасибо
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
SyntaxError: import * only allowed at module level
У вас в коде этого не видно, но видимо вы где-то внутри функции используйте import * from module_name, а это можно делать только на уровне модуля, то есть вне функций.
Также в этой строке будет ошибка:
Python:
title, prompt, btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
так как функция ничего не возвращает (возвращает None) и получить из нее значения для трех переменных не получится.
Чтобы так сделать нужно возвращать 3 значения из функции:

Python:
def MsgBoxYesNo(title, prompt, btn_text):
    print('Hello, world!', title, prompt, btn_text)
    return title, prompt, btn_text
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
спасибо, теперь:
Код:
import MsgBox
title, prompt, btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
print(title, prompt, btn_text)
в файле:
Код:
from tkinter import *
def MsgBoxYesNo(title, prompt, btn_text):
    print(title, prompt, btn_text)
    # from tkinter import * - нужно выносить за пределы функции
    def click_buttonY(): root.destroy(); btn_text = 'Y'; return btn_text # print(btn_text); # exit(0) # destroy = уничтожать, разрушать
    def click_buttonN(): root.destroy(); btn_text = 'N'; return btn_text # print(btn_text); # exit(0) # destroy = уничтожать, разрушать
    root = Tk()
    ............
и не возвращает, ошибка:
Traceback (most recent call last):
File "C:\pythonProject\sudrf.ru1.py", line 3, in <module>
title, prompt, btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
TypeError: cannot unpack non-iterable NoneType object
подскажите пожалуйста, где я ошибся? спасибо
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
TypeError: cannot unpack non-iterable NoneType object
подскажите пожалуйста, где я ошибся? спасибо
Выше я уже говорил что возникнет данная ошибка, так как функция MsgBoxYesNo ничего не возвращает.
Для того чтобы этот код работал:
Python:
title, prompt, btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
нужно чтобы функция MsgBoxYesNo возвращала 3 значения:
Python:
from tkinter import *
def MsgBoxYesNo(title, prompt, btn_text):
    print(title, prompt, btn_text)
    # from tkinter import * - нужно выносить за пределы функции
    def click_buttonY(): root.destroy(); btn_text = 'Y'; return btn_text # print(btn_text); # exit(0) # destroy = уничтожать, разрушать
    def click_buttonN(): root.destroy(); btn_text = 'N'; return btn_text # print(btn_text); # exit(0) # destroy = уничтожать, разрушать
    root = Tk()
    ............
    return title, prompt, btn_text
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
спасибо, сделал всё как сказали (вроде)
Код:
import MsgBox
btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
print('print НЕ из def MsgBoxYesNo, btn_text: ' + btn_text)
# модуль в файле
from tkinter import *
def MsgBoxYesNo(title, prompt, btn_text):
    print('print из def MsgBoxYesNo: ' + title, prompt, btn_text)
    def click_buttonY():
        root.destroy()
        btn_text = 'Y'
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    def click_buttonN():
        root.destroy()
        btn_text = 'N'
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    ..............
        return btn_text
судя по напечатанному в консоли:
print из def MsgBoxYesNo: Заголовок формы 22
32 -ПЕРЕДАЛОСЬ
print из def MsgBoxYesNo, btn_text: Y -ОПРЕДЕЛИЛО
print НЕ из def MsgBoxYesNo, btn_text: -НО НЕ ВЕРНУЛО, ПОЧЕМУ?
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
print НЕ из def MsgBoxYesNo, btn_text: -НО НЕ ВЕРНУЛО, ПОЧЕМУ?
Потому что переменная btn_text = 'Y' определена внутри вложенной функции click_buttonY(), а из функции MsgBoxYesNo возвращает переменная btn_text которая находится в теле функции, а не во вложенных функциях. Если нужно вернуть значение из вложенной функции, то сначала вложенная функция должна вернуть это значение, а она у вас ничего не возвращает.

Python:
import MsgBox
btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
print('print НЕ из def MsgBoxYesNo, btn_text: ' + btn_text)
# модуль в файле
from tkinter import *
def MsgBoxYesNo(title, prompt, btn_text):
    print('print из def MsgBoxYesNo: ' + title, prompt, btn_text)
    def click_buttonY():
        root.destroy()
        btn_text = 'Y'
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
        return btn_text
    def click_buttonN():
        root.destroy()
        btn_text = 'N'
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
        return btn_text
    ..............
        # тут нужно записать результат вложенной функции в переменную btn_text
        # ... (чтобы написать логику нужно видеть полный код и знать что нужно вернуть)
        
        # потом вернуть его
        return btn_text
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
(чтобы написать логику нужно видеть полный код и знать что нужно вернуть)
прилагаю:
Код:
# запуск
import MsgBox
btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
print('print НЕ из def MsgBoxYesNo, btn_text: ' + btn_text)
# модуль с файла
from tkinter import *
def MsgBoxYesNo(title, prompt, btn_text):
    print('print из def MsgBoxYesNo: ' + title, prompt, btn_text)
    # vb_Yes_No = MsgBox("Вопрос", vbYesNo, "MsgBoxДа\Нет") 'VBA Yes = 6, No = 7
    # title = 'sms' # title = заголовок
    # prompt = 'txt' # prompt = подсказка, то есть тело формы, \n - абзац можно применять
    # нужно выносить за пределы функции, иначе бужет ошибка import * only allowed at module level=импорт * разрешен только на уровне модуля
    # from tkinter import *
    def click_buttonY():
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'Y'
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
        return btn_text
    def click_buttonN():
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'N'
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
        return btn_text
    root = Tk()
    # root.resizable(0, 0)  # делает неактивной кнопку Развернуть
    # root.attributes('-toolwindow', True)  # удаляет кнопки Свернуть Развернуть, удаляет Иконку
    ### root.attributes('-disabled', True)  # блокирует кнопки Свернуть Развернуть Закрыть, и остальные элементы при нажатии в любом месте формы раздаётся звук
    # root.attributes('-fullscreen', True)  # делает во весь экран, кнопки Свернуть Развернуть Закрыть отсутствуют
    root.overrideredirect(True)  # отображет форму без шапки формы
    root.title(title)
    w=700 # ширина
    h=200 # высота
    w_monitor=250 # место появления формы на экране, ширина от края экрана
    h_monitor=250 # место появления формы на экране, высота от края экрана
    root.geometry(str(w) + 'x' + str(h) + '+' + str(w_monitor) + '+' + str(h_monitor))
    # названия шрифта, размер, стиль bold=полужирное начертание, normal — нормальное начертание
    Label1 = Label(text=prompt, font=('Arial', 12, 'bold'))
    Label1.place(x=10, y=10)
    # !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
    # Label1.pack() # метод pack(), чтобы сделать элемент видимым
    btnY = Button(text='Yes',  # текст кнопки
             background='#555',  # фоновый цвет кнопки
             foreground='#ccc',  # цвет текста
             padx='30',  # НЕ ширина кнопки, а отступ от границ кнопки до её текста справа и слева justify: устанавливает выравнивание текста, значение LEFT выравнивает текст по левому краю, CENTER - по центру, RIGHT - по правому краю
             pady='10',  # НЕ высота кнопки, отступ от границ кнопки до её текста сверху и снизу justify: устанавливает выравнивание текста, значение LEFT выравнивает текст по левому краю, CENTER - по центру, RIGHT - по правому краю
             font='16',  # высота шрифта
             command=click_buttonY)  # обработчик кнопки
    btnY.place(x=20, y=130, width=50, height=50) # width=ширина кнопки, height=высота кнопки
    # !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
    # btnY.pack() # метод pack(), чтобы сделать элемент видимым
    btnN = Button(text='No',  # текст кнопки
             background='#555',  # фоновый цвет кнопки
             foreground='#ccc',  # цвет текста
             padx='30',  # ширина
             pady='10',  # высота
             font='16',  # высота шрифта
             command=click_buttonN)  # обработчик кнопки
    btnN.place(x=180, y=130, width=50, height=50) # width=ширина кнопки, height=высота кнопки
    # !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
    # btnN.pack() # метод pack(), чтобы сделать элемент видимым
    root.mainloop()  # оставляем окно открытым
    return btn_text
спасибо
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Можно во вложенных функциях изменять значение btn_text с помощью global:
Python:
def MsgBoxYesNo(title, prompt, btn_text):
    print('print из def MsgBoxYesNo: ' + title, prompt, btn_text)
    # vb_Yes_No = MsgBox("Вопрос", vbYesNo, "MsgBoxДа\Нет") 'VBA Yes = 6, No = 7
    # title = 'sms' # title = заголовок
    # prompt = 'txt' # prompt = подсказка, то есть тело формы, \n - абзац можно применять
    # нужно выносить за пределы функции, иначе бужет ошибка import * only allowed at module level=импорт * разрешен только на уровне модуля
    # from tkinter import *
    btn_text = '' # переменная для возврата значения из функции
    def click_buttonY():
        global btn_text  # используем внешнюю переменную внутри функции 
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'Y'  # меняем ее значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)

    def click_buttonN():
        global btn_text   # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'N'  # меняем ее значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)  
    
    ...
    return btn_text
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
спасибо, но ведь так и не передаётся код:
Код:
from tkinter import *
def MsgBoxYesNo(title, prompt, btn_text):
    print('print из def MsgBoxYesNo: ' + title, prompt, btn_text)
    # vb_Yes_No = MsgBox("Вопрос", vbYesNo, "MsgBoxДа\Нет") 'VBA Yes = 6, No = 7
    # title = 'sms' # title = заголовок
    # prompt = 'txt' # prompt = подсказка, то есть тело формы, \n - абзац можно применять
    # нужно выносить за пределы функции, иначе бужет ошибка import * only allowed at module level=импорт * разрешен только на уровне модуля
    # from tkinter import *
    btn_text = '' # переменная для возврата значения из функции
    def click_buttonY():
        global btn_text  # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'Y'  # меняем значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    def click_buttonN():
        global btn_text   # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'N'  # меняем значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    root = Tk()
    # root.resizable(0, 0)  # делает неактивной кнопку Развернуть
    # root.attributes('-toolwindow', True)  # удаляет кнопки Свернуть Развернуть, удаляет Иконку
    ### root.attributes('-disabled', True)  # блокирует кнопки Свернуть Развернуть Закрыть, и остальные элементы при нажатии в любом месте формы раздаётся звук
    # root.attributes('-fullscreen', True)  # делает во весь экран, кнопки Свернуть Развернуть Закрыть отсутствуют
    root.overrideredirect(True)  # отображет форму без шапки формы
    root.title(title)
    w=700 # ширина
    h=200 # высота
    w_monitor=250 # место появления формы на экране, ширина от края экрана
    h_monitor=250 # место появления формы на экране, высота от края экрана
    root.geometry(str(w) + 'x' + str(h) + '+' + str(w_monitor) + '+' + str(h_monitor))
    # названия шрифта, размер, стиль bold=полужирное начертание, normal — нормальное начертание
    Label1 = Label(text=prompt, font=('Arial', 12, 'bold'))
    Label1.place(x=10, y=10)
    # !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
    # Label1.pack() # метод pack(), чтобы сделать элемент видимым
    btnY = Button(text='Yes',  # текст кнопки
             background='#555',  # фоновый цвет кнопки
             foreground='#ccc',  # цвет текста
             padx='30',  # НЕ ширина кнопки, а отступ от границ кнопки до её текста справа и слева justify: устанавливает выравнивание текста, значение LEFT выравнивает текст по левому краю, CENTER - по центру, RIGHT - по правому краю
             pady='10',  # НЕ высота кнопки, а отступ от границ кнопки до её текста сверху и снизу justify: устанавливает выравнивание текста, значение LEFT выравнивает текст по левому краю, CENTER - по центру, RIGHT - по правому краю
             font='16',  # высота шрифта
             command=click_buttonY)  # обработчик кнопки
    btnY.place(x=20, y=130, width=50, height=50) # width=ширина кнопки, height=высота кнопки
    # !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
    # btnY.pack() # метод pack(), чтобы сделать элемент видимым
    btnN = Button(text='No',  # текст кнопки
             background='#555',  # фоновый цвет кнопки
             foreground='#ccc',  # цвет текста
             padx='30',  # ширина
             pady='10',  # высота
             font='16',  # высота шрифта
             command=click_buttonN)  # обработчик кнопки
    btnN.place(x=180, y=130, width=50, height=50) # width=ширина кнопки, height=высота кнопки
    # !!!!!!!!!!!!!! при использовании метода place() не надо использовать метод pack()
    # btnN.pack() # метод pack(), чтобы сделать элемент видимым
    root.mainloop()  # оставляем окно открытым
    return btn_text
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
спасибо, но ведь так и не передаётся код:
Во вложенной функции в переменную btn_text записывается 'Y' или 'N', потом это значение возвращается из функции MsgBoxYesNo и может быть получено в другом файле (в который импортируется модуль MsgBox.py):
Python:
import MsgBox


btn_text = MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text='')
print(btn_text) # здесь выведется Y или N
или нужно чтобы передавалось что-то другое?
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
# здесь выведется Y или N
так в том и дело, что не выводится, на запуск
Код:
import MsgBox

btn_text = (MsgBox.MsgBoxYesNo(title='Заголовок формы', prompt='22\n32', btn_text=''))
print('print НЕ из def MsgBoxYesNo, btn_text: ' + btn_text)
ответ:
print из def MsgBoxYesNo: Заголовок формы 22
32
print из def MsgBoxYesNo, btn_text: Y
print НЕ из def MsgBoxYesNo, btn_text:
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
так в том и дело, что не выводится, на запуск
Ошибся немного, нужно заменить global на nonlocal и должно работать:
Python:
btn_text = '' # переменная для возврата значения из функции
    def click_buttonY():
        nonlocal btn_text  # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'Y'  # меняем значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    def click_buttonN():
        nonlocal btn_text   # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'N'  # меняем значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
 

Ципихович Эндрю

Активный пользователь
Пользователь
Мар 27, 2021
490
25
28
спасибо большое, работает..........и вишенка на торте, как две функции заменить одной?
Код:
def click_buttonY():
        nonlocal btn_text  # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'Y'  # меняем значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    def click_buttonN():
        nonlocal btn_text   # используем внешнюю переменную внутри функции
        root.destroy() # destroy = уничтожать, разрушать
        btn_text = 'N'  # меняем значение
        print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
в ниже разница в одной строке, присваивается Y или N.......
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
и вишенка на торте, как две функции заменить одной?
Можно так:
Python:
# функция
def click_button(txt):
    nonlocal btn_text  # меняем значение внешней переменной
    root.destroy() # destroy = уничтожать, разрушать
    if txt == 'Yes':
        btn_text = 'Y'
    else:
        btn_text = 'N'
    print('print из def MsgBoxYesNo, btn_text: ' + btn_text)
    
# привязка к кнопкам
btnY = Button(..., command=lambda: click_button(btnY['text']))
btnN = Button(..., command=lambda: click_button(btnN['text']))
 

Форум IT Специалистов