Форум программистов, компьютерный форум, киберфорум
Python: Решение задач
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.97/29: Рейтинг темы: голосов - 29, средняя оценка - 4.97
0 / 0 / 0
Регистрация: 22.07.2021
Сообщений: 2

Передача переменных в функцию и области видимости

22.07.2021, 02:46. Показов 6462. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем доброго времени суток.
Знаний в языке программирования не много, поэтому прошу не судить строго.
Вопрос возможно для кого-то простой, но найти решения я пока не смог.
Опишу на простом примере.
Есть основной файл с циклом, в котором вызываются и выполняются функции (my1.py).
Есть список, по которому мы идем в цикле (my2.py).
Каждая функция написана в отдельном файле, для удобства (в данном примере все три функции в одном файле my3.py).
Когда код написан в одном файле, все работает, когда разбил отдельно функции по файлам, возникла проблема.
Так вот, нужно чтоб текущую переменную цикла из списка я мог каким-то образом передать в тело функции, например, в func3.
Как решить эту проблему никак не пойму, решил обратиться за помощью..

my1.py
Python
1
2
3
4
5
6
7
from my2 import spisok
from my3 import func1, func2, func3
 
for symb in spisok:
    func1()
    func2()
    func3()
my2.py
Python
1
spisok = ['a','b','c']
my3.py
Python
1
2
3
4
5
6
7
8
def func1():
    print ('func1')
 
def func2():
    print ('func2')
 
def func3():
    print (symb)
Результат нужно получить такого плана:
func1
func2
a
func1
func2
b
func1
func2
c
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.07.2021, 02:46
Ответы с готовыми решениями:

Области видимости переменных, C#
Темный лес для меня эти области видимости, но разбираться надо, большую часть вроде разобрал, но вот тут зашел в тупик: Имеем форму, в...

Области видимости переменных
Скорее всего тут все происходит от незнания. Приведу скрипт. var couchbase = require('couchbase'); var cluster = new...

Области видимости переменных
Когда последняя инструкция в foo присваивает новое значение переменной x, компилятор решает, что это локальная переменная. Следовательно,...

16
5515 / 2868 / 571
Регистрация: 07.11.2019
Сообщений: 4,758
22.07.2021, 06:39
Лучший ответ Сообщение было отмечено Welemir1 как решение

Решение

Python
1
2
3
4
5
6
7
from my2 import spisok
from my3 import func1, func2, func3
 
for symb in spisok:
    func1()
    func2()
    func3(symb)
Python
1
2
3
4
5
6
7
8
def func1():
    print ('func1')
 
def func2():
    print ('func2')
 
def func3(symb):
    print (symb)
2
0 / 0 / 0
Регистрация: 22.07.2021
Сообщений: 2
22.07.2021, 08:46  [ТС]
u235, Да, действительно просто, спасибо!
Немного не хватило мне понимания передать в эту функцию переменную def func3(symb): , везде ее пытался объявить.
В основном коде вроде тоже все заработало.
0
99 / 86 / 20
Регистрация: 10.09.2019
Сообщений: 708
22.07.2021, 09:24
-T0MMY-, не забывайте про локальные области видимости функции.
0
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
23.07.2021, 19:55
-T0MMY-, А вот пример, как с помощью ООП можно с помощью коммутатора из любого модуля передавать значения в переменную любого другого модуля принадлежащего заданной композиции модулей, связанных в единое целое.

commutator.py Основной запускаемый файл.
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import my1 as m1
import my2 as m2
import my3 as m3
 
 
class Prog_Tools:
    def __init__(self):
 
        # ************************ КОММУТАТОР *****************************
        self.m1 = m1               # атрибут для работы с модулем my1 из других модулей
        self.m1.t1 = self          # передача в модуль my1 экземпляра класса Prog_Tools
        self.m2 = m2               # атрибут для работы с модулем my2 из других модулей
        self.m2.t1 = self          # передача в модуль my2 экземпляра класса Prog_Tools
        self.m3 = m3               # атрибут для работы с модулем my3 из других модулей
        self.m3.t1 = self          # передача в модуль my3 экземпляра класса Prog_Tools
 
        # *********************** КОНЕЦ Коммутатора ***********************
 
if __name__ == '__main__':
 
    t1 = Prog_Tools()              # Создание экземпляра t1 класса Prog_Tools
    t1.m1.main()

my1.py
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
t1 = None              # экземпляр класса Prog_Tools (присваивается из модуля program_Tools)
 
def main():
    for i in range(1, len(t1.m2.spisok)+1):
        t1.m3.func1(i)
        t1.m3.func2(i)
        t1.m3.func3(i)
    print(*t1.m2.spisok1, sep = '\n')
    print(*t1.m2.spisok2, sep = '\n')
    print(*t1.m2.spisok3, sep = '\n')

my2.py
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
t1 = None              # экземпляр класса Prog_Tools (присваивается из модуля program_Tools)
 
spisok = ['a','b','c']
spisok1 = []
spisok2 = []
spisok3 = []

my3.py
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
t1 = None              # экземпляр класса Prog_Tools (присваивается из модуля program_Tools)
 
con = 0
def func1(n):
    if n == 1:
        t1.m2.spisok1.append('func1')
    elif n == 2:
        t1.m2.spisok2.append('func1')
    elif n == 3:
        t1.m2.spisok3.append('func1')
 
def func2(n):
    if n == 1:
        t1.m2.spisok1.append('func2')
    elif n == 2:
        t1.m2.spisok2.append('func2')
    elif n == 3:
        t1.m2.spisok3.append('func2')
 
def func3(n):
    if n == 1:
        t1.m2.spisok1.append(t1.m2.spisok[n-1])
    elif n == 2:
        t1.m2.spisok2.append(t1.m2.spisok[n-1])
    elif n == 3:
        t1.m2.spisok3.append(t1.m2.spisok[n-1])

Все четыре файла должны находится в одном каталоге.
Алгоритм такой:
Загружается коммутатор, связывающий все модули.
Из главного сценария с коммутатором запускается основная функция main из модуля my1.py .
Эта функция в цикле запускает функции из модуля my3.py.
Функции из модуля my3.py заполняют три списка в модуле my2.py .
Затем функция main из модуля my1.py распечатывает списки сформированные в модуле my2.py

