main中的局部变量由其他程序的函数修改,即使它不应该修改

2024-05-06 06:34:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我在为python课程做作业时遇到了python错误。任务是使用添加和列表(打印所有元素)等操作创建一个费用数组

该错误在任何版本的Python(3.7,3.8,3.9)和不同的IDE(VisualStudio、PyCharm、一些在线解释器)中都存在

要描述错误,请执行以下操作: 主函数中的变量由辅助函数修改,即使没有处理程序修改该数据。我假设程序将主函数中的变量视为全局变量

我是python的新手,所以我可能只是不理解该语言的一些基本概念

这就是代码(我知道我不应该发布全部代码,但我不知道错误来自何处):

from datetime import date

def get_day_of_expense(_element):
    return int(_element['day'])


def get_type_of_expense(_element):
    return _element['expense type']


def get_amount_of_money_of_expense(_element):
    return int(_element['amount of money'])


def function_add_a_new_expense(expenses_table, _expense_type, _day, _amount_of_money):
    expenses_table.append({'day': _day, 'expense type': _expense_type, 'amount of money': _amount_of_money})
    return expenses_table


def check_for_expense_type(expenses_table_types, _expense_type):
    '''
    This function check if the searched _expense_type is a valid one (exists in array of types)
    :param: expenses_table_types: array of expense types
    :pram: _expense_type: the searched value type
    :return: True if the element was found, False otherwise
    '''
    for expense_type in expenses_table_types:
        if _expense_type == expense_type:
            return True
    return False


def check_for_command(command_dictionary, _command_name):
    '''
    This function check if the searched command is a valid one (exists in array of commands)
    :param: command_dictionary: dictionary of commands
    :pram: _command_name: the searched command
    :return: True if the element was found, False otherwise
    '''
    for command in command_dictionary.keys():
        if command == _command_name:
            return True
    return False


def finish_program(expenses_table_types, expenses_table, _data_array):
    return {'continue': False, 'expenses_table': expenses_table, 'message': "Goodbye"}


def get_today_date():
    return date.today().day


def initialize_command_dictionary():
    command_dictionary = {
        'add': {'description': "Add a new expense in current day : add <sum> <expense type>",
                'command': add_a_new_expense},
        'list': {
            'description': "Print all expenses : list", 'command': display_all_expenses_UI},
        'exit': {'description': 'Exit the program', 'command': finish_program}
    }
    return command_dictionary


def to_str(_expense):
    return 'Day: ' + str(get_day_of_expense(_expense)).rjust(2) + ', Expense type: ' + str(
        get_type_of_expense(_expense)).ljust(12) + ' > ' + str(get_amount_of_money_of_expense(_expense)).rjust(4)


def add_a_new_expense(expenses_table_types, expenses_table, _data_array):
    """
    This function handles the add command
    :param: expenses_table_types: array of expense types
    :param: expenses_table: the list of expenses
    :param: _data_array: the input command parsed by words [command,amount of money,expense_type]
    :return: a dictionary with properties continue ( True or False if the program should continue or not), updated expenses_table array and message, a string that can be a confirmation or an error
    """
    if (len(_data_array) < 3):
        return {'continue': True, 'expenses_table': expenses_table, 'message': "Incomplete command"}
    elif len(_data_array) > 3:
        return {'continue': True, 'expenses_table': expenses_table, 'message': "Command is too long"}
    else:
        try:
            _day = get_today_date()
        except:
            return {'continue': True, 'expenses_table': expenses_table, 'message': "Could not query date correctly"}
        try:
            _amount_of_money = int(_data_array[1])
            if (_amount_of_money < 1):
                return {'continue': True, 'expenses_table': expenses_table,
                        'message': "Amount of money should be greater than 0"}
        except ValueError:
            return {'continue': True, 'expenses_table': expenses_table, 'message': "Amount of money must be an integer"}
        expense_type = _data_array[2]
        if not check_for_expense_type(expenses_table_types, expense_type):
            return {'continue': True, 'expenses_table': expenses_table, 'message': "This expense type does not exist"}
        else:
            expenses_table = function_add_a_new_expense(expenses_table, expense_type, _day, _amount_of_money)
            return {'continue': True, 'expenses_table': expenses_table, 'message': "Added the expense"}


def display_all_expenses_UI(expenses_table_types, expenses_table, command_split_in_words):
    """
    This function prints the array of expenses
    :param: expenses_table_types: array of expense types
    :param: expenses_table_types,command_split_in_words : 2 extra so I can call from command_dictionary
    :return: a dictionary with properties continue ( True or False if the program should continue or not), updated expenses_table array and message, a string that can be a confirmation or an error
    """
    for _expense in expenses_table:
        print(to_str(_expense))
    if len(expenses_table) == 0:
        return {'continue': True, 'expenses_table': expenses_table, 'message': "The selection of the list is null"}
    return {'continue': True, 'expenses_table': expenses_table, 'message': ""}


