Проблема с импортированием переменной в коде Python

Проблема в следующем: есть 3 файла, основной main.py, user_cabinet.py и config.py. Переменная берется из config, меняется в main, но изменения не видны в user_cabinet. Речь идет о переменной user_login_value.

Проект на GitHub

main.py

import flet as ft
import connection as con
import book_settings as bs
import user_cabinet as uc
from config import user_login_value
con.connection_reg() #подключение к базе данных

user_login_value = 'имя'
def main(page: ft.Page):
    """Основная настройка страницы"""
    global user_login_value

    page.title = 'Папирус'
    page.theme_mode = 'dark'
    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.window.width = 600
    page.window.height = 900
    page.window.resizable = False   

    logged_in = False #переменная-заглушка, меняется при авторизации пользователя и позволяет посмотреть личный кабинет
    
    def register(e):
        """Функция для регистрации нового пользователя"""

        global user_login_value
        with con.connection_to_data_base_reg.cursor() as cursor:
            query = f"""
            INSERT INTO `reg`(user_name, user_pass) VALUES('{user_login.value}', '{user_password.value}')"""
            try:
                cursor.execute(query)
                con.connection_to_data_base_reg.commit()
                page.open(ft.SnackBar(ft.Text(f'Приятно познакомиться,{user_login.value}')))
                user_password.value = ''
                user_login_value = user_login.value
                print(user_login_value)

            except Exception as ex:
                page.open(ft.SnackBar(ft.Text('Имя занято')))
                print('Ошибка', ex)
            page.update()
            
    def auth(e):
        """Функция для авторизации пользователя"""
        global user_login_value
        with con.connection_to_data_base_reg.cursor() as cursor:
            query = """
            SELECT * FROM reg WHERE user_name = %s AND user_pass = %s
            """
            try:
                cursor.execute(query, (user_login.value, user_password.value))
                result = cursor.fetchone() 
                if result: 
                    user_password.value = ''
                    user_login_value = user_login.value
                    print(user_login_value)
                    nonlocal logged_in
                    logged_in = True
                    
                    navigate(None)
                    page.navigation_bar.destinations.pop(0)
                    page.navigation_bar.destinations.pop(0)
                    
                    global second_nav
                    second_nav = ft.NavigationBar(
                        destinations= [
                            ft.NavigationBarDestination(icon=ft.icons.BOOK, label= 'Кабинет'),
                            ft.NavigationBarDestination(icon=ft.icons.SEARCH, label="На поиски"),
                            ft.NavigationBarDestination(icon=ft.icons.MY_LIBRARY_BOOKS, label="Моя подборка")
                        ],
                        on_change=navigate_for_cabinet)
                    page.add(second_nav)                           
                else: 
                    page.open(ft.SnackBar(ft.Text('Неверные данные')))
                page.update()
            except Exception as ex:
                print('Ошибка', ex)
                auth_btn.text = 'Не получилось'

    def valid(e):
        """Функция для проверки заполненности полей"""
        if all([user_login.value, user_password.value]):
            registr_btn.disabled = False
            auth_btn.disabled = False
        else:
            registr_btn.disabled = True
            auth_btn.disabled = True
        page.update()

    def change_pass(e):
        """Функция для смены иконки замка и отображения пароля"""
        if pass_lock.icon == ft.icons.LOCK:
            pass_lock.icon = ft.icons.LOCK_OPEN  
            user_password.password = False  
        else:
            pass_lock.icon = ft.icons.LOCK  
            user_password.password = True  
        page.update()       
    
    user_login = ft.TextField(label='Ваше имя', width= 200, on_change= valid)
    pass_lock = ft.IconButton(icon=ft.icons.LOCK, on_click= change_pass)
    user_password = ft.TextField(label='Ваш пароль', width= 200, on_change= valid, password=True, suffix_icon=pass_lock)
    registr_btn = ft.OutlinedButton(text='Начать', width=200, on_click= register, disabled=True)
    auth_btn = ft.OutlinedButton(text='Начать', width=200, on_click= auth, disabled=True)    
    registration = ft.Row(
            [
                ft.Column(
                    [
                        ft.Text('Регистрация'),
                        user_login,
                        user_password,
                        registr_btn
                    ]
                )
            ],
            alignment=ft.MainAxisAlignment.CENTER

        )
    autorisation = ft.Row(
            [
                ft.Column(
                    [
                        ft.Text('Авторизация'),
                        user_login,
                        user_password,
                        auth_btn
            
                    ]
                )
            ],
            alignment=ft.MainAxisAlignment.CENTER,
        )

    
    def open_all_books(e):
        page.controls.clear()
        show_books_container = ft.Container(
        content=ft.Column( 
            controls=show_books,  
            alignment=ft.MainAxisAlignment.CENTER,  
            scroll=ft.ScrollMode.ALWAYS, 
            width=400,
            height=700, 
        ),alignment=ft.Alignment(0, 0))
        page.add(navigate_for_my_books) 
        page.add(show_books_container) 
        page.add(second_nav)  
        page.update() 

    def open_all_foreign_books(e):
        page.controls.clear()
        show_books_container = ft.Container(
        content=ft.Column( 
            controls=show_books,  
            alignment=ft.MainAxisAlignment.CENTER,  
            scroll=ft.ScrollMode.ALWAYS, 
            width=400,
            height=700, 
        ),alignment=ft.Alignment(0, 0))
        page.add(navigate_for_my_books) 
        page.add(show_books_container) 
        page.add(second_nav)  
        page.update() 

    def open_all_art_books(e):
        page.controls.clear()
        show_books_container = ft.Container(
        content=ft.Column( 
            controls=show_books[:2],  
            alignment=ft.MainAxisAlignment.CENTER,  
            scroll=ft.ScrollMode.ALWAYS, 
            width=400,
            height=700, 
        ),alignment=ft.Alignment(0, 0))
        page.add(navigate_for_my_books) 
        page.add(show_books_container) 
        page.add(second_nav)  
        page.update() 

    def open_all_adventure_books(e):
        page.controls.clear()
        show_books_container = ft.Container(
        content=show_books[1],
        alignment=ft.Alignment(0, 0), 
        padding=10)
        page.add(navigate_for_my_books)
        page.add(show_books_container) 
        page.add(second_nav)
        page.update()
       
    def open_all_tragedy_books(e):
        page.controls.clear()
        show_books_container = ft.Container(
        content=show_books[0],
        alignment=ft.Alignment(0, 0), 
        padding=10)
        page.add(navigate_for_my_books)
        page.add(show_books_container) 
        page.add(second_nav)
        page.update()
     
   
    navigate_for_my_books = ft.Container(
        content=ft.Row(
            controls=[
                ft.IconButton(ft.icons.COLLECTIONS_BOOKMARK, icon_color='#e85a4f', on_click=open_all_books),
                ft.IconButton(ft.icons.EXPLORE, icon_color='white', on_click=open_all_foreign_books),
                ft.IconButton(ft.icons.PALETTE, icon_color='#e85a4f', on_click=open_all_art_books),
                ft.IconButton(ft.icons.MAP, icon_color='#e9eeca', on_click=open_all_adventure_books),
                ft.IconButton(ft.icons.SENTIMENT_DISSATISFIED_SHARP, icon_color='white', on_click=open_all_tragedy_books)
            ],
            alignment=ft.MainAxisAlignment.CENTER,
            spacing=70,
        ),
        height=80, 
        padding = ft.Padding(0,0,0,0)
    )
    
    cabinet = ft.Row(
            [   
                uc.main_user_profile()
            ]   
        )
    search = ft.Row(
            [
                ft.Column(
                    [
                        ft.Text('Здесь вы найдете книги своей мечты')
                    ]
                )
            ],
            alignment=ft.MainAxisAlignment.CENTER,
        )
    
    show_books = [
        bs.stack_1,
        bs.stack_2,
        bs.stack_3
    ]
    
    my_books = ft.Column(
        controls=[
            ft.Container(navigate_for_my_books),
            ft.Container(
                ft.Column(
                    controls=show_books,
                    alignment=ft.MainAxisAlignment.CENTER,
                    scroll=ft.ScrollMode.ALWAYS,
                    width=400,
                    height=700,     
                ),
                alignment=ft.Alignment(0,0),
            )
        ],
        alignment=ft.MainAxisAlignment.CENTER,  
    )
    def navigate(e):
        """Выбор между регистрацией и авторизацией. Развертывание личного кабинета для авторизованных пользователей"""
        page.clean()
        if logged_in:
            page.add(cabinet)
        else:
            index = page.navigation_bar.selected_index
            if index == 0:
                page.add(registration)
            elif index == 1:
                page.add(autorisation)
        page.update()

    def navigate_for_cabinet(e):
        """Навигация внутри личного кабинета"""
        index = second_nav.selected_index
        page.clean()
        if index == 0:
            page.add(cabinet)
            page.add(second_nav)
        elif index == 1:
            page.add(search)
            page.add(second_nav)
        elif index == 2:
            page.add(my_books)
            page.add(second_nav)
        page.update()

    page.navigation_bar = ft.NavigationBar(
        destinations=[
            ft.NavigationBarDestination(icon=ft.icons.BOOKMARK_ADD, label="Регистрация"),
            ft.NavigationBarDestination(icon=ft.icons.BOOKMARK, label="Авторизация"),
        ],
        on_change=navigate
    )
   
    page.add(registration)