Добавлено через 17 минут
-T0MMY-, Если Вы ООП еще не изучали, то может пригодится в будущем.
1
99 / 86 / 20
Регистрация: 10.09.2019
Сообщений: 708
23.07.2021, 20:51
Viktorrus, ознакомился с вашей идеей с сетевой структурой модулей, очень интересно. Подробная документация по использованию была бы кстати. У меня, например, проблема была другого характера, импорта модулей из каталога выше и их взаимосвязь. Если бы ваша технология решала и эту проблему было бы очень круто, я бы попробовал прикрутить и к своему проекту что нибудь. Ну или реализовать примеры на PyQt или PySide.
0
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
24.07.2021, 01:57
Цитата Сообщение от AlexMarkov Посмотреть сообщение
У меня, например, проблема была другого характера, импорта модулей из каталога выше
Эта технология достаточно подробно (с примерами) описана у Лутца. Но материал достаточно сложный для понимания. Я не стал его подробно изучать, пробежался бегло, так как предпочитаю все модули помещать в один каталог. Так меньше мороки.
А вот если модули с данными, и они размещены кем то в разных каталогах, то импортировать модули из других каталогов уже придется.
Я про импорт из других каталогов читал в 4-ом издании Лутца. А в 5-ом издании эту тему пропустил.
Вам нужно почитать про пакеты при импорте модулей. Пакетом Лутц называет путь к импортируемому модулю.
"Основы импортирования пакетов.
На элементарном уровне операции импортирования пакетов прямолинейны —
там, где в операторах import находилось имя простого файла, взамен можно указать
путь с именами, разделенными точками:
import dirl.dir2.mod "
Смотрите Лутц М. Изучаем Python (том 1, 5-е издание, 2019) Глава 24 "Пакеты модулей"
Раздел Основы импортирования пакетов стр. 721-755. (материал сложный).
AlexMarkov, Что касается создания сети связанных модулей, то я завтра на примере выше поясню как связать модули в сеть и как такая сеть работает.

Добавлено через 17 минут
AlexMarkov, Если Вы обеспечите импорт модулей из других каталогов, то сетевая структура модулей я думаю и в этом случае будет работать.
0
99 / 86 / 20
Регистрация: 10.09.2019
Сообщений: 708
24.07.2021, 05:37
Viktorrus, импорт из других каталогов уже обеспечен, при прочтении глав о которых вы говорите все и было сделано, правда я не знаю насколько правильно, да и на первом этапе все объекты из простенькой бд в пространстве имён модулей, пока все работает мне этого достаточно, правда приходиться немного подождать при первом запуске модулей пока интерпретатор в оперативу все записывает, а потом норм до выключения или перезагрузки системы, на рабочем компе самое то, он больше ни для чего и не нужен, кроме екселей с вордами, да там и нет ничего больше. Бд типа sql, думаю на PostgreSql, MySql или SqlLite, буду потом прикручивать, если будут данные для обновления бд. Жду ваших решений с сетями связанных модулей ну и примеры, естественно, без примеров сложно понять применимы эти принципы на практике или нет, ну и простенькое README, документирование кода или самодокументирующийся код не помешают.
0
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
24.07.2021, 10:32
AlexMarkov, Питон для меня хобби, и коммерческими продуктами я не занимаюсь. Поэтому ни когда не пользовался средствами для создания документации. Но свои продукты, которые пишу для себя, я тщательно документирую, что бы использовать их в будущем.
У меня есть шаблоны, для создания журналов записей, там все подробно комментировано.
Первый шаблон я создавал первоначально используя сеть модулей. Это более крупный пример, он состоит из 5-ти файлов. Я про него расскажу позже, после объяснения примера выше, в этом топике.
Второй шаблон, это тот же журнал записей, который я сделал, засунув все модули из первого шаблона в один файл. Хотя там нет сети модулей, но использована та же логика и те же обозначения, как в первом шаблоне. Но он Вам в данном случае будет не интересен.
Итак, в следующем комментарии я расскажу о примере выше в этом топике. Код размещен выше, смотрите его, когда я буду объяснять.

Добавлено через 1 час 20 минут
AlexMarkov, "Сеть модулей", или как я еще это называю "агрегированный модуль" состоит из нескольких файлов, которые жестко связаны друг с другом, и с ними можно работать только как с единым целым, состоящим из нескольких частей, каждая из которых находится в отдельном файле.
Для чего это сделано.
Кликните здесь для просмотра всего текста
Каждый файл, это не большой код, который проще проектировать и с ним разбираться, чем когда все свалено в одну кучу в один файл. Но если использовать традиционные цепочки модулей, то там сложно передавать данные между модулями, когда модулей много. Обычно в них передачу данных между модулями осуществляют с помощью функций.
Использование ООП позволяет общаться (передавать данные) между модулями напрямую и достаточно просто.
Создается следующая структура модулей:
Основной модуль "сети модулей" (агрегатора) импортирует на себя все остальные модули (у которых отсутствует импорт других модулей).
Мы грубо говоря имеем как бы аналог компьютерной сети, в которой есть сервер и связанные с ним рабочие станции.

Итак сеть модулей имеет структуру звезды, где есть центральный (главный) модуль и все остальные, связанные с ним модули.
Рассмотрим, как это реализовано в нашем примере.
Сеть модулей в этом примере состоит из:
1) commutator.py - главный модуль (в сети модулей)
и дополнительные модули, которые импортирует главный модуль
2) my1
3) my2
4) my3
Теперь еще немного теории, как создается связь модулей.
Кликните здесь для просмотра всего текста
Все основано на способность экземпляров класса создавать свои изолированные пространства имен из атрибутов этого экземпляра класса.
И что примечательно. Если в некотором месте большой программы, включая разные модули, нам доступен указанный экземпляр класса, то становятся и доступны (в том числе для записи) все его атрибуты из пространства имен этого экземпляра класса.
Код главного модуля commutator.py, идущий после импорта вспомогательных модулей, помещается внутрь класса.
В данном случае это класс
Prog_Tools
Когда мы в дальнейшем создадим экземпляр этого класса, то он создаст свое собственное пространство имен из своих атрибутов.
А дальше встает вопрос. Как получить доступ к этому экземпляру, а значит и к его пространству имен?
Я придумал сделать это так:
Передавать в модули экземпляр создаваемого класса в переменную, которую я называю так же, как и название экземпляра класса. А именно t1.
Делается это вот как:
В каждом из вспомогательный модулей инициализируем переменную t1 = None.

Когда создается экземпляр t1 класса Prog_Tools , при инициализации созданный экземпляр передается во все модули в переменные t1 .
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import my1 as m1
import my2 as m2
import my3 as m3
 
 
class Prog_Tools:
    def __init__(self):
 
        # ************************ КОММУТАТОР *****************************
        self.m1 = m1               # атрибут для работы с модулем my1 из других модулей
        self.m1.t1 = self          # передача в модуль my1 экземпляра класса Prog_Tools
        self.m2 = m2               # атрибут для работы с модулем my2 из других модулей
        self.m2.t1 = self          # передача в модуль my2 экземпляра класса Prog_Tools
        self.m3 = m3               # атрибут для работы с модулем my3 из других модулей
        self.m3.t1 = self          # передача в модуль my3 экземпляра класса Prog_Tools
 
        # *********************** КОНЕЦ Коммутатора ***********************

