在更新字典时在 python 中使用跨类的函数时,在类方法、cls 和 self 上苦苦挣扎

Struggling with class methods, cls, and self when using functions cross classes in python while updating a dictionary

提问人:Shenanigator 提问时间:8/26/2023 最后编辑:Shenanigator 更新时间:8/29/2023 访问量:58

问:

我正在尝试构建一个小 UI,用于更新一些设置,然后在 raspberrypi 上显示一些摄入数据。Python 版本为 3.9.2。我认为保存设置的最合乎逻辑的方法是构建 JSON,然后将其保存到文件中。

我正在努力让json_data词典更新和保留设置。我摆脱了一些尝试,使用 cls 而不是 self。我试过了,但根据我认为我对那个装饰器的理解,这似乎不对。我尝试在函数中使用args,**args,**kwargs。__init__@classmethod@staticmethod

Settings.update_settings() 在不同时间从多个类调用以更新设置。我已经能够更新json_data,但问题是在每次调用update_settings使用类方法时重置json_data。当使用 self 时,我认为这是意料之中的,在 Settings 类之外调用时缺少 self 参数。

我需要在输入时保存 json 片段的原因是我在设置组之间移动时会破坏小部件。

这是主屏幕 (MainApp),他们在 Settings 类中输入 JSON 的第一次更新。

from guizero import App, Box, info, Picture, PushButton, Text, TextBox, Window, yesno
from datetime import datetime as dt
import subprocess
import sys
from data_output_setup_page import LoggerSetupPage
from logging_data_display import DataDisplayPage
import logging as log
from utilities import Settings


class MainApp:


    def __init__(self):

        self.submit_site_text = 'Submit'
        self.app = App('Epic One Water Pulse Logging',
                       width=800, height=480, bg='#050f2b')
        # Maximize the app window
        #self.app.tk.attributes('-fullscreen', True)

        # Top Box for header
        self.top_box = Box(self.app, layout="grid")
        self.brand = Picture(self.top_box, image=r'/home/ect-one-user'
                                                 r'/Desktop/One_Water_Pulse_Logger'
                                                 r'/assets/Brand.png',
                             align='left', grid=[0, 0])
        self.header = Text(self.top_box, text=dt.now().strftime('%Y-%m-%d %H:%M:%S'),
                           align='right', grid=[1, 0], width='fill')
        self.header.text_color = 'white'
        self.header.width = 90
        
        self.welcome_box = Box(self.app, layout='grid', align='top')
        self.welcome_text = Text(self.welcome_box, text="Welcome to the ECT Pulse Logger Prototype.",
                                 size=14, grid=[0, 0])
        self.welcome_text.text_color = 'white'
        self.welcome_text.width = 90

        self.welcome_text_l2 = Text(self.welcome_box, text="Please send any feedback to [email protected]",
                                    size=14, grid=[0, 1])
        self.welcome_text_l2.text_color = 'white'
        self.welcome_text_l2.width = 90

        # Middle of Screen box
        self.box = Box(self.app, layout='grid', align='top')
        self.spacer = Text(self.box, text='', grid=[0, 1], width='fill')

        self.site_name_label = Text(self.box, text='Site Name:', grid=[0, 2])
        self.site_name_label.text_color = 'white'

        self.l_spacer = Text(self.box, text='', grid=[1, 2])  

        self.site_name = TextBox(self.box, grid=[2, 2])
        self.site_name.width = 20
        self.site_name.bg = 'white'

        self.r_spacer = Text(self.box, text='', grid=[3, 2])
        
        self.submit_site =  PushButton(self.box, text=self.submit_site_text,
        command=self.site_lock, grid = [4, 2])
        self.submit_site.text_color = 'white'
        
        self.spacer = Text(self.box, text='', grid=[0, 3], width='fill')
        
        self.sv_stg_to_file = PushButton(self.box, text='Save Settings File',
        command=Settings.save_to_json, grid=[0, 4, 3, 1])
        self.sv_stg_to_file.text_color = 'white'
        

        # Create a button holder at bottom of screen
        self.bottom_box = Box(self.app, layout='grid', align='bottom')
        self.open_ds_button = PushButton(self.bottom_box, text='Logger Setup',
                                         command=lambda: self.open_window(
                                             LoggerSetupPage, 'Logger Setup'),
                                         align='left', grid=[0, 0])
        self.open_ds_button.text_color = 'white'
        self.open_ds_button.hide()
            

        self.open_db_button = PushButton(self.bottom_box, text='Open Logging',
                                         command=lambda: self.open_window(
                                             DataDisplayPage, 'Logging'),
                                         align='left', grid=[1, 0])
        self.open_db_button.text_color = 'white'
        self.open_db_button.hide()

        self.close_button = PushButton(self.bottom_box, text='Shutdown Logger',
                                       command=self.exit_pgm,
                                       align='left', grid=[2, 0])
        self.close_button.text_color = 'white'

    def run(self):

        self.app.display()
        
    def get_settings(self):

        self.settings = Settings.retrieve_settings()
        print(self.settings)
        if not isinstance(self.settings, type(None)):
            load_settings = yesno('Load Settings', 'Settings file found. Load settings?')
            if load_settings:
                self.site_name.value = self.settings['Site Name']
                self.logger_setup.import_settings(self.settings)
        elif isinstance(self.settings, type(None)):
            info('Config', 'No settings file found. Please configure settings.')

    def check_json(self):

        self.local_settings = Settings.check_json()
        print(self.local_settings)
        if self.local_settings:
            info('Config', 'Settings ready for save.')
            self.sv_stg_to_file.show()
        else:
            self.sv_stg_to_file.hide()

    def site_lock(self):

        if self.submit_site_text == 'Submit':
            self.site_name.disable()
            self.submit_site_text = 'Alter Site Name'
            Settings.update_settings({
                'Settings':
                    {'Site Name': self.site_name.value}
                })
            self.get_settings()
            self.open_ds_button.show()
            self.open_db_button.show()

            # Add a log statement
            log.info('Site name updated to {0}'.format(self.site_name.value))

        else:
            self.site_name.enable()
            self.submit_site_text = 'Submit'
            self.open_ds_button.hide()
            self.open_db_button.hide()

            # Add a log statement
            log.info('Site name updated to {0}'.format(self.site_name.value))

        self.submit_site.text = self.submit_site_text

    def open_window(self, module, wdw_name):

        self.app.hide()
        new_window = Window(
            self.app, title=wdw_name, width=800, height=480, bg='#050f2b')
        #new_window.tk.attributes('-fullscreen', True)
        
        # Create an instance of DataDisplayPage
        open_page = module(new_window, self)
        new_window.show()

    def exit_pgm(self):

        self.app.destroy()
        # subprocess.Popen(['shutdown','-h','now'])
        sys.exit()


