Проблема с импортированием переменной в коде Python
Проблема в следующем: есть 3 файла, основной main.py, user_cabinet.py и config.py. Переменная берется из config, меняется в main, но изменения не видны в user_cabinet. Речь идет о переменной user_login_value.
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 шт):
Это так не работает. Если вы импортируете переменную из какого-то файла и потом меняете, то меняете вы её только там, где поменяли. При новом импорте импортируется то, что в импортируемом файле, там эта переменная никак не меняется.
У вас там сложность ещё в том, что вы заранее создаёте контролы с зашитым туда значением. Нужно либо позже создавать контролы, уже после авторизации. Либо как-то на ходу им свойства менять. :/
Это тоже скорее всего не сработает.
Уберите из кабинета строку:
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 файла и сохранять в этот же файл. А когда вам нужно будет получить или сохранить это значение - нужно будет вызывать эти функции. Вот так это должно работать.
Строкой 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}',
...