Теперь посмотрите коды в модулях, и какие строчки не понятны, то спрашивайте, что бы мне не рассказывать о каждой строке в коде модулей.

Добавлено через 19 минут
AlexMarkov, Когда разберетесь с данным в этой теме примером, то посмотрите более крупный пример. Это шаблон "Журнала записей" созданный в виде сети модулей из 4-х файлов, и пятого файла сценария, импортирующего этот агрегированный модуль. Я его выложил в конце темы
Написать программу автосервис
Цитата от туда:
"Схема такая:
1. файл сценария journalRecordsPattern.py импортирует модуль program_Tools.py , который является главной частью (базовым модулем-частью) агрегированного модуля состоящего из следующих частей:
2. program_Tools.py - главная часть агрегированного модуля,
3. input_Data.py - модуль входных данных (часть агрегированного модуля),
4. output_Data.py - модуль выходных данных (часть агрегированного модуля),
5. journal.py - модуль журнала (часть агрегированного модуля), который является основной содержательной частью проекта (цифровой моделью реального журнала записей)."

Добавлено через 18 минут
AlexMarkov, Я использую короткие имена в цепочке пути при обращении к нужной переменной в другом модуле, мне так удобнее. А то при развернутых именах цепочки пути получатся длинными. Но вы можете использовать и полные имена в цепочке пути. Может Вам так будет удобнее. Это кому как больше нравится.
Недостаток коротких имен, это помнить, что они обозначают. Но я продумал мини язык для создания таких имен, и постоянно пользуясь этой технологией, у меня нет проблем помнить, что обозначает каждая короткая переменная.
Правило создания коротких имен описано в шаблоне "Журнала записей" в файле program_Tools.py , который выложен в теме, ссылку на которую я дал.
2
99 / 86 / 20
Регистрация: 10.09.2019
Сообщений: 708
24.07.2021, 16:37
Цитата Сообщение от Viktorrus Посмотреть сообщение
spisok1 = []
spisok2 = []
spisok3 = []
В задании ТС не было присвоения переменных с empty list, вы доработали код или это необходимость при работе с пространством имен класса Prog_Tools? Добавить наименование экземпляра класса в префиксе названий модуля не составит труда, тем более вы предложили варианты для быстрого поиска коротких имен, при работе с внутренними структурами данных дополнительные преобразования не нужны, это усложняет разработку настолько, что все минусы дополнительных преобразований внутренних структур самого pythonа перевешивают плюсы использования пространства имен класса "Агрегированного модуля" , лучше чтобы все работало "под ключ". Сейчас не очень соображаю, так что прошу прощения если вопрос не очень.
Цитата Сообщение от Viktorrus Посмотреть сообщение
con = 0
Зачем эта переменная, нигде не используется?
Также интересен момент добавления модуля в данный пример, если дополнительный код будет выделен, например, красным было бы понятнее. Дополнительный код - еще один модуль m4 с дополнительной внутренней логикой, т.е. как нам включать допом модули для работы с ними?

Добавлено через 3 минуты
Цитата Сообщение от Viktorrus Посмотреть сообщение
Когда разберетесь с данным в этой теме примером, то посмотрите более крупный пример.
При наличии свободного времени, обязательно.
0
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
24.07.2021, 20:00
Цитата Сообщение от AlexMarkov Посмотреть сообщение
В задании ТС не было присвоения переменных с empty list, вы доработали код или это необходимость при работе с пространством имен класса Prog_Tools?
Я расширил условие для того, что бы показать возможности сети модулей. При исходном условии у ТС, применение сети модулей не оправдано усложняет решение, когда можно просто использовать передачу аргумента в функцию, как изначально было предложено выше.
Цитата Сообщение от AlexMarkov Посмотреть сообщение
con = 0
Это мусор, который я забыл удалить, после того, как хотел определять с каким элементом списка spisok идет работа по индексу этого элемента в списке. Потом решил использовать другой алгоритм, а переменную con = 0 забыл удалить.
1
99 / 86 / 20
Регистрация: 10.09.2019
Сообщений: 708
25.07.2021, 06:41
Viktorrus, все очень круто и шустро работает. Думаю использовать вашу идею в следующей версии для редактирования базы данных, для пользователя-программера-разработчика будет самое то для понимания дальнейших целей в выполнении поставленной задачи. Я так понимаю с GUI на tkinter все также хорошо работает? Очень сложно разбираться в чужом коде, поэтому в дальнейшем попробую самостоятельно поработать со своей базой данных, ну и рассмотреть возможность встроенной GUI на Qt. Если будут вопросы, где лучше их задавать, здесь, в блоге или в отдельной теме? В общем, идея зачет, спасибо.
0
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
25.07.2021, 11:56
Цитата Сообщение от AlexMarkov Посмотреть сообщение
Я так понимаю с GUI на tkinter все также хорошо работает?
Именно впервые создать класс Prog_Tools в основном сценарии я использовал в проекте с GUI.
Кликните здесь для просмотра всего текста
Проект состоит из 3-х файлов, основного сценария и двух модулей с GUI. У меня возникла проблема с синхронизацией модулей содержащих GUI. И я придумал, как решить эту проблему, поместив код в файле сценария в класс Prog_Tools, через который появилась возможность синхронизировать работу модулей с GUI. Я с любого из этих модулей смог давать команды для другого модуля, для их синхронизации. Но идея создания коммутатора, для объединения любого количества модулей в сеть, это появилось уже позже. Но именно в том проекте эта идея позволила решить проблему, которую по другому я не смог решить. Это не значит, что других решений не может существовать, но мое решение помогло мне справится с проблемой. Для меня использование ООП является наиболее органичным, так как моделирует мой мыслительный процесс. Но графика очень сильно увеличивает объем кода, поэтому он большой. Но программа работающая и включает разные возможности, включая поиск. Так как первоначально я создавал электронную телефонную книжку, то предусмотрена возможность группировки записей по начальной букве. Но эта возможность полезна и для любого журнала записей.

Могу привести код (для трех файлов, размещаемых в одном каталоге ) этого проекта. Это все тот же шаблон журнала записей, но с использованием GUI.

journalEntriesTemplate1.py - основной файл сценария. Его нужно запускать. Может иметь любое название, соответствующее тематике журнала записей.
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
""" "Журнал записей" Шаблон """
# файл journalEntriesTemplate1.pyw (расширение .pyw необходимо для подавления окна DOS)
# в модуле journalEntriesTemplate1 заменить Поле1 внутри кода на название соответствующее теме
# в модуле journalEntriesTemplate1 заменить Поле2 внутри кода на название соответствующее теме
# в модуле journalEntriesTemplate1 заменить Поле3 внутри кода на название соответствующее теме
# в модуле journalEntriesTemplate1 заменить Поле4 внутри кода на название соответствующее теме
# в модуле journalEntriesTemplate1 заменить Поле5 внутри кода на название соответствующее теме
# в модуле journalEntriesTemplate1 заменить Поле6 внутри кода на название соответствующее теме
# в строке 69 заменить название экземпляра программы (имя базы данных), которое присваивается атрибуту nameBook
 