if __name__ == "__main__":
    app = MainApp()
    app.check_json()
    app.run()

这是我的设置类

from botocore.client import Config
import boto3
import collections.abc
import ftplib
import json
import logging

from base64 import b64decode as bd
from datetime import datetime as dt


class Settings:

settings_directory = '/home/ect-one-user/Desktop/One_Water_Pulse_Logger/config/'
settings_filename = '_logger_config.json'
json_data = {
        'Settings': {
            'Site Name': None,
            'Sensor': {

                },
            'Data Output': {
                
                },
            'Email Address': {

                }
            }
        }

@staticmethod
def update_settings(d):
    
   Settings.json_data.update(d)

@staticmethod
def check_json():
    print(Settings.json_data)
    try:
        if Settings.json_data['Settings']['Site Name'] is not None \
            and Settings.json_data['Settings']['Sensor']['Name'] is not None \
            and Settings.json_data['Settings']['Data Output']['Location'] is not None:
            return True
    except:
        return False

LoggerSetupPage 类

from base64 import b64encode as be
from base64 import b64decode as bd
from datetime import datetime as dt
from guizero import Box, Combo, info, Picture, ListBox, PushButton, Text, TextBox, Window
from utilities import Settings

class LoggerSetupPage:

    def __init__(self, parent, main_app):

        self.parent = parent
        self.main_app = main_app
        self.current_row = 0       
        self.settings_dict = {}
        self.widgets_to_destroy = []
        
        # Top Box for header
        self.top_box = Box(self.parent, layout='grid')

        # Display the brand logo in the top left corner of the main window.
        self.brand = Picture(self.top_box,
                             image='/home/ect-one-user/Desktop/One_Water_Pulse_Logger/assets/Brand.png'
                             , align='left', grid=[0, 0])

        self.header = Text(self.top_box,
                           text=dt.now().strftime('%Y-%m-%d %H:%M:%S'),
                           align='right', grid=[1, 0])
        self.header.width = 90
        self.header.text_color = 'white'


        # Middle box
        self.mid_box = Box(self.parent, layout='grid')

        self.config_selection = Combo(
            self.mid_box,
            options=[ 'Data Output Config', 'Sensor Config'],
            command=self.check_selection,
            grid=[0, 0]
        )
        self.config_selection.text_color = 'white'
        self.config_selection.text_size = 16

        # Bottom box for buttons
        self.bottom_box = Box(self.parent, layout='grid', align='bottom')

        self.return_button = PushButton(self.bottom_box,
                text='Return to Main Page',
                command=self.return_to_main, align='bottom', grid=[0, 2])
        self.return_button.text_color = 'white'

    def return_to_main(self):

        self.main_app.app.show()
        self.main_app.check_json()
        self.parent.destroy()

    def create_input_list(self):
        
            if self.config_selection.value == 'Data Output Config':
                    
                self.data_output_choice_label = Text(self.mid_box, text='Data Output:',
                grid=[0, 0])
                self.data_output_choice_label.text_color = 'white'

                self.data_output_choice = Combo(self.mid_box,
                options=['local', 's3', 'ftp'], command=self.check_sub_selection,
                grid=[1, 0])
                self.data_output_choice.text_color = 'white'

                self.current_row += 1

                self.widgets_to_destroy.extend([
                    self.data_output_choice_label,
                    self.data_output_choice
                    ])

    def create_inputs(self):

        if self.config_selection.value == 'Sensor Config':

            self.sn_label = Text(self.mid_box, text='Sensor Name:',
                align='left', grid=[0, 1])
            self.sn_label.text_color = 'white'
            self.sn_input = TextBox(self.mid_box, grid=[1, 1], width=30,
                align='left',)
            self.sn_input.text_color = 'white'

            self.current_row += 1
            
            self.kf_label = Text(self.mid_box, text='K Factor:',
                align='left', grid=[0, 2])
            self.kf_label.text_color = 'white'
            self.kf_input = TextBox(self.mid_box, grid=[1, 2], width=10,
            align='left',)
            self.kf_input.text_color = 'white'

            self.current_row += 1
            
            self.su_label = Text(self.mid_box, text='Sensor Units:',
                        align='left', grid=[0, 3])
            self.su_label.text_color = 'white'
            self.su_input = TextBox(self.mid_box, grid=[1, 3], width=10,
            align='left',)
            self.su_input.text_color = 'white'

            self.current_row += 1
            
            self.du_label = Text(self.mid_box, text='Desired Units:', grid=[0, 4])
            self.du_label.text_color = 'white'
            self.du_input = TextBox(self.mid_box, grid=[1, 4], width=10,
            align='left',)
            self.du_input.text_color = 'white'

            self.current_row += 1

            self.widgets_to_destroy.extend([
                self.sn_label,
                self.sn_input,
                self.kf_label,
                self.kf_input,
                self.su_label,
                self.su_input,
                self.du_label,
                self.du_input
                ])
                      
        elif self.data_output_choice.value == 's3':

            self.l_spacer = Text(self.mid_box, text='', grid=[0, 1], width = 'fill')

            self.current_row += 1             

            self.s3_bucket_label = Text(self.mid_box, text='S3 Bucket:',
            grid=[0, 2], align='left')
            self.s3_bucket_label.text_color = 'white'

            self.s3_bucket_input = TextBox(self.mid_box, grid=[1, 2], width=30,
            align='left')
            self.s3_bucket_input.text_color = 'white'

            self.current_row += 1

            self.s3_prefix_label = Text(self.mid_box, text='S3 Folder:',
            grid=[0, 3], align='left')
            self.s3_prefix_label.text_color = 'white'

            self.s3_prefix_input = TextBox(self.mid_box, grid=[1, 3], width=30,
            align='left')
            self.s3_prefix_input.text_color = 'white'

            self.current_row += 1

            self.s3_key_label = Text(self.mid_box, text='S3 Filename:', 
            grid=[0, 4], align='left')
            self.s3_key_label.text_color = 'white'

            self.s3_key_input = TextBox(self.mid_box, grid=[1, 4], width=30,
            align='left')
            self.s3_key_input.text_color = 'white'

            self.current_row += 1

            self.s3_ak_label = Text(self.mid_box, text='User Access Key:',
            grid=[0, 5], align='left')
            self.s3_ak_label.text_color = 'white'

            self.s3_ak_input = TextBox(self.mid_box, grid=[1, 5], width=30,
            align='left')
            self.s3_ak_input.text_color = 'white'

            self.current_row += 1

            self.s3_sk_label = Text(self.mid_box, text='User Secret Key:',
            grid=[0, 6], align='left')
            self.s3_sk_label.text_color = 'white'

            self.s3_sk_input = TextBox(self.mid_box, grid=[1, 6], width=30,
            align='left')
            self.s3_sk_input.text_color = 'white'

            self.current_row += 1

            self.s3_role_label = Text(self.mid_box, text='Role to Assume:',
            grid=[0, 7], align='left')
            self.s3_role_label.text_color = 'white'

            self.s3_role_input = TextBox(self.mid_box, grid=[1, 7], width=30,
            align='left')
            self.s3_role_input.text_color = 'white'

            self.current_row += 1

            self.widgets_to_destroy.extend([
                self.s3_bucket_label,
                self.s3_bucket_input,
                self.s3_prefix_label,
                self.s3_prefix_input,
                self.s3_key_label,
                self.s3_key_input,
                self.s3_ak_label,
                self.s3_ak_input,
                self.s3_sk_label,
                self.s3_sk_input,
                self.s3_role_label,
                self.s3_role_input,
                self.l_spacer
                ])

        elif self.data_output_choice.value == 'ftp':
            
            self.l_spacer = Text(self.mid_box, text='', grid=[0, 1], width = 'fill')

            self.ftp_host_label = Text(self.mid_box, text='FTP Host:',
            grid=[0, 2], align='left')
            self.ftp_host_label.text_color = 'white'

            self.ftp_host_input = TextBox(self.mid_box, grid=[1, 2], width=30,
            align='left')
            self.ftp_host_input.text_color = 'white'

            self.current_row += 1

            self.ftp_port_label = Text(self.mid_box, text='FTP Port:',
            grid=[0, 3], align='left')
            self.ftp_port_label.text_color = 'white'

            self.ftp_port_input = TextBox(self.mid_box, grid=[1, 3], width=30,
            align='left')
            self.ftp_port_input.text_color = 'white'

            self.current_row += 1

            self.ftp_un_label = Text(self.mid_box, text='FTP Username:',
            grid=[0, 4], align='left')
            self.ftp_un_label.text_color = 'white'

            self.ftp_un_input = TextBox(self.mid_box, grid=[1, 4], width=30,
            align='left')
            self.ftp_un_input.text_color = 'white'

            self.current_row += 1

            self.ftp_pwd_label = Text(self.mid_box, text='FTP Password:',
            grid=[0, 5], align='left')
            self.ftp_pwd_label.text_color = 'white'

            self.ftp_pwd_input = TextBox(self.mid_box, grid=[1, 5], width=30,
            align='left')
            self.ftp_pwd_input.text_color = 'white'

            self.current_row += 1

            self.ftp_dir_label = Text(self.mid_box, text='Save Location:',
            grid=[0, 6], align='left')
            self.ftp_dir_label.text_color='white'

            self.ftp_dir_input = TextBox(self.mid_box, grid=[1, 6], width=30,
            align='left')
            self.ftp_dir_input.text_color='white'

            self.current_row += 1

            self.widgets_to_destroy.extend([
                self.ftp_host_label,
                self.ftp_host_input,
                self.ftp_port_label,
                self.ftp_port_input,
                self.ftp_un_label,
                self.ftp_un_input,
                self.ftp_pwd_label,
                self.ftp_pwd_input,
                self.ftp_dir_label,
                self.ftp_dir_input,
                self.l_spacer
                ])

        elif self.data_output_choice.value == 'local':
            
            self.l_spacer = Text(self.mid_box, text='', grid=[0, 1], width = 'fill')

            self.email_address_label = Text(self.mid_box, text='Email Address:',
            grid=[0, 2], align='left')
            self.email_address_label.text_color = 'white'

            self.email_address_input = TextBox(self.mid_box, grid=[1, 2], width=40,
            align='left')
            self.email_address_input.text_color = 'white'

            self.current_row += 1

            self.widgets_to_destroy.extend([
                self.email_address_label,
                self.email_address_input,
                self.l_spacer
                ])
                         
        # Create a button to return the ListBox to visible
        self.show_list_btn = PushButton(self.bottom_box, text='Back to List',
        command=self.show_config, grid=[0, self.current_row+1],
        align='bottom')
        self.show_list_btn.text_color = 'white'

        self.save_settings_btn = PushButton(self.bottom_box, text='Save Settings',
        command=self.save_settings, grid=[1, self.current_row+1], align='bottom')
        self.save_settings_btn.text_color = 'white'
        
        self.widgets_to_destroy.extend([
            self.show_list_btn,
            self.save_settings_btn
            ])
                
    def import_settings(self, kwargs):
        if kwargs['Location'] == 's3':
            self.data_output_choice.value = 's3'
            self.s3_bucket_input.value = kwargs['Settings']['Data Output']['Bucket']
            self.s3_prefix_input.value = kwargs['Settings']['Data Output']['Prefix']
            self.s3_key_input.value = kwargs['Settings']['Data Output']['Key']
            self.s3_ak_input.value = bd(kwargs['Settings']['Data Output']\
                ['Auth']['Access Key']).decode('utf-8')
            self.s3_sk_input.value = bd(kwargs['Settings']['Data Output']\
                ['Auth']['Secret Key']).decode('utf-8')
            self.s3_role_input.value = kwargs['Settings']['Data Output']\
                ['Auth']['Role']
        elif kwargs['Location'] == 'ftp':
            self.data_output_choice.value = 'ftp'
            self.ftp_host_input.value = kwargs['Settings']['Data Output']['Host']
            self.ftp_port_input.value = kwargs['Settings']['Data Output']['Port']
            self.ftp_un_input.value = bd(kwargs['Settings']['Data Output']\
                ['Auth']['Username']).decode('utf-8')
            self.ftp_pwd_input.value = bd(kwargs['Settings']['Data Output']\
                ['Auth']['Password']).decode('utf-8')
            self.ftp_dir_input.value = kwargs['Settings']['Data Output']['Directory']
        else:
            self.data_output_choice.value = 'local'
            self.email_input.value = kwargs['Email Address']
        
        self.sn_input.value = kwargs['Settings']['Sensor']['Name']
        self.kf_input.value = kwargs['Settings']['Sensor']['K Factor']
        self.su_input.value = kwargs['Settings']['Sensor']['Standard Unit']
        self.du_input.value = kwargs['Settings']['Sensor']['Desired Unit']
    
    def save_settings(self):

        if self.config_selection.value == 'Data Output Config':
            if self.data_output_choice.value == 's3':
                self.settings_dict.update({
                    'Settings': {
                        'Data Ouput': {
                            'Location': self.data_output_choice.value,
                            'Bucket': self.s3_bucket_input.value,
                            'Prefeix': self.s3_prefix_input.value,
                            'Key': self.s3_key_input.value,
                            'Access Key': be(self.s3_ak_input.value.encode('utf-8')),
                            'Secret Key': be(self.s3_sk_input.value.encode('utf-8')),
                            'Role': self.s3_role_input.value
                        }
                    }
                })

            elif self.data_output_choice.value == 'ftp':
                self.settings_dict.update({
                    'Settings': {
                        'Data Ouput': {
                            'Location': self.data_output_choice.value,
                            'Host': self.ftp_host_input.value, 
                            'Port': self.ftp_port_input.value,
                            'Username': be(self.ftp_un_input.value.encode('utf-8')),
                            'Password': be(self.ftp_pwd_input.value.encode('utf-8')),
                            'Directory': self.ftp_dir_input.value
                        }
                    }
                })
            else:
                self.settings_dict.update({
                    'Settings': {
                        'Data Ouput': {
                            'Location': self.data_output_choice.value,
                            'Email Address': self.email_address_input.value
                        }
                    }
                })

        elif self.config_selection.value == 'Sensor Config':
            self.settings_dict.update({
                'Settings': {
                    'Sensor': {
                        'Name': self.sn_input.value,
                        'K Factor': self.kf_input.value,
                        'Standard Unit': self.su_input.value,
                        'Desired Unit': self.du_input.value
                    }
                }
            })
            
        Settings.update_settings(self.settings_dict)
        info('success', 'settings staged.')
        self.return_to_main()

    def check_selection(self):

        if self.config_selection.value == 'Data Output Config':          
            # Hide the ListBox
            self.config_selection.hide()
            self.return_button.hide()
            
            # Create input widgets
            self.create_input_list()
            self.create_inputs()

        elif self.config_selection.value == 'Sensor Config':
            # Hide the ListBox
            self.config_selection.hide()
            self.return_button.hide()
            
            # Create input widgets
            self.create_inputs()

    def check_sub_selection(self):

        if self.data_output_choice.value in ['ftp', 's3'] \
            and self.config_selection.visible == False:
            # Destroy input widgets and the "Show List" button
            self.destroy_widgets()

            # Create input widgets
            self.create_inputs()

    def destroy_widgets(self):

        # Destroy existing input widgets if there are any
        for widget in self.widgets_to_destroy:
            widget.destroy()

        self.widgets_to_destroy = []  # Clear the list

    def show_config(self):

        # Destroy input widgets and the "Show List" button
        self.destroy_widgets()

        # Show the ListBox
        self.config_selection.show()
        self.return_button.show()