def print_menu(command_dictionary):
    print(
        '--------------------------------------------------------------------------------------------------------------------')
    for command in command_dictionary.keys():
        print(command + ": " + command_dictionary[command]['description'])


def command_handler(expenses_table_types, expenses_table, command):
    """
    This function takes the input, converts it into an array of words and calls the function needed
    :param: expenses_table_types: array of expense types
   :param: expenses_table: the list of expenses
   :param: command: input that was just read and waits to be parsed
   :return: a dictionary with properties continue ( True or False if the program should continue or not), updated expenses_table array and message, a string that can be a confirmation or an error

    """
    command_dictionary = initialize_command_dictionary()
    command_split_in_words = command.strip().split(' ')
    _command_name = command_split_in_words[0]
    if check_for_command(command_dictionary, _command_name):
        return command_dictionary[_command_name]['command'](expenses_table_types, expenses_table,
                                                            command_split_in_words)
    else:
        return {'continue': True, 'expenses_table': expenses_table, 'message': "Invalid command"}


def menu_handler(expenses_table_types, expenses_table):
    """
    This function ensure the user interface and reads the commands
    :param: expenses_table_types: array of expense types
    :param: expenses_table: the list of expenses
    :return: calls the function command_handler which will continue interpreting the command
    """
    command_dictionary = initialize_command_dictionary()
    print_menu(command_dictionary)
    command = input("Give a command: ")
    return command_handler(expenses_table_types, expenses_table, command)


def test_init(expenses_table_types, expenses_table):
    # use this function to add the 10 required items
    command_handler(expenses_table_types, expenses_table, 'add 25 clothing')
    command_handler(expenses_table_types, expenses_table, 'add 100 internet')
    command_handler(expenses_table_types, expenses_table, 'add 1230 others')
    display_all_expenses_UI(expenses_table_types, expenses_table,[])  # this prints the expenses_table with all those 3 elements previously added, even though I don't save the elements
    command_handler(expenses_table_types, expenses_table, 'add 15 transport')
    command_handler(expenses_table_types, expenses_table, 'add 50 food')
    command_handler(expenses_table_types, expenses_table, 'add 30 housekeeping')
    add_a_new_expense(expenses_table_types, expenses_table, ['add', '50', 'housekeeping']) # this also does that weird behaviour. Item is added even though it shoulnd't
    print('------------------------------Second test output. This should not work---------------------------------')
    display_all_expenses_UI(expenses_table_types, expenses_table,[])

def main():
    expenses_table = []
    expenses_table_types = ['housekeeping', 'food', 'transport', 'clothing', 'internet', 'others']
    test_init(expenses_table_types, expenses_table)
    print('-----------------------------------Testing again in main. This should also not work---------------------------------------------')
    display_all_expenses_UI(expenses_table_types, expenses_table, [])
    _continue = True
    while _continue:
        _result = menu_handler(expenses_table_types, expenses_table)
        print(_result['message'])
        _continue = _result['continue']
        expenses_table = _result['expenses_table']
    '''
    This also works
    while _continue:
        menu_handler(expenses_table_types, expenses_table)
        display_all_expenses_UI(expenses_table_types, expenses_table, [])
    '''
    '''
    This also works
    while _continue:
        menu_handler(expenses_table_types, expenses_table)
        print(expenses_table) 
        
    just checked not to be a weird link between functions, to pass false data between them
    '''
main()


1条回答
网友
1楼 · 发布于 2024-05-06 06:34:05

不能从其他函数更改变量

但是!列表是一个对象,您可以从另一个函数更改任何对象,只要您为该函数提供指向该对象的链接:

def function_1():
    variable_1 = 'Hello from function 1!'
    
    
def function_2(give_me_the_variable):
    give_me_the_variable = 'Hello from function 2!'


def function_3(give_me_link_to_the_object):
    give_me_link_to_the_object[0] = 'data from function_3'

    
def main():
    variable_1 = 'Hello from main!'
    print(variable_1)
  
    function_1()
    print('Variable is still: ' + variable_1)
   
    function_2(variable_1)
    print('Variable is still: ' + variable_1)

    test_list = ['main1', 'main2', 'main3']
    print('Data from list without changes: ' + str(test_list))

    function_3(test_list)
    print('Data from test_list after changing from function_3: ' + str(test_list))
    
    
main()

输出将是:

Hello from main!

Variable is still: Hello from main!

Variable is still: Hello from main!

Data from list without changes: ['main1', 'main2', 'main3']

Data from test_list after changes from function_3: ['data from function_3', 'main2', 'main3']

您可以将列表转换为元组(不可更改的列表),并将它们提供给函数,以确保函数无法更改列表中的数据:

my_list = ['param1', 'param2', 'param3']
my_tuple = tuple(my_list)

print(type(my_tuple))
print(my_tuple)

对我的英语很抱歉:))

相关问题 更多 >