1
def create_and_update_worksheets():
    """
    Add 'Player statistics' if the worksheet is not in file_name. 
    Otherwise, it will update the worksheet itself.
    """

    os.chdir(os.path.dirname(os.path.abspath(__file__)))

    writer = pd.ExcelWriter(file_name, engine='openpyxl')
    row = 0

    for item in worksheets['Game Schedule'].values():
        multiple_dfs(item, 'Game Schedule')

    for sheet in writer.sheets.values():
        resize_columns(sheet)

    writer.save()
    writer.close()

In this actual code, writer and row is already defined, but I got some error if I decide to implement multiple_dfs as :

def multiple_dfs(item, sheets):
    """
    Put multiple dataframes into one xlsx sheet
    """

    response = send_request(item).content
    df = pd.read_csv(io.StringIO(response.decode('utf-8')))

    df.to_excel(writer, sheets, startrow=row, index=False)
    row = row + len(df) + 2

I got the following error for writer, but the same thing happened with row.

Traceback (most recent call last):
  File "create_and_update_xlsx_sheets.py", line 66, in <module>
    create_and_update_worksheets()
  File "create_and_update_xlsx_sheets.py", line 56, in create_and_update_worksheets
    multiple_dfs(item, 'Game Schedule')
  File "create_and_update_xlsx_sheets.py", line 33, in multiple_dfs
    df.to_excel(writer, sheets, startrow=row, index=False)
NameError: name 'writer' is not defined

How could I fix those errors? I don't want to redefine them in multiple_dfs, but I will need to redefine them in future function as well.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • 1
    For starters, you could pass `writer` to your function that uses it. How will your function know to use a variable that it doesn't have access to? `writer` is not a global variable to begin with. – cs95 Oct 15 '17 at 21:09
  • @cᴏʟᴅsᴘᴇᴇᴅ Do you mean `multiple_dfs(item, sheets, writer, row)`? I would like to avoid such practice. Could I define `writer` as a global variable in staying in `create_and_update_worksheets()` function? What do you suggest? –  Oct 15 '17 at 21:11
  • Why do you want to avoid something in favour of something else that you _should_ be avoiding? `global` variables are a bad practice and lead to code smell, and besides, you shouldn't really be using global variables here since the writer is closed just before the function exits. – cs95 Oct 15 '17 at 21:15
  • @cᴏʟᴅsᴘᴇᴇᴅ Suppose I have `variable1`, `variable2`, ..., `variableN` in both function a bit like `writer` and `row`, I don't think it is a good practice to display `multiple_dfs(item, sheets, writer, row, variable1, ..., variableN)`. What do you suggest in that case? –  Oct 15 '17 at 21:20
  • Pass a list or variable arguments... https://stackoverflow.com/questions/3394835/args-and-kwargs – cs95 Oct 15 '17 at 21:21
  • Ok, I am not used to with that practice. Could you show me how to define `multiple_dfs` and how to use it inside `create_and_update_worksheets`? I think I would appreciate a lot. –  Oct 15 '17 at 21:24
  • Yes, you are right, and I did it often. –  Oct 15 '17 at 21:41
  • To accept a question, you must check the grey arrow next to an answer and toggle it to green. Accepting an answer shows the community that answer worked for you, and helps others understand your question was solved. Also, see my answer. – cs95 Oct 15 '17 at 21:42
  • (While you've gotten your follow-up question answered, we generally frown on editing a question that already has a correct and useful answer in a way that makes that answer invalid or incomplete -- better to ask an additional question). – Charles Duffy Oct 15 '17 at 21:51

1 Answers1

2

Even though you're calling the function from a scope where writer exists, the callee cannot see it, that's just how python's scoping rules work.

I'd recommend having your multiple_dfs function accept another parameter called writer, which you pass from the caller function. If you have multiple arguments to pass besides writer, you'd need to use variable arguments.

def multiple_dfs(item, sheets, *args):
    for i, var in enumerate(args, 1):
        print('variable {}: {}'.format(i, var))
    ...

Calling multiple_dfs:

multiple_dfs(item, 'Game Schedule', variable1, variable2, ...)
cs95
  • 379,657
  • 97
  • 704
  • 746
  • @J.Doe add this line: `writer, row = args[:2]`, it seems you need to read a python tutorial. Also, unaccepting an answer because of your mistakes is a bit unfair, don't you think. – cs95 Oct 15 '17 at 22:01
  • Do not be suceptible. I will accept an answer when my problem is completely resolved. –  Oct 15 '17 at 22:03
  • @J.Doe You do realise that, to access a variable, it must have been declared? `multiple_dfs` has your writer as `args[0]`, so you should access it that way, or assign it to something else. If you do not know that, that means you need to read a python tutorial on how variables and parameter passing works. – cs95 Oct 15 '17 at 22:05