在我以前的任何项目中,我都没有使用过类,因为它是一个用于非常特定目的的一次性脚本,通常与移动数据有关,其中只有几个小函数。我正在努力扩展我的能力,但我真的很难理解和解决这个问题。我在这方面花了太多时间,不得不进入下一个困难的部分,即使用线程来显示数据,然后以一定的时间间隔记录它。

更改输入或函数以保留必要的设置,然后使保存设置按钮可见以将 JSON 写入文件的最有效方法是什么?

根据提供的答案的当前状态:

启动时 - check_json {'settings': {'站点名称': 无, 'sensor': {}, '数据输出': {}, '电子邮件地址': {}}}

在选择本地的 LoggerSetupPage 上保存设置按钮后 - check_json {'settings': {'数据输出': {'location': 'local', 'Email Address': ''}}}

在 LoggerSetupPage 上保存设置按钮后,选择本地并输入传感器设置 - check_json {'settings': {'sensor': {'name': '123', 'k factor': '123', 'Standard Unit': '2512', '所需单位': '441'}}}

这是我之前看到的行为。它不会保留以前添加的字典项。它正在重置自己。可能是因为我更新的是实例,而不是实际的类级字典。

蟒蛇 python 类

评论


答:

0赞 tax evader 8/27/2023 #1