from tkinter import *               # импорт объектов для графического интерфейса
from tkinter.messagebox import *    # импорт объектов для диалоговых окон
import shelve                       # импорт модуля для работы с базой данных 
import journal as mJ                # импорт модуля с формой журнала
import record as mR                 # импорт модуля с формой для одной выбранной записи
 
class Progr:
    # создание класса моделирующего данные программы и ее дествия
    def __init__(self, dbName, j1=None):
        self.j1 = mJ.Journal(dbName)    # создание экземпляра j1 класса Journal
        self.dbName = dbName
        self.fieldnamesRecTab = ('keyRec', 'char', 'field1', 'field2', 'field3', 'commen', 'delR')  # кортеж имен полей записи в таблице
        self.fieldnamesRecTabCyr = ('№№', 'Буква', 'Поле1', 'Поле2', 'Поле3', 'Комментарий', 'тип')  # кортеж имен полей на руском
        self.fieldnamesRec = ('char', 'field1', 'field2', 'field3', 'field4', 'field5', 'field6', 'commen')   # кортеж имен полей для формы с одной записью
        self.fieldnamesRecCyr = {'char':'Буква', 'field1':'Поле1', 'field2':'Поле2', 'field3':'Поле3', 'field4':'Поле4', 'field5':'Поле5', 'field6':'Поле6', 'commen':'Комментарий'} # словарь для перевода полей в кирилицу
        self.fieldnamesRecFull = ('keyRec', 'char', 'field1', 'field2', 'field3', 'field4', 'field5', 'field6',
                            'commen', 'delR')     # кортеж всех полей в записи
 
        self.activCh = 'А'                                      # буква, активная на текущий момент                                        # текущая запись
        self.typeRec = ''                                       # тип выводимых на экран записей, '' - открытые, "с" - скрытые
        self.dicRem = {}                                        # словарь оставшихся не выведенными записей
 
    def load_DB(self):
        # загрузка записей из базы данных db1, при необходимости добавить дополнительные БД
        db1 = shelve.open(self.j1.dbName)     # открытие базы данных (имя берется
                                              # из атрибута dbName экземпляра класса Data)
        self.j1.dic_recs = dict(db1.items())  # загрузка записей из базы данных в атрибут dic_recs
                                              # экземпляра класса Data (в словарь экземпляра класса)
        db1.close()                           # закрытие базы данных
 
    def save_DB(self):
        # сохранение записей в базе данных db1, при необходимости добавить дополнительные БД
        db1 = shelve.open(self.j1.dbName)     # открытие базы данных
        for (key, record) in self.j1.dic_recs.items():  # запись содержимого из словаря dic_recs
            db1[key] = record                       # экземпляра j1 класса Data в базу данных
        db1.close()                           # закрытие базы данных
 
    def open_Journal(self):
        mJ.p1 = p1            # передача в модуль journal экземпляра p1 класса программы Progr
        mJ.fieldnamesRecTab = p1.fieldnamesRecTab       # кортеж имен полей записи в таблице
        mJ.fieldnamesRecTabCyr = p1.fieldnamesRecTabCyr # кортеж имен полей на руском
        mJ.fieldnamesRec = p1.fieldnamesRec             # кортеж имен полей для формы с одной записью
        mJ.fieldnamesRecCyr = p1.fieldnamesRecCyr       # словарь для перевода полей в кирилицу
        mJ.fieldnamesRecFull = p1.fieldnamesRecFull     # кортеж всех полей в записи
        mJ.window = mJ.makeWidgets()    # создание формы
        mJ.fetchChr('А')                # вывод в качестве стартовой страницу с буквой "А"
        mJ.window.mainloop()            # передача управления форме
 
    def open_Record(self):
        mR.p1 = p1             # передача в модуль record экземпляра p1 класса программы Progr
        mR.fieldnamesRec = p1.fieldnamesRec   # имена полей у записи (передается в модуль record)
        mR.fieldnamesRecCyr = p1.fieldnamesRecCyr   # словарь для перевода полей в кирилицу (передается в модуль record)
        mR.record = p1.j1.dic_recs[p1.j1.currentKey]    # экземпляр записи для вывода в форме в модуле
        mR.winRec = mR.makeWidgets()       # создание в модуле формы с одной записью
        mR.fetchRecord(mR.record)         # вывод в форме в модуле указанной записи
        mR.winRec.mainloop()                  # передача управления форме в модуле
 
if __name__ == '__main__':
    p1 = Progr("Записи")     # создание экземпляра класса Progr
    p1.load_DB()             # загрузка записей из внешней БД в словарь dic_recs
 
    p1.open_Journal()


В один комментарий все не влазит, поэтому разобью комментарий на части.
1
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
25.07.2021, 12:00
journal.py - модуль с GUI общего вида журнала. Название фиксированное.
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# файл journal.py - модуль, импортируемый сценарием journalEntriesTemplate1.py (или journalEntriesTemplate1.pyw)
 
 
from tkinter import *                  # импорт объектов для графического интерфейса
from tkinter.messagebox import *       # импорт объектов для диалоговых окон
import shelve                          # импорт модуля для работы с базой данных 
 
p1 = None                              # экземпляр класса Progr (присваивается из модуля journalEntriesTemplate1)
window = None                          # окно для журнала записей (присваивается из модуля journalEntriesTemplate1)
 
fieldnamesRecTab = None    # кортеж имен полей записи в таблице (передается из journalEntriesTemplate1)
fieldnamesRecTabCyr = None # кортеж имен полей на руском (передается из journalEntriesTemplate1)
fieldnamesRec = None       # кортеж имен полей для формы с одной записью (передается из journalEntriesTemplate1)
fieldnamesRecCyr = None    # словарь для перевода полей в кирилицу (передается из journalEntriesTemplate1)
fieldnamesRecFull = None   # кортеж всех полей в записи (передается из journalEntriesTemplate1)
 
activCh = 'А'                                      # буква, активная на текущий момент                                        # текущая запись
typeRec = ''                                       # тип выводимых на экран записей, '' - открытые, "с" - скрытые
dicRem = {}                                        # словарь оставшихся не выведенными записей
 
