0

My generate_report function has 2 parameters. Within the generate_report function I have another function named generate_sub_report. I want to use the parameters report_type and date_range within generate_sub_report.

def generate_report(report_type, date_range):
  with open('file.csv') as f:
    # do some stuff
  def generate_sub_report():
    report_map = {'Budget': ['a', 'b', 'c'], 'Finance': ['d', 'e', 'f']}
    get_list_from_dict = report_map.get(report_type)
    if date_range == 'Summary':
       columns = ...

How do I use the function parameters report_type and date_range within generate_sub_report too? What I'm trying to say is, how can I make generate_sub_report inherit the parameters from generate_report?

Edited/Updated Question

Run the code below.

It throws: UnboundLocalError: local variable 'date_range' referenced before assignment

If I change def get_keyword_report_request(report_type, date_range): with the thought that maybe I have to pass the parameters through the nested function, it then throws:

TypeError: get_keyword_report_request() missing 2 required positional arguments: 'report_type' and 'date_range'

def generate_report(report_type, date_range):
  def get_keyword_report_request():
    columns_map = {
        "Account": ["AccountName", "AccountId", "Impressions", "Clicks", "Spend",
                    "Conversions"],
        "Campaign": ["AccountName", "AccountId", "CampaignName", "Status", "Impressions",
                     "Clicks", "Spend", "Conversions"],
        "Keyword": ["AccountName", "AccountId", "CampaignName", "CampaignStatus",
                    "AdGroupName", "AdGroupStatus", "Keyword", "KeywordStatus",
                    "BidMatchType", "CurrentMaxCpc", "Impressions", "Clicks", "Spend",
                    "AveragePosition", "Conversions"],
        "Ad group": ["AccountName", "AccountId", "CampaignName", "AdGroupName", "Status",
                     "Impressions", "Clicks", "Spend", "AveragePosition", "Conversions"],
        "Search Query": ["AccountName", "AccountId", "CampaignName", "CampaignStatus",
                         "AdGroupName", "SearchQuery", "Keyword", "BidMatchType",
                         "DeliveredMatchType", "Impressions", "Clicks", "Spend",
                         "AveragePosition", "Conversions"],
        "Ad": ["AccountName", "AccountId", "CampaignName", "AdGroupName", "Status",
               "AdTitle", "AdDescription", "DisplayUrl", "DestinationUrl", "AdStatus",
               "Impressions", "Clicks", "Spend", "AveragePosition", "Conversions"]
    }

    columns = columns_map.get(report_type)

    if isinstance(date_range, list):
      # do this
      print('wha')
    elif isinstance(date_range, str):
      date_range = date_range
      print(date_range)
    return(date_range, report_type)
  get_keyword_report_request()
generate_report('Keyword', 'Summary')

My initial question still remains: How can I use the top-level function's parameters in a nested/inner function within the larger function? This is probably super-basic and I'm probably an idiot, thumbs down, that's fine. I clearly don't comprehend something very fundamental. Sorry for the lack of clarity initially.

2
  • 1
    This already works. The report_type and date_range names are available as closures in generate_sub_report. Are you having issues with this approach? Commented Sep 19, 2015 at 6:42
  • I guess that this is related to this question: Function inside function Commented Sep 19, 2015 at 6:44

1 Answer 1

3

The report_type is already available to the generate_subreport because it is automatically captured. Here's the proof:

>>> def generate_report(report_type):
...    def generate_subreport():
...       print "the report type is " + report_type
...    generate_subreport()
...
>>> generate_report('Big Report')
the report type is Big Report
>>> generate_report('Small Report')
the report type is Small Report
>>>

Update

Congratulations, you've hit one of the known Python warts. Any variables that are assigned are assumed to be a local variable.

This works:

>>> def generate_report(date_range):
...   def get_keyword_report_request():
...     print date_range
...   get_keyword_report_request()
...
>>> generate_report('Annually')
Annually

But this fails

>> def generate_report(date_range):
...   def get_keyword_report_request():
...     print date_range
...     date_range = 'Monthly' # one extra line
...   get_keyword_report_request()
...
>>> generate_report('Annually')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in generate_report
  File "<stdin>", line 3, in get_keyword_report_request
UnboundLocalError: local variable 'date_range' referenced before assignment

Python saw that you're assigning to the date_range variable in the inner function, and decided that it needed to declare a new date_range local variable in the inner function, and when you call print date_range, it throws and error because the inner date_range has not been initialised yet.

Your fix - is to remove the date_range = date_range assignment. It does absolutely nothing.

def generate_report(report_type, date_range):
  def get_keyword_report_request(): 
    columns_map = {'Account': ['AccountName', 'AccountId', 'Impressions', 'Clicks', 'Spend', 'Conversions'],
             'Campaign': ['AccountName', 'AccountId', 'CampaignName', 'Status', 'Impressions', 'Clicks', 'Spend', 'Conversions'],
             'Ad group': ['AccountName', 'AccountId', 'CampaignName', 'AdGroupName', 'Status', 'Impressions', 'Clicks', 'Spend', 'AveragePosition', 'Conversions'], #Adgroup status?
             'Ad': ['AccountName', 'AccountId', 'CampaignName', 'AdGroupName', 'Status', 'AdTitle', 'AdDescription', 'DisplayUrl', 'DestinationUrl', 'AdStatus', 'Impressions', 'Clicks', 'Spend', 'AveragePosition', 'Conversions'],
             'Keyword': ['AccountName', 'AccountId', 'CampaignName', 'CampaignStatus', 'AdGroupName', 'AdGroupStatus', 'Keyword', 'KeywordStatus', 'BidMatchType', 'CurrentMaxCpc', 'Impressions', 'Clicks', 'Spend', 'AveragePosition', 'Conversions'],
             'Search Query': ['AccountName', 'AccountId', 'CampaignName', 'CampaignStatus', 'AdGroupName', 'SearchQuery', 'Keyword', 'BidMatchType', 'DeliveredMatchType', 'Impressions', 'Clicks', 'Spend', 'AveragePosition', 'Conversions']
             }

    columns = columns_map.get(report_type)

    if isinstance(date_range, list):
      # do this
      print('wha')
    elif isinstance(date_range, str):
      # Commented out: date_range = date_range
      print(date_range)
    return(date_range, report_type)
  get_keyword_report_request()
Sign up to request clarification or add additional context in comments.

2 Comments

It's worth noting that if you do need to assign to a variable in an outside scope, in Python 3 (which the questioner is probably using, given the parentheses around his print args) you can use a nonlocal statement. In Python 2, your only options are to wrap the value in the outer scope up in some kind of container (like a list) or make it an attribute of some object. You can mutate the contents of a non-local variable with impunity, just not rebind it (without a nonlocal statement).
@Chui Tey This was super-helpful. I have never heard of the term Python Warts before. This problem was driving me crazy at the time! Your examples and explanation above is great. I should have named date_range something else, or just not made it at all (I just did it thinking it wasn't being referenced mentioned from the UnboundLocalError).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.