根据您的用例,设置属性在类之间是一致的,我认为您应该通过将类属性(、等)设置为静态来将其设置为方法外部,并使用并删除参数将方法设置为静态。settings_directorysettings_filename__init__staticmethodself

class Settings:
    settings_directory = '/home/ect-one-user/Desktop/One_Water_Pulse_Logger/config/'
    settings_filename = ''
    json_data = {
        'Settings': {
            'Site Name': None,
            'Sensor': {

            },
            'Data Output': {

            },
            'Email Address': {

            }
        }
    }

    @staticmethod
    def update_settings(d):
        Settings.json_data.update(d)
        print(Settings.json_data)

    @staticmethod
    def check_json():
        print(Settings.json_data)
        try:
            if Settings.json_data['Settings']['Site Name'] is not None \
                and Settings.json_data['Settings']['Sensor']['Name'] is not None \
                and Settings.json_data['Settings']['Data Output']['Location'] is not None:
                return True
        except:
            return False

    @staticmethod
    def save_to_json():
        
        settings_filename = Settings.json_data['Settings']['Site Name']

        # Serialize the JSON data to a file
        with open(Settings.settings_directory + settings_filename, 'w') as sf:
            json.dump(json_data, sf, indent=4)  # Use json.dump() to serialize the data

        sf.close()
        return {'Settings' : 'Saved to file'}

    @staticmethod
    def retrieve_settings():
        settings = None
        try:
            with open(Settings.settings_directory + Settings.settings_filename, 'r') as json:
                settings = json.load(json)
            
            json.close()
        
            return settings
        except (IsADirectoryError, FileNotFoundError):
            return settings

