Python exec 命令在函数内执行无效,已解决

文章讲述了作者在使用exec和eval函数尝试在函数内部从npz_data字典中赋值时遇到的问题,以及如何通过字典解析和避免全局变量污染来解决。最后强调了在函数内部修改的限制和优化代码的权衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了很多文章,有很多介绍的很详细。但一直都不能正确使用,总是出现这样那样的问题。但学到了很多名词和描述。
继续和AI对话过程中,找到了解决方案。这里只针对个人问题做一个记录。

npz_data是一个字典,
方案2原因:由于它在函数内,所以在exec函数里添加globals(),也是错的。

但在此基础上,问了AI几个问题,就得到了正确方案。

  1. 如果把exec命令封装于一个函数内部,则会报变量未被定义的错误。有没有其它的方法,可以解决这个问题
  2. 有没有与exec类似功能的函数或包,可以替代它
  3. for key in npz_data: # .files
    exec(f"{key} = npz_data[‘{key}’]")
    用eval函数实现以上代码的功能
  4. eval(f"{key} = npz_data[‘{key}’]")
    File “”, line 1
    up_pair_idx = npz_data[‘up_pair_idx’]
    ^
    SyntaxError: invalid syntax

正确答复:

根据你提供的错误追踪信息,问题出现在以下这行代码:

eval(f"{key} = npz_data['{key}']")

这是因为在eval函数中,你试图执行一个赋值操作,但这不是有效的Python语法。eval函数只能用于执行表达式,而不能执行赋值语句。

如果你想将npz_data字典中的值赋给相应的变量名,你可以使用字典解析来实现。这里是一个示例:

for key in npz_data:  
    globals()[key] = npz_data[key]

这里,globals()函数返回当前全局符号表,然后我们通过key将npz_data中的值赋给全局变量。

但是,请注意,这种方法可能会导致命名冲突和意外的副作用,因为它直接修改了全局符号表。更好的做法是使用一个临时字典来存储结果,或者创建一个新的命名空间来存储这些变量。

   def update_mark2npz(self, prd_uni):
       npz_data, df = self.read_npz(prd_uni)
       # 方案1:失败
       # for key in npz_data: 
	   #	 exec(f"{key} = npz_data['{key}']")
       # 方案2:失败
       # for key in npz_data: 
       #     exec(f"{key} = npz_data['{key}']", globals())
       # 方案3:失败
       # for key in npz_data: 
       #     eval(f"{key} = npz_data['{key}']") 
       for key in npz_data:
           globals()[key] = npz_data[key]

修.240112

还是不能在函数内修改,只能调用。
想修改还是要再次global var1…
所以仅调用,可以方便使用。但如果要做修改,还是常规引用吧。
有时候优化代码会上瘾,这里先自我妥协了**-_-!!!**