ft.app(target=main)
con.connection_reg.close()

user_cabinet.py

import flet as ft
import os

import book_settings as bs
from book_settings import BookSample

import connection as con
from connection import *

from config import user_login_value

class LatestUserBooks:
    def __init__(self, book_sample):
        self.title = book_sample.title
        self.author = book_sample.author
        self.year = book_sample.year
        self.country = book_sample.country
        self.image_url_2 = book_sample.image_url_2

    def show_latest_books(self):
        return ft.Stack(
            controls=[
                ft.Image(
                    src=self.image_url_2,
                    width=400,
                    height=300,
                    fit=ft.ImageFit.COVER,
                    border_radius=25,
                ),
                ft.Container(
                    content=ft.Text(
                        self.title,
                        color="#e9eeca",
                        size=22,
                        weight="bold",
                        text_align=ft.TextAlign.CENTER,
                    ),
                    alignment=ft.Alignment(0, 0),
                    padding=ft.Padding(15, -30, 15, 0),
                ),
                ft.Container(
                    content=ft.Text(
                        self.author,
                        color="#e9eeca",
                        size=17,
                        weight="light",
                        text_align=ft.TextAlign.CENTER,
                    ),
                    alignment=ft.Alignment(0, 0.2),
                    padding=ft.Padding(15, -10, 15, 0),
                ),
                ft.Container(
                    content=ft.Text(
                        f'{self.year}, {self.country}',
                        color="#e9eeca",
                        size=13,
                        weight="bold",
                        text_align=ft.TextAlign.CENTER,
                    ),
                    alignment=ft.Alignment(0.1, 0.2 ),
                    padding=ft.Padding(0, 70, 20, 0),
                ),
            ],
            width=300,  
            height=200,
            
        )