class Journal:
    def __init__(self, dbName, currentKey=None, dic_recs={}):
        self.dbName = dbName              # название журнала
        self.currentKey = currentKey      # номер текущей записи в журнале
        self.dic_recs = dic_recs      # словарь записей, который загружается из БД
                                      # и с которым программма динамически работеет,
                                      # чтобы затем измененные данные сохранить в БД
 
class Record:
    # класс Запись
    def __init__(self, keyRec, char, field1, field2, field3, 
                 field4, field5, field6, commen, delR=''):
        # инициализация атрибутов экземпляров класса
        self.keyRec = keyRec                   # ключ записи
        self.char = char                       # буква, на странице которой находится запись
        self.field1 = field1                   # метка, к чему относится запись
        self.field2 = field2                   # Поле2
        self.field3 = field3                   # Поле3
        self.field4 = field4                   # Поле4
        self.field5 = field5                   # Поле5
        self.field6 = field6                   # Поле6
        self.commen = commen                   # комментарий
        self.delR = delR                       # служебное поле для пометки записи:
                                               # ''- видимая, 'с' - скрытая, 'у' - удаляемая
 
def onDeleteRequest():
#    print('Got wm delete') # щелчок на кнопке X в окне: можно отменить или перехватить
    saveRec()
    window.destroy()         # возбудит событие <Destroy>
 
def makeWidgets():
    # создание графической формы
    global entriesRec, entRec, lab1, alph          # перечень глобальных переменных, которые будут использоваться и за пределами функции
    entRec = {}                                    # словарь, в который будут заносится объекты ввода entFind (поиск) и entKeyRec (ключ)
    window = Tk()                                  # создание главного окна
    window.title('Книги')                       # заголовок окна
    window.geometry('1260x600+0+0')                # размеры окна
#    window.bind('FocusIn', updatePage)             # при получении окном фокуса, обновление таблицы записей
#    window.bind('<Destroy>', doRootDestroy)              # для корневого и дочерних 
    window.protocol('WM_DELETE_WINDOW', onDeleteRequest) # на кнопке X окна (перехватывает нажатие кнопки Х)
    form1 = Frame(window)                          # создание внутри окна window контейнера form1
    form1.pack()
    lab1 = Label(form1, text=activCh, fg="#eee", bg="#333", width=5)  # метка, показывающая
    lab1.pack(side=LEFT)                                              # активную букву
    Label(form1, text='  ', width=30).pack(side=LEFT)                 # вспомагательная пустая метка для улучшения расположения
    alph = ["А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", 
            "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Э", "Ю", "Я"]         # список букв
    for i in range(len(alph)):                     # создание кнопок с буквами
        Button(form1, text=alph[i], command=(lambda x=alph[i]: fetchChr(x))).pack(side=LEFT)
    ent = Entry(form1, width=27)                   # поле ввода для поиска
    ent.pack(side=LEFT)
    entRec['entFind'] = ent                        # поместить объект поля ввода в словарь entRec
    Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT)     # создание кнопки Поиск
 
    form2 = Frame(window)                          # создание внутри окна window контейнера form2
    form2.pack()
    entriesRec = {}                # словарь, для занесения в него объектов Entry ячеек таблицы ввода записей
    for (ix, label) in enumerate(fieldnamesRecTabCyr): # создание надписей заголовков столбцов таблицы
        lab = Label(form2, text=label)
        lab.grid(row=2, column=ix)
    for i in range(1, 26):         # создаются ячейки таблицы для ввода записей
        for (ix, label) in enumerate(fieldnamesRecTab):
            if label == 'keyRec' or label == 'char' or label == 'delR':  # выделяются столбцы, которые потом будут иметь особый режим доступа
                ent = Entry(form2, state='normal', width=6)
            else:
                ent = Entry(form2, width=40)
                ent.bind('<Button-1>', getKey)
            ent.grid(row=i+2, column=ix)
            entriesRec[label+str(i)] = ent   # объекты ячеек таблицы заносятся в словарь, причем к имени 
                                             # столбца ячейки добавляется номер строки, 
                                             # тем самым однозначно определяются координаты ячейки,
                                             # что бы к ней обращаться
    form3 = Frame(window)                    # создание внутри окна window контейнера form3
    form3.pack()
    Button(window, text="Следующая страница", command=fetchNext).pack()  # кнопка Следующая страница
    Label(window, text='      ', width=10).pack(side=LEFT)       # вспомогательная пустая метка
    labKeyRec = Label(window, text='№').pack(side=LEFT)     # надпись перед полем ввода номера ключа
    ent = Entry(window, width=10)                                # поле ввода номера ключа
    ent.pack(side=LEFT)
    entRec['entKeyRec'] = ent             # занесение объекта поле ввода номера ключа в словарь entRec
    Button(window, text="Скрыть", command=hideRec).pack(side=LEFT)             # кнопка Скрыть (запись)
    Button(window, text="Показать скрытые", command=fetchHide).pack(side=LEFT) # кнопка Показать скрытые
    Button(window, text="Открыть", command=openRec).pack(side=LEFT)            # кнопка Открыть (запись)
    Label(window, text=' ', width=2).pack(side=LEFT)                           # вспомогательная пустая метка
    Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT)          # кнопка удалить (запись)
    Label(window, text=' ', width=10).pack(side=LEFT)                           # вспомогательная пустая метка
    Button(window, text="Вывести запись", command=fetchRecord).pack(side=LEFT) # кнопка выводит запись в отдельной форме
    Label(window, text=' ', width=3).pack(side=LEFT)                           # вспомогательная пустая метка
    Button(window, text="Восстановить", command=updatePage).pack(side=LEFT)
    Label(window, text=' ', width=30).pack(side=LEFT)                     # вспомогательная пустая метка
    btns = Button(window, text="Сохранить", command=interSave).pack(side=LEFT)   # кнопка Сохранить (страницу)
    Label(window, text='      ', width=20).pack(side=LEFT)                     # вспомогательная пустая метка
    Button(window, text="Выход", command=fin).pack(side=LEFT)                  # кнопка Выход (из программы)
    return window                                              # функция makeWidgets возвращает окно window
 
def clear_sheet():
    # очистка листа
    for i in range(1, 26):
        for field in fieldnamesRecTab:
            if field == 'keyRec' or field == 'delR':              # для очистки полей keyRec и delR,
                entriesRec[field+str(i)].config(state='normal')   # нужно открыть их для записи
                entriesRec[field+str(i)].delete(0, END)
                entriesRec[field+str(i)].config(state='readonly')
            else:
                entriesRec[field+str(i)].delete(0, END)         # очистка остальных полей