将类属性和方法设置为静态后,可以调用函数,这些函数应该在调用方之间持久化Settings.update_settings(d)

json_data = {
    'Settings': {
        'Site Name': 'abc',
        'Sensor': {
            'abc': 1
        },
        'Data Output': {
            'abc': 2

        },
        'Email Address': {
            'abc': '[email protected]'

        }
    }
}

Settings.check_json()
data = Settings.retrieve_settings()
print(data)

Settings.update_settings(json_data)

Settings.check_json()
data = Settings.retrieve_settings()
print(data)

评论

0赞 Shenanigator 8/27/2023
我很确定我的类的一个迭代正是这样做的,但我没有添加设置。到json_data。即使添加此项也不会改变行为。它仍然不会以增量方式保存字典。我也尝试过这个@classmethod没有__init__
0赞 tax evader 8/27/2023
@Shenanigator嗯,我认为调用 Settings 方法的函数是从不同的进程运行的,因此保存的静态设置不是持久的。我对预期行为有点困惑,您能否澄清一下设置的预期输出。我认为一种方法是在初始化时将保存的设置 json 文件(如果存在)立即加载到设置静态值
0赞 Shenanigator 8/27/2023
因此,第一次运行时将没有文件。将所有适当的设置填充到字典中后,将创建该文件。第一个设置位于 MainApp 页面上,即站点名称。我提交并“更新”字典。根据你关于它们不是持久的陈述,这就是确切的问题。当我从 LoggerSetupPage 类执行设置的下一部分时,它不会持久存在。即使其余的都来自那个班级。如果无法将它们保存在内存中,那么我所能做的就是写/追加文件。
0赞 Shenanigator 8/28/2023 #2