first_book = LatestUserBooks(bs.book_1)
show_first_book = [first_book.show_latest_books()]

second_book = LatestUserBooks(bs.book_2)
show_second_book = [second_book.show_latest_books()]

third_book = LatestUserBooks(bs.book_3)
show_third_book = [third_book.show_latest_books()]

all_books = show_first_book + show_second_book + show_third_book


def main_user_profile():    
            user_photo = 'user_photo.jpg'
            url_for_user_photo = os.path.join('..','img',user_photo)
            first_achievement  =  ft.Icon(name=ft.icons.CHROME_READER_MODE,color='white', tooltip='За добавление 5 книг')
            second_achievement =  ft.Icon(name=ft.icons.ACCESS_ALARM_OUTLINED,color='white', tooltip='За проведение 24 часов в приложении')
            third_achievement  =  ft.Icon(name=ft.icons.FORMAT_LIST_BULLETED_ROUNDED,color='white', tooltip='За добавление книг из 3 разных жанров')

            """Оформление кабинета пользователя"""
            return ft.Stack(
                controls=[
                    ft.Container(
                        ft.Text(f'Ваше имя: {user_login_value}',
                        color="white",
                        size=25,
                        weight="bold"),
                        alignment=ft.Alignment(0, 0),
                        margin=ft.Margin(340, -80, 15, 0)
                    ),
                    
                    ft.Container(
                        ft.Text('Дата регистрации в Папирус: ',
                        color="white",
                        size=15,
                        weight="light"),
                        alignment=ft.Alignment(0, 0),
                        margin=ft.Margin(340, -10, 15, 0)
                    ),
                    ft.Container(
                        ft.Image(
                        src=url_for_user_photo,
                        border_radius=25,
                        width= 250,
                        height=250,
                        fit=ft.ImageFit.COVER,
                    ),
                        alignment=ft.Alignment(0, 0),
                        margin=ft.Margin(50, -70, 15, 0)
                    ),
                    ft.Container(
                        content = ft.Row(controls=[first_achievement,second_achievement,third_achievement]),
                        alignment=ft.Alignment(0, 0),
                        margin=ft.Margin(125, 200, 15, 0)
                    ),
                    ft.Container(
                        ft.Text('Последние добавленные книги:',
                        color="white",
                        size=15,
                        weight="bold",),
                        
                        alignment=ft.Alignment(0, 0),
                        margin=ft.Margin(50, 300, 15, 0)
                    ),

                    ft.Container(
                        ft.Text('Книг в моей коллекции: 3',
                        color="white",
                        size=15,
                        weight="bold",),
                        
                        alignment=ft.Alignment(0, 0),
                        margin=ft.Margin(350, 300, 15, 0)
                    ),
                    
                    ft.Container(
                        content=ft.Row(controls= all_books, scroll=ft.ScrollMode.ALWAYS),
                        margin=ft.Margin(50, 350, 15, 0),
                        height=200,
                        width = 510,
                        padding=ft.Padding(10,0,0,0)
                    )
                ]
            )