def fetchChr(ch):
    # выбрать записи на букву ch
    global activCh, typeRec, lab1
    saveRec()                      # предварительно сохранить предыдущую страницу
    typeRec = ''                   # выбор для буквы делать только из открытых записей
    activCh = ch                   # сделать ch текущей буквой
    lab1.config(text=activCh)      # написать, для какой буквы выводятся записи
    dic_recsChr = {}                 # словарь, в который помещаются выбранные записи
    for key in p1.j1.dic_recs.keys():      # выбор записей и помещение их в словарь
        if p1.j1.dic_recs[key].char == ch:
            dic_recsChr[key] = p1.j1.dic_recs[key]
    fetch(dic_recsChr)                        # вывод записей в таблицу формы
def interSave():
    # принудительное сохранение текущей страницы и повторный вывод записей для этой буквы начиная с первой страницы
    fetchChr(activCh)
def fetchHide():
    # вывод скрытых записей
    global typeRec, lab1
    saveRec()
    lab1.config(text='скр')
    typeRec = 'с'              # выбор делать только из скрытых записей
    fetch(p1.j1.dic_recs)
def fetch(dicR):
    # вывод записей из заданнго словаря
    global dicRem                        # словарь записей, оставшихся не выведенными
    clear_sheet()                        # очистка таблицы
    count = 1                            # счетчик показывающий номер строки, в которую выводится запись
    dicRe = dicR.copy()                  # словарь, ведущий учет записей, которые еще не выведены
    while count <= 25 and len(dicRe):    # в цикле, заполнение строк таблицы записями
        for key in dicR.keys():            # в цикле вывод записи удовлетворяющей условию
            if dicR[key].delR == typeRec:
                record = dicR[key]                   # запись для вывода
                for field in fieldnamesRecTab:          # в цикле последовательное заполнение полей в строке
                    if field == 'keyRec' or field == 'delR':    # поля, которые необходимо открыть для записи
                        entriesRec[field+str(count)].config(state='normal')
                        entriesRec[field+str(count)].insert(0, getattr(record, field))
                        entriesRec[field+str(count)].config(state='readonly')
                    else:
                        entriesRec[field+str(count)].insert(0, getattr(record, field))  # все остальные поля
                count += 1         # переход к следующей строке таблицы
                dicRe.pop(key)     # удаление записи, которая выведена из словаря учета оставшихся записей           
                if count > 25:     # если все строки таблицы заполнены, то выход из цикла while
                    break
            else:
                dicRe.pop(key) # удаление из словаря учета записи, которая не удовлетворяет условию вывода в таблицу
    dicRem = dicRe.copy()      # словарь записей, оставшихся не выведенными
 
def fetchNext():
    # вывод на следующей странице записей, оставшихся не выведенными
    saveRec()
    fetch(dicRem)
 
def updatePage():
    # обновление страницы
    global activCh, typeRec, lab1
    lab1.config(text=activCh)      # написать, для какой буквы выводятся записи
    dic_recsChr = {}                 # словарь, в который помещаются выбранные записи
    for key in p1.j1.dic_recs.keys():      # выбор записей и помещение их в словарь
        if p1.j1.dic_recs[key].char == activCh:
            dic_recsChr[key] = p1.j1.dic_recs[key]
    fetch(dic_recsChr)                        # вывод записей в таблицу формы
 
def delKeyRec():
    # физическое удаление из базы данных записи, которая указана в ячейке entKeyRec
    key = entRec['entKeyRec'].get()  # из ячейки entKeyRec берется ключ записи для удаления
    if key.isnumeric() and (key in p1.j1.dic_recs.keys()): # проверка, указан ли номер существующей записи
        if askyesno('Подтверждение', 'Удалить запись без возможности востановления?'):  # подтверждение на удаление
            del p1.j1.dic_recs[key]               # запись удаляется из динамического словаря p1.j1.dic_recs
            db = shelve.open(p1.j1.nameBook)    # открывается база данных
            del db[key]                      # указанная запись физически удаляется из базы данных
            db.close()                       # база данных закрывается
            for i in range(1, 26): # ищется строка таблицы с этой записью, и помечается как удаленная, 
                if entriesRec['keyRec'+str(i)].get() == key:         # что бы потом при сохранении страницы,
                    entriesRec['delR'+str(i)].config(state='normal') # она не была вновь занесена в базу данных
                    entriesRec['delR'+str(i)].insert(0, 'у')
                    entriesRec['delR'+str(i)].config(state='readonly')
            entRec['entKeyRec'].delete(0, END)            # очищается ячейка, содержащая номер удаляемой записи
        else:
            showinfo('Отмена', 'Удаление записи отменено')   # удаление отменено
    else:
        showinfo('Отмена', 'Укажите номер существующей записи') # не указан номер записи
def hideRec():
    # пометить как скрытую
    key = entRec['entKeyRec'].get()  # из ячейки entKeyRec берется ключ записи для сокрытия
    for i in range(1, 26):           # ищется строка таблицы с этой записью, и помечается как скрытая
        if entriesRec['keyRec'+str(i)].get() == key:
            entriesRec['delR'+str(i)].config(state='normal')
            entriesRec['delR'+str(i)].insert(0, 'с')
            entriesRec['delR'+str(i)].config(state='readonly')
    entRec['entKeyRec'].delete(0, END)           # очищается ячейка, содержащая номер скрываемой записи записи
def openRec():
    # открыть скрытую запись
    key = entRec['entKeyRec'].get()   # из ячейки entKeyRec берется ключ записи для открытия
    for i in range(1, 26):            # ищется строка таблицы с этой записью, и помечается как открытая
        if entriesRec['keyRec'+str(i)].get() == key:
            entriesRec['delR'+str(i)].config(state='normal')
            entriesRec['delR'+str(i)].delete(0, END)
            entriesRec['delR'+str(i)].insert(0, '')
            entriesRec['delR'+str(i)].config(state='readonly')
    entRec['entKeyRec'].delete(0, END)           # очищается ячейка, содержащая номер открываемой записи 
 
def fetchFind():
    # поиск записей по заданной строке
    global lab1
    saveRec()
    clear_sheet()
    lab1.config(text='поиск')      # сигнализирует о режиме поиска
    strF = entRec['entFind'].get().lower() # строка для поиска берется из ячейки entFind
    dicFind = {}                   # словарь, для занесения в него найденных записей
    for key in p1.j1.dic_recs.keys():   # в тлефонном справочнике ищутся записи содержащие искомую строку
        record = p1.j1.dic_recs[key]
        for field in fieldnamesRecFull:
        #for field in fieldnamesRecTab:
            if (field != 'keyRec' and field != 'char' and field != 'delR' and # поиск в полях, за исключением перечисленных
                getattr(record, field).lower().find(strF) != -1):
                dicFind[key] = record
                break
    fetch(dicFind)                  # вывод найденных записей
