如何将函数内创建的pandas DataFrame转为全局可访问变量?
如何将函数内创建的Pandas DataFrame提取为全局可访问变量
嘿,作为Pandas和Python的初学者,我完全理解你想在函数外部拿到生成的DataFrame的需求!这里有几个不同的方案,从直接满足你需求的全局变量方法,到更符合Python最佳实践的实现方式,你可以根据自己的场景选择:
方案1:使用全局变量(直接满足需求)
你可以在全局作用域先声明df变量,然后在print_response函数里通过global关键字指定要使用全局变量,最后把生成的DataFrame赋值给它:
import pandas as pd from oauth2client.service_account import ServiceAccountCredentials from apiclient.discovery import build # 全局作用域初始化df df = None KEY_FILE_LOCATION = "your-key-file.json" SCOPES = ['https://www.googleapis.com/auth/analytics.readonly'] VIEW_ID = "your-view-id" def initialize_analyticsreporting(): credentials = ServiceAccountCredentials.from_json_keyfile_name( KEY_FILE_LOCATION, SCOPES) analytics = build('analyticsreporting', 'v4', credentials=credentials) return analytics def get_report(analytics): return analytics.reports().batchGet( body={ 'reportRequests': [ { 'viewId': VIEW_ID, 'pageSize': 100000, 'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'yesterday'}], 'metrics': [{'expression': 'ga:sessions'}], 'dimensions': [{'name': 'ga:country'}, {'name': 'ga:hostname'}, {'name': 'ga:pagePathLevel1'}, {'name': 'ga:pagePathLevel2'}, {'name': 'ga:keyword'}, {'name': 'ga:adMatchedQuery'}, {'name': 'ga:operatingSystem'}, {'name': 'ga:hour'}, {'name': 'ga:exitPagePath'}] } ] } ).execute() def print_response(response): global df # 声明要使用全局变量df data_list = [] # 避免用list作为变量名,它是Python内置类型 for report in response.get('reports', []): columnHeader = report.get('columnHeader', {}) dimensionHeaders = columnHeader.get('dimensions', []) metricHeaders = columnHeader.get( 'metricHeader', {}).get('metricHeaderEntries', []) rows = report.get('data', {}).get('rows', []) for row in rows: row_dict = {} # 同样避免用dict作为变量名 dimensions = row.get('dimensions', []) dateRangeValues = row.get('metrics', []) for header, dimension in zip(dimensionHeaders, dimensions): row_dict[header] = dimension for i, values in enumerate(dateRangeValues): for metric, value in zip(metricHeaders, values.get('values')): if ',' in value or '.' in value: row_dict[metric.get('name')] = float(value) else: row_dict[metric.get('name')] = int(value) data_list.append(row_dict) df = pd.DataFrame(data_list) return df def main(): analytics = initialize_analyticsreporting() response = get_report(analytics) print_response(response) if __name__ == '__main__': main() # 现在可以在函数外部直接访问df了 print(df.head())
⚠️ 注意:全局变量虽然简单,但在大型项目中容易导致代码逻辑混乱,难以追踪变量的修改,所以仅推荐在小型脚本中临时使用。
方案2:让main函数返回DataFrame(推荐的规范方式)
这是更符合Python设计理念的做法:让main函数返回生成的DataFrame,然后在主程序中赋值给变量,这样既避免了全局变量的副作用,又能在外部访问数据:
# 导入和常量定义部分与方案1一致 # initialize_analyticsreporting、get_report、print_response函数保持不变(去掉global相关代码) def main(): analytics = initialize_analyticsreporting() response = get_report(analytics) return print_response(response) # 返回生成的DataFrame if __name__ == '__main__': df = main() # 将返回的DataFrame赋值给全局可用的df # 后续可以直接使用df print(df.describe())
这种方式逻辑清晰,函数职责明确(生成数据的函数返回数据,主程序负责接收和使用),代码更易维护。
方案3:封装成类(适合长期扩展的项目)
如果你的后续需求会不断扩展(比如添加数据清洗、分析功能),可以把所有相关逻辑封装成类,将DataFrame作为类的实例属性,方便后续方法调用:
import pandas as pd from oauth2client.service_account import ServiceAccountCredentials from apiclient.discovery import build KEY_FILE_LOCATION = "your-key-file.json" SCOPES = ['https://www.googleapis.com/auth/analytics.readonly'] VIEW_ID = "your-view-id" class AnalyticsReportProcessor: def __init__(self): self.df = None # 初始化DataFrame属性 self.analytics = self._initialize_analyticsreporting() def _initialize_analyticsreporting(self): credentials = ServiceAccountCredentials.from_json_keyfile_name( KEY_FILE_LOCATION, SCOPES) return build('analyticsreporting', 'v4', credentials=credentials) def _get_report(self): return self.analytics.reports().batchGet( body={ 'reportRequests': [ { 'viewId': VIEW_ID, 'pageSize': 100000, 'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'yesterday'}], 'metrics': [{'expression': 'ga:sessions'}], 'dimensions': [{'name': 'ga:country'}, {'name': 'ga:hostname'}, {'name': 'ga:pagePathLevel1'}, {'name': 'ga:pagePathLevel2'}, {'name': 'ga:keyword'}, {'name': 'ga:adMatchedQuery'}, {'name': 'ga:operatingSystem'}, {'name': 'ga:hour'}, {'name': 'ga:exitPagePath'}] } ] } ).execute() def _process_response(self, response): data_list = [] for report in response.get('reports', []): columnHeader = report.get('columnHeader', {}) dimensionHeaders = columnHeader.get('dimensions', []) metricHeaders = columnHeader.get( 'metricHeader', {}).get('metricHeaderEntries', []) rows = report.get('data', {}).get('rows', []) for row in rows: row_dict = {} dimensions = row.get('dimensions', []) dateRangeValues = row.get('metrics', []) for header, dimension in zip(dimensionHeaders, dimensions): row_dict[header] = dimension for i, values in enumerate(dateRangeValues): for metric, value in zip(metricHeaders, values.get('values')): if ',' in value or '.' in value: row_dict[metric.get('name')] = float(value) else: row_dict[metric.get('name')] = int(value) data_list.append(row_dict) self.df = pd.DataFrame(data_list) def run(self): response = self._get_report() self._process_response(response) if __name__ == '__main__': processor = AnalyticsReportProcessor() processor.run() # 通过实例属性访问DataFrame print(processor.df.head())
这种方式把所有相关逻辑聚合在一起,代码结构更清晰,后续添加新功能(比如数据过滤、可视化)时可以直接在类中新增方法,非常适合需要长期维护的项目。
内容的提问来源于stack exchange,提问作者Jonas Palačionis
相关产品推荐
相关产品推荐