这就是我最终到达的地方。可能有更有效的方法,但这在经过多次测试后才起作用。

from benedict import benedict as bdict
from botocore.client import Config
import boto3
import ftplib
import json
import logging

from base64 import b64decode as bd
from datetime import datetime as dt

class LoggerSettings:

settings_directory = '/home/ect-one-user/Desktop/One_Water_Pulse_Logger/config/'
settings_filename = '_logger_config.json'
json_data = {}

@staticmethod
def update_settings(d):
    bdict(LoggerSettings.json_data).merge(d, overwrite=True)

@classmethod
def check_json(cls):
    
    keys_to_get = ['Site Name', 'Sensor', 'Data Output']
    keys_exist = []
    
    while len(keys_exist) < len(keys_to_get):
        keys_exist.append(False)
    
    for i in range(len(keys_to_get)):
        if bdict.from_json(cls.json_data)\
            .search(keys_to_get[i], in_keys=True, in_values=True):        
            keys_exist[i] = True

    return keys_exist

@staticmethod
def save_to_json():
    
    json_file = LoggerSettings.settings_directory + \
        LoggerSettings.json_data['Settings']['Site Name'] + \
        LoggerSettings.settings_filename
    # Serialize the JSON data to a file
    with open(json_file, 'w') as sf:
        json.dump(LoggerSettings.json_data, sf, indent=4)  # Use json.dump() to serialize the data

    sf.close()
    return {'Settings' : 'Saved to file'}

现在在条目后从 MainApp 调用时的check_json显示如下内容

{'Site Name': 'Test Site', 'Sensor': {'Name': '1245123', 'K Factor': '12354', 'Standard Unit': '123asdf', 'Desired Unit': '123561231'}, 'Data Ouput': {'Location': 's3', 'Bucket': '123', 'Prefeix': '1155123', 'Key': '155123', 'Access Key': b'MTI1MTIz', 'Secret Key': b'MTEyMzEyNjY3', 'Role': '1123125'}}}

此编辑包括更新的 JSON 检查,此处更新为 MainApp 类verify_json函数以在返回的列表中使用 all()。

def verify_json(self):

    self.local_settings = LoggerSettings.check_json()
    print(self.local_settings)
    if all(self.local_settings):
        info('Config', 'Settings ready for save.')
        self.sv_stg_to_file.show()

谢谢你不像这里的人们的共同主题逃税者;感谢您的帮助。我对类和单例的理解更好一些,但还有很长的路要走。