def saveRec():
    # сохранение текущей страницы
    global typeRec
    for i in range(1, 26):       # просмотр строк и при наличии хотя бы в одном поле строки данных, сохранение ее
        key = entriesRec['keyRec'+str(i)].get() # проверка наличия в строке ключа
        if entriesRec['delR'+str(i)].get() == 'у': # записи помеченные как удаленные пропускаются
            continue
        elif key:                # иначе, если запись не удаленная и с ключом, то она перезаписывается
            record = p1.j1.dic_recs[key]
            for field in fieldnamesRecTab:
                setattr(record, field, entriesRec[field+str(i)].get())
            p1.j1.dic_recs[key] = record
        else: # иначе, если в строке нет ключа, но в одном из полей есть данные, то создается запись-экземпляр
            existRec = False                                               # и помещается а словарь p1.j1.dic_recs
            for field in fieldnamesRecTab:
                if entriesRec[field+str(i)].get(): existRec = True # Если существует запись в поле на этой строке
            if existRec:     # если данные в строке существуют, то создается запись
                if entriesRec['char'+str(i)].get():  # если поле буквы не пусто, то в запись заносится эта буква
                    char = entriesRec['char'+str(i)].get()
                else:              # иначе в запись заносится буква, являющаяся на данный момент активной
                    char = activCh
                field1 = entriesRec['field1'+str(i)].get()             # заполняются переменные
                field2 = entriesRec['field2'+str(i)].get()             # для формирования записи
                field3 = entriesRec['field3'+str(i)].get()
                field4 = ''
                field5 = ''
                field6 = ''
                commen = entriesRec['commen'+str(i)].get()
                if len(p1.j1.dic_recs)>0: # если телефонный справочник не пуст, то к максимальному значению ключа 
                    L = sorted(p1.j1.dic_recs.items(), key=lambda item: int(item[0]))  # прибавляется единица
                    keyRec = str(int(L[-1][0]) + 1)
                else:        # иначе записи присваивается ключ равный 1
                    keyRec = "1"
                record = Record(keyRec, char, field1, field2, field3, field4, field5, field6, commen) # создается запись, экземпляр класса Record
                p1.j1.dic_recs[keyRec] = record     #  и записывается в словарь p1.j1.dic_recs
    p1.save_DB()  # словарь p1.j1.dic_recs сохраняется во внешней базе данных "Книги"
 
def get_key(val):
    # функция для возврата ключа из словаря по значению
    for key, value in entriesRec.items():    # перебираем пары (ключ, значение)
         if val == value:                    # и находим ключ, у которого заданное значение
             return key
    print("key doesn't exist")
 
def getKey(event):
    # получить ключ записи
    currStr = get_key(event.widget)[6:]           # номер текущей строки
    currKey = entriesRec['keyRec'+currStr].get()  # ключ текущей записи
    entRec['entKeyRec'].delete(0, END)            # очистка ячейки указывающей выбранный номер записи
    entRec['entKeyRec'].insert(0, currKey)        # запись текущего номера записи в ячейку выбранного номера записи
 
def fetchRecord():
    # вывод формы с одной записью
    saveRec()                     # сохранение текущей страницы таблицы
    currentKey = entRec['entKeyRec'].get()   # из ячейки entKeyRec берется ключ записи
    if currentKey.isnumeric() and (currentKey in p1.j1.dic_recs.keys()): # проверка, указан ли номер существующей записи
        p1.j1.currentKey = currentKey       # p1.j1.dic_recs[currentKey]    # экземпляр записи для вывода в форме в модуле
        window.destroy()
        p1.open_Record()                          # открытие окна текущей записи
    else:
        showinfo('Отмена', 'Укажите номер существующей записи') # не указан номер записи
 
def fin():            # сохранение перед закрытием окна (в том числе крестом)
    saveRec()         # сохранение текущей страницы
    window.destroy()  # закрытие окна


Добавлено через 1 минуту
record.py - модуль с GUI выводит форму для одной записи, имеющую дополнительными поля в записи. Название фиксированное.
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# файл record.py - модуль, импортируемый сценарием journalEntriesTemplate1.py (или journalEntriesTemplate1.pyw)
 
from tkinter import *                              # импорт объектов для графического интерфейса
from tkinter import Toplevel                       # класс дополнительных окон
from tkinter.messagebox import showerror           # всплывающее окно диалога сообщающее об ошибке
import shelve                                      # импорт модуля для работы с базой данных 
 
p1 = None                   # экземпляр класса Progr (передается из journalEntriesTemplate1)
winRec = None
 
fieldnamesRec = None #p1.fieldnamesRec       # имена полей у записи (передается из journalEntriesTemplate1)
fieldnamesRecCyr = None #p1.fieldnamesRecCyr    # словарь для перевода полей в кирилицу (передается из journalEntriesTemplate1)
record = None              # экземпляр записи для вывода в форме (передается через функцию)
 
entriesRec = {}          # словарь, для занесения в него объектов Entry ячеек формы ввода записи
 
def onDeleteRequest():
#    print('Got wm delete') # щелчок на кнопке X в окне: можно отменить или перехватить
    saveRec()        # сохранение текущей записи
    winRec.destroy()  # закрытие окна текущей записи (возбудит событие <Destroy>)
    p1.open_Journal()    # открытие окна журнала
 
def makeWidgets():       # создание графической формы для вывода одной записи
    global entriesRec
    winRec = Tk()                 # создание дополнительного окна для второй формы
    winRec.title('Книга')               # заголовок окна
    winRec.geometry('500x250+350+150')  # размеры окна
    winRec.protocol('WM_DELETE_WINDOW', onDeleteRequest) # на кнопке X окна (перехватывает нажатие кнопки Х)
    form = Frame(winRec)             # создание фрейма
    form.pack(side=TOP, expand=YES, fill=BOTH)   # упаковка фрейма
    entriesRec = {}                              # словарь содержащий объекты Entry
    for (ix, label) in enumerate(fieldnamesRec): # формирование названия полей и полей ввода Entry
        lab = Label(form, text= fieldnamesRecCyr[label]) # название поля (в кирилице)
        ent = Entry(form, width=200)             # поле ввода
        lab.grid(row=ix, column=0)                  # размещение по сетке
        ent.grid(row=ix, column=1)
        entriesRec[label] = ent                  # запись в словарь
    Button(winRec, text="Сохранить", command=saveRec).pack(side=LEFT)  # кнопка Сохранить
    Button(winRec, text="Выход", command=fin).pack(side=RIGHT)  # закрывает одно окно
    return winRec          # возвращает второе окно со сформированной второй формой
 
#def recBook(recordsBook):
    # функция для передачи в модуль экземпляра t1 книги класса RecordsBook
    global t1
    t1 = recordsBook       # содержит экземпляр t1 класса RecordsBook
#def curRec(curRecord):
    # функция для передачи в модуль экземпляра текущей записи класса Record
    global record
    _record = curRecord   # экземпляр записи переданный в модуль
 