<think>我们正在解决PyQt5中QWebEngineView加载Bilibili网页视频无法播放的问题。根据引用[1]和引用[2],我们知道问题可能出在网站使用video.js导致使用Flash播放,而QtWebEngine对Flash的支持可能不够好(尤其是国内视频网站)。另外,引用[1]提到Youtube可以全屏,但Bilibili不行,说明可能是Bilibili的播放器适配问题。解决方案思路:1.强制使用HTML5播放器:因为QtWebEngine是基于Chromium的,支持HTML5视频,但Bilibili可能会因为User-Agent等原因判断为不支持HTML5而回退到Flash。2.设置正确的User-Agent:将QWebEngineView的User-Agent设置为常见的浏览器(如Chrome),以欺骗网站使用HTML5播放器。3.启用必要的特性:如已经设置的PluginsEnabled,JavascriptEnabled,FullScreenSupportEnabled等。根据引用[1]中的代码,已经启用了FullScreenSupportEnabled并连接了fullScreenRequested信号,但全屏无效。因此,我们重点解决播放问题。步骤:1.设置User-Agent:通过QWebEngineProfile设置User-Agent字符串,模拟Chrome浏览器。2.确保禁用Flash(因为Flash可能无法正常工作),并强制使用HTML5。但注意,在引用[1]中启用了PluginsEnabled,这可能会启用Flash,我们可以尝试禁用插件(即设置PluginsEnabled为False)来避免使用Flash。3.另外,Bilibili可能会根据浏览器能力检测来决定使用哪种播放器,我们可以通过注入JavaScript来覆盖其检测结果,强制使用HTML5播放器。然而,根据引用[2]中提到,QWebEngineView对HTML5视频的支持可能也有问题(尤其是在加载本地文件时),但Bilibili是在线视频,所以情况不同。我们尝试以下方法:方法1:设置User-Agent方法2:禁用插件(避免Flash)方法3:通过JavaScript注入强制使用HTML5播放器(需要知道Bilibili页面中如何设置)但是,由于Bilibili页面复杂,注入JavaScript可能比较困难。因此,我们优先尝试设置User-Agent和禁用插件。参考引用[1]中的代码,修改如下:1.在创建QWebEngineView后,设置User-Agent:w.setUrl(...)之前,获取profile并设置User-Agent字符串。2.禁用插件:将w.settings().setAttribute(QWebEngineSettings.PluginsEnabled,False)注意:原代码中启用了PluginsEnabled,我们尝试将其设置为False。另外,我们也可以尝试启用其他属性,如QWebEngineSettings.PlaybackRequiresUserGesture(设置是否需要用户手势才能播放),因为有些网站要求用户交互后才能播放视频。但Bilibili一般有播放按钮,所以可能不需要。具体修改代码:由于Bilibili可能会更新,我们还可以尝试加载其他使用HTML5的视频网站(比如引用[1]中的Youtube)来验证User-Agent和设置是否有效。代码修改示例:```pythonimportsysfromPyQt5importQtWidgets,QtCorefromPyQt5.QtWebEngineWidgetsimportQWebEngineView,QWebEngineSettingsfromPyQt5.QtWebEngineWidgetsimportQWebEngineProfile#用于设置User-Agentdef_fullScreenRequested(request):request.accept()#注意:这里原代码是w.showFullScreen(),但w是全局变量,我们可以将其改为请求的页面所在的视图#实际上,request的页面就是当前页面,我们可以用以下方式获取视图view=request.webEngineView()ifview:view.showFullScreen()app=QtWidgets.QApplication(sys.argv)#支援flash-但这里我们不使用flash,所以可以去掉#但注意:如果去掉了,需要确保不加载flash插件#argvs.append('--ppapi-flash-path=./pepflashplayer.dll')#注释掉,不使用flashw=QWebEngineView()#设置User-Agent,模拟Chromeuser_agent="Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/91.0.4472.124Safari/537.36"w.page().profile().setHttpUserAgent(user_agent)#设置WebEngine属性settings=w.settings()settings.setAttribute(QWebEngineSettings.PluginsEnabled,False)#禁用插件(包括Flash)settings.setAttribute(QWebEngineSettings.JavascriptEnabled,True)settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled,True)settings.setAttribute(QWebEngineSettings.PlaybackRequiresUserGesture,False)#设置不需要用户手势即可播放#连接全屏请求信号w.page().fullScreenRequested.connect(_fullScreenRequested)#加载Bilibili视频w.load(QtCore.QUrl('https://www.bilibili.com/video/BV1xx411c7BF'))#可以换一个视频测试w.show()app.exec_()```注意:上面的User-Agent字符串可以更换为最新的Chrome版本。另外,如果仍然无法播放,可能是Bilibili页面有其他检测机制。我们可以尝试在页面加载完成后注入JavaScript代码来覆盖其播放器设置。但是,由于Bilibili页面结构复杂,这需要具体分析,且可能随时失效。如果上述方法无效,我们可以考虑使用其他方式,比如使用mpv等播放器内核,或者使用Bilibili的API获取视频流地址,但这超出了QWebEngineView的范围。由于引用[3]和引用[4]是关于嵌入ECharts和创建窗口的,与视频播放问题关系不大,所以我们主要参考引用[1]和引用[2]。总结:我们通过设置User-Agent模拟Chrome浏览器,并禁用插件(避免使用Flash)来尝试让Bilibili提供HTML5播放器。如果问题仍然存在,可能需要进一步调试,例如:1.检查控制台输出:通过QWebEngineView的javaScriptConsoleMessage信号来获取控制台信息,可能有助于诊断问题。2.尝试其他视频网站(如Youtube)确认是Bilibili的问题还是通用问题。以上是解决该问题的主要思路和代码修改。注意:由于网络环境和网站更新,解决方案可能需要调整。相关问题:1.如何通过QWebEngineView获取网页的JavaScript控制台消息?2.在PyQt5中如何通过QWebEngineView执行JavaScript代码?3.如何解决QWebEngineView中网页视频自动播放的问题?</think>### PyQt5 QWebEngineView 加载 Bilibili 视频无法播放的解决方案 在 PyQt5 中使用 QWebEngineView 加载 Bilibili 视频无法播放的主要原因包括: 1. **用户代理检测问题**:Bilibili 根据 User-Agent 判断浏览器环境 2. **播放器选择机制**:网站会优先选择 Flash 播放器而非 HTML5 3. **DRM 和编解码器限制**:QWebEngineView 默认不支持某些视频编码格式 4. **权限设置缺失**:未启用必要的 Web 引擎功能 #### 完整解决方案代码 ```python import sys from PyQt5 import QtWidgets, QtCore from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings, QWebEngineProfile # 解决全屏问题的回调函数 def handle_fullscreen(request): request.accept() # 获取关联的 WebEngineView 并切换全屏状态 view = request.webEngineView() if view.isFullScreen(): view.showNormal() else: view.showFullScreen() # 主程序 app = QtWidgets.QApplication(sys.argv) # 1. 设置现代浏览器 User-Agent user_agent = ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/91.0.4472.124 Safari/537.36" ) # 创建 WebEngineView webview = QWebEngineView() profile = QWebEngineProfile.defaultProfile() profile.setHttpUserAgent(user_agent) # 应用自定义 UA # 2. 启用必要功能 settings = webview.settings() settings.setAttribute(QWebEngineSettings.PluginsEnabled, True) settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True) settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) settings.setAttribute(QWebEngineSettings.PlaybackRequiresUserGesture, False) # 允许自动播放 # 3. 连接全屏信号 webview.page().fullScreenRequested.connect(handle_fullscreen) # 4. 强制使用 HTML5 播放器(针对 Bilibili) # 在页面加载完成后注入 JS 强制使用 HTML5 播放器 def force_html5_player(): js_code = """ // 尝试覆盖 Bilibili 播放器检测逻辑 if (typeof window.__playinfo__ !== 'undefined') { window.__playinfo__.support_formats = [{ description: "html5" }]; } // 强制使用 HTML5 视频元素 const videoElements = document.querySelectorAll('video'); videoElements.forEach(video => { if (video.__vue__) video.__vue__.enableH5Player(); }); """ webview.page().runJavaScript(js_code) webview.loadFinished.connect(force_html5_player) # 加载 Bilibili 视频 webview.load(QtCore.QUrl('https://www.bilibili.com/video/BV1GJ411x7h7')) # 示例视频 webview.show() sys.exit(app.exec_()) ``` #### 关键配置说明 1. **用户代理设置**: ```python user_agent = "Mozilla/5.0 ... Chrome/91.0.4472.124 Safari/537.36" profile.setHttpUserAgent(user_agent) ``` 使用最新 Chrome 的 UA 欺骗 Bilibili 识别为现代浏览器[^1] 2. **功能启用设置**: ```python settings.setAttribute(QWebEngineSettings.PluginsEnabled, True) # 启用插件 settings.setAttribute(QWebEngineSettings.PlaybackRequiresUserGesture, False) # 解除自动播放限制 ``` 3. **HTML5 强制启用**: ```javascript // 覆盖 Bilibili 内部播放器检测 if (typeof window.__playinfo__ !== 'undefined') { window.__playinfo__.support_formats = [{ description: "html5" }]; } ``` 4. **全屏支持**: ```python webview.page().fullScreenRequested.connect(handle_fullscreen) ``` #### 补充建议 1. **启用硬件加速**(在应用启动前添加): ```python QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_UseSoftwareOpenGL, False) ``` 2. **安装媒体编解码器**: - 在 Windows 安装 [Web Media Extensions](https://www.microsoft.com/store/productId/9N5TDP8VCMHS) - Linux 安装 `libavcodec-extra` 包 3. **调试模式**(查看控制台错误): ```python webview.page().javaScriptConsoleMessage.connect( lambda level, msg, line, source: print(f"JS ERROR: {msg}") ) ``` #### 技术原理 Bilibili 会根据 `navigator.userAgent` 和 `navigator.plugins` 判断浏览器环境。当检测到非常规浏览器(如 QtWebEngine)时,会默认使用 Flash 播放器而非 HTML5 播放器。通过覆盖 UA 和强制设置播放器参数,可绕过此检测机制[^1][^2]。 > **注意**:Bilibili 可能更新其播放器检测逻辑,若此方案失效,需更新注入的 JS 代码以适应新机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值