config.py

user_login_value = None

Ответы (2 шт):

Автор решения: CrazyElf

Это так не работает. Если вы импортируете переменную из какого-то файла и потом меняете, то меняете вы её только там, где поменяли. При новом импорте импортируется то, что в импортируемом файле, там эта переменная никак не меняется.

У вас там сложность ещё в том, что вы заранее создаёте контролы с зашитым туда значением. Нужно либо позже создавать контролы, уже после авторизации. Либо как-то на ходу им свойства менять. :/

Это тоже скорее всего не сработает.

Уберите из кабинета строку:

from config import user_login_value

И добавьте в:

def main_user_profile():
    global user_login_value # <- берём ту же глобальную переменную

Ниже нерабочий вариант.

(Не работает, потому что uc.main_user_profile(user_login_value) отрабатывает сразу, ещё до изменения переменной и её показа.)

Поскольку вы кабинет этот прямо вызываете из main как функцию: uc.main_user_profile(), то вам проще передать эту переменную прямо при этом вызове:

uc.main_user_profile(user_login_value)

А в кабинете принять её:

def main_user_profile(user_login_value): 

Если же речь о том, чтобы куда-то сохранять эту переменную между вызовами программы, то в config вам нужно сделать функции, которые будут загружать данные, например, из json файла и сохранять в этот же файл. А когда вам нужно будет получить или сохранить это значение - нужно будет вызывать эти функции. Вот так это должно работать.

→ Ссылка
Автор решения: Vitalizzare ушел в монастырь

Строкой from config import user_login_value вы импортируете не переменную, а имя, указывающее на некий объект, созданный в модуле config. Когда вы пишите user_login_value = 'Someone', то тем самым переназначаете это имя другому объекту (строке 'Someone'). При этом вы теряете связь с объектом из модуля config. Поэтому в других модулях, которые по прежнему смотрят на объект из config, вносимые вами изменения не видны.

Проблема решается созданием объекта, у которого есть изменяемое состояние. И тогда вместо переназначения имени другому объекту, вы изменяете состояние исходного. Если мы говорим об изменяемых настройках всего фреймворка, то как правило создается словарь, а настройка производится изменением значений по тому или иному ключу (пример из жизни - словарь matplotlib.rcParams). Изменения в словаре, сделанные в одном модуле, будут видны из другого.

Пример реализации:

# config.py

settings = {
    'user_login_value': None
}


# user_cabinet.py

from config import settings

def get_current_login():
   return settings['user_login_value']


# main.py

from config import settings
from user_cabinet import get_current_login

print('user_login_value в программе main до изменений:', settings['user_login_value'])
print('user_login_value в модуле user_cabinet до изменений:', get_current_login())

settings['user_login_value'] = 'New User'
print('user_login_value в программе main после изменений:', settings['user_login_value'])
print('user_login_value в модуле user_cabinet после изменений:', get_current_login())

Результат работы:

$ python main.py
user_login_value в программе main до изменений: None
user_login_value в модуле user_cabinet до изменений: None
user_login_value в программе main после изменений: New User
user_login_value в модуле user_cabinet после изменений: New User

Если речь о настройках отдельной сессии, которых может быть много, то тогда мы либо создаем словарь настроек и передаем его той или иной функции как контекст, либо создаем объект с настраиваемым состоянием и работаем с его методами, которые учитывают заданное состояние.

Совсем простой вариант - работать не с отдельным именем, импортированным из модуля config, а непосредственно с модулем. При импортировании модуль загружается один раз. Последующее импортирование этого же модуля в другом месте берет его из кеша. Поэтому строка import config всегда будет создавать имя config, указывающее на один и тот же объект (см. ответ на тему импортирования):

main.py

import config

config.user_login_value = 'имя'

def main(page: ft.Page):
    # global user_login_value <- это не нужно
    ...
    def register(e):
        # global user_login_value <- это не нужно
        ...
                config.user_login_value = user_login.value
                print(config.user_login_value)
        ...
    def auth(e):
        # global user_login_value <- это не нужно
        ...
                    config.user_login_value = user_login.value
                    print(config.user_login_value)
...

user_cabinet.py

import config
...
                        ft.Text(f'Ваше имя: {config.user_login_value}',
...
→ Ссылка