def fetchRecord(record):
    # вывод в форме указанной записи
    for field in fieldnamesRec:
        entriesRec[field].insert(0, getattr(record, field)) # для каждого поля заполняется виджет Entry
def saveRec():
    # сохранение записи (занесение в экземпляр записи содержимого формы и сохранение экземпляра) 
    global record            # экземпляр записи выведенный в форме
    key = record.keyRec      # ключ записи
    for field in fieldnamesRec:   # занесение в экземпляр записи содержимого формы
        setattr(record, field, entriesRec[field].get())
        #print(record)                    # печать атрибутов для отладки
    p1.j1.dic_recs[key] = record   # сохранение экземпляра записи в словаре книги
    p1.save_DB()  # словарь t1.dicRec сохраняется во внешней базе данных "Книги"
 
def fin():            # сохранение перед закрытием окна 
    saveRec()        # сохранение текущей записи
    winRec.destroy()  # закрытие окна текущей записи (возбудит событие <Destroy>)
    p1.open_Journal()    # открытие окна журнала
1
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
25.07.2021, 17:55
AlexMarkov, Поправка. В этом пректе класс в основном сценарии называется Progr, а не Prog_Tools, как я стал называть аналогичные классы позже.

Добавлено через 19 минут
AlexMarkov, Кстати этот проект с GUI наиболее тщательно за комментирован. Но там есть тонкие моменты, приходилось придумывать свои решения. К ним относятся и создание графической таблицы и работы с ней (создание системы координат каждой ячейки, а так же создание возможности листать страницы, правда только вниз, когда записей больше 24-х размещаемых на одной странице). И другие решения с графикой, связанные с работой с окнами и с сохранением записей в базе данных на основе модуля shelve.
Поэтому, что будет не понятно, спрашивайте.

Добавлено через 10 минут
Если бы это был коммерческий проект, я бы был вынужден написать инструкцию к работе с программой. А так я не стал заморачиватся. Что будет не понятно в работе программы, объясню.
Я реально использую эту программу в качестве электронного телефонного справочника. И другой вариант, использую для электронного каталога всех моих документов.
Работа программы вполне меня устраивает.
Правда я так и не собрался реализовать автоматическое сохранение архивов базы данных. Но меня устраивает и простое копирование каталога с файлами программы вручную в архивную папку.

Добавлено через 4 часа 57 минут
AlexMarkov, Предупреждение. Если Вы все-таки будете разбираться с кодом проекта, содержащим графику (в чем я не уверен, так как код достаточно объемный), то имейте ввиду, что писал я его давно и там использовал прием, который сейчас не стал бы применять. Это скрытые глобальные переменные. Когда переменные инициализируются внутри одной функции и объявляются в ней глобальными, и потом идет работа с ними из другой функции. При этом в начале модуля, где должны определятся глобальные переменные, их нет. Такой код труден для понимания. Сейчас я бы сделал по другому. Создал бы класс Data и в нем соответствующие атрибуты экземпляра класса. И заменил бы глобальные переменные этими атрибутами. Так код проще и для проектирования и для последующего чтения. И снимаются все проблемы с глобальными переменными. Но так как код нормально работает, то мне не хочется туда лезть и его менять.
Но если что будет не понятно, обращайтесь, я объясню.
Кстати в этом примере я разобравшись у Лутца использовал прием автоматического сохранения записей из текущего листа в окне журнала, когда окно закрывается крестом в верхнем правом углу графического окна.
Вообще, при уходе с текущего листа всегда происходит автоматическое сохранение информации с этого листа.
Я так сделал, из-за того, что память у меня иногда уже подводит, поэтому боюсь потерять занесенную информацию.

Добавлено через 19 минут
Цитата Сообщение от AlexMarkov Посмотреть сообщение
Если будут вопросы, где лучше их задавать, здесь, в блоге или в отдельной теме?
Если будут вопросы по Вашему проекту, то Вам нужно будет создать свою тему. Но только тогда пошлите мне сообщение со ссылкой на созданную вами тему.
А вопросы по моим проектам, которые я здесь выложил, задавайте здесь.
1
99 / 86 / 20
Регистрация: 10.09.2019
Сообщений: 708
25.07.2021, 19:31
Цитата Сообщение от Viktorrus Посмотреть сообщение
скрытые глобальные переменные
Не использую глобальные переменные с самого начала и не собираюсь.
Цитата Сообщение от Viktorrus Посмотреть сообщение
использовал прием автоматического сохранения записей из текущего листа в окне журнала, когда окно закрывается крестом в верхнем правом углу графического окна
С сохранением файла настроек и автосохранением разберусь при необходимости.
Цитата Сообщение от Viktorrus Посмотреть сообщение
боюсь потерять занесенную информацию
Думаю о распространенной реляционной базе данных поддерживающей язык запросов sql, а там они NoSql уже используют, или говорят что используют. В итоге все равно вся инфа нужна будет на вебе, скорее всего, в десктопной версии никто и не захочет или некому уже будет разбираться. Файлы формата sql практически везде сейчас поддерживаются, так что остановлюсь на них, а там посмотрим. В любом случае, для себя на qt буду подключать sqlite для собственной базы и работы с ней, там и воспользуюсь вашим кодом. Практический опыт с ненадежностью серверов как способа сохранения информации в долговременной перспективе не внушает доверия. Деньги в проект (сервис) не идут, сразу удаляют все подчистую или обновляются так, что вся прежняя инфа в утиль. В общем надоело до такой степени, что записываю все на собственные носители, и в архив.
0
1732 / 970 / 199
Регистрация: 22.02.2018
Сообщений: 2,693
Записей в блоге: 6
25.07.2021, 19:44
Цитата Сообщение от AlexMarkov Посмотреть сообщение
Файлы формата sql практически везде сейчас поддерживаются
База данных с sql, это на сегодня для веба по моему наиболее популярный формат хранения данных, который все сервера поддерживают.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
25.07.2021, 19:44
Помогаю со студенческими работами здесь

Области видимости переменных + функции
Всем добрый вечер. Небольшая теория (предисловие). Как нам известно в Java Script есть две области видимости это локальная и глобальная....

Области видимости переменных точечного запроса
Как определить в каком месте какую переменную запроса можно использовать? Наример, запрос var se =...

Области видимости переменных, типов, констант
Области видимости переменных, типов, констант. Как можно развёрнуто ответить?

Области видимости переменных\или проблема вывода из БД
Доброго времени суток, господа, я не такой уж сильный знаток PHP по этому возникла проблема: есть некая форма для поиска с несколькими...

Области видимости и передача массива из метода
Всем привет, прошу вашей помощи, т.к. не могу уловить один ключевой момент: есть два класса Program (с методом Main) и Work (в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru