百科问答小站 logo
百科问答小站 font logo



为什么 macOS 在 /usr/bin/ 下会有 python3? 第1页

  

user avatar   changanmoon 网友的相关建议: 
      

简略版答案:

题目中的这个 Python 3.8.2 来自于苹果的一套命令行开发者工具(command line developer tools),其对应目录在:

       /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework     

而在终端执行/usr/bin目录下的python3时,终端先根据环境变量PATH扫描是否有 Python 3.x 的可执行程序,若不存在,则调出命令行开发者工具的安装程序,引导用户安装。

命令行开发者工具并不会对从官网下载安装的 Python 有任何影响,并且也不建议开发者删除(因为这也会将gitclanggccflex等工具一并删除)。

只有当并不需要额外的其他工具,并认为此确实困扰到了自己的时候,才可以将其删掉,这个 Python 3.8.2 就随之消失了,执行如下命令即可:

       sudo rm -rf /Library/Developer/CommandLineTools     

(以下为原文)

这个问题提的很好,平常我用 macOS 的时候从未想到会有这个问题。

因为 macOS 是一个类 Unix 系统,系统文件结构与 Linux 类似,以我用 Linux 的经验来看,按理说,/usr/bin目录下的python3是一个链接文件(替身),可以从它找到相应指向的源文件(原身),进而可以得出系统内置 Python 3 所在的目录。

但我用

       cd /usr/bin && ls -la@O | grep python3     

查看了这个文件的属性,却发现“python3”是一个可执行文件:

       -rwxr-xr-x     1 root   wheel  restricted,compressed   137600  1  1  2020 python3     

这确实令我困惑,因为官方的帮助里并没有对这个细节作任何提及,不过我发现这样一个链接——

注意到了这样一句话:

A clean installation of Catalina includes a/usr/bin/python3binary, but it's a stub for installing the command line developer tools, which includes Python 3.

“stub”这个词有“桩脚”的意思,但这里我没能理解,不过我注意到了“clean installation”和“command line developer tools”。

所以可猜:macOS “内置”的 Python 3 很可能与命令行开发者工具有关。

为验证猜想,我从头创建了一个 macOS 虚拟机,当我迫不及待地执行python3这个命令的时候,神奇的一幕出现了:

系统竟然提示我安装命令行开发者工具 (以下简称 CLDT) ?!

安装好后,python3命令可以正常使用了,当然这个版本就是 3.8.2,和题目一模一样。然后开始搜索 Python 3.8.2 的相应资源,结果发现全在这里:

       /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework     

相应的 CLDT 目录在:

       /Library/Developer/CommandLineTools     

接下来删掉 CLDT 的目录(以下就是把它卸载的方法):

       sudo rm -rf /Library/Developer/CommandLineTools     

结果发现删除目录之后python3命令又会失效,回到前面的提示了。

但若从 python.org 安装好 Python,执行python3命令后,其显示的 Python 版本却是已经安装的版本。

所以,这个诡异的执行文件/usr/bin/python3的作用大概可以知道了:单独运行此程序时,调用 CLDT 中的 Python 3,若无 CLDT,且无手动安装的 Python,则激活“Install Command Line Developer Tools”应用,引导用户安装。[1]

可能有人会问了:为什么从终端调用python3命令(而不是手动双击执行那个二进制文件)的时候,就只会运行手动安装的 Python 呢?

原因是环境变量 PATH 默认先加载配置在最前面的路径,如果某命令已经加载完毕,则不再继续往下寻找,否则会继续寻找,直到全部加载为止,若完全找不到,当然会输出“command not found”啦。

比方说我的用户名为administrator(大雾),执行如下命令:

       echo $PATH | awk '{ gsub(/:/,"
"); print $0 }'     

输出结果如下(这就是我的 Mac 上的PATH变量的设定,分行显示的):

       /usr/local/sbin /usr/local/bin /Users/administrator/opt/anaconda3/bin /Library/Frameworks/Python.framework/Versions/3.9/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin /Applications/VMware Fusion.app/Contents/Public /Applications/Server.app/Contents/ServerRoot/usr/bin /Applications/Server.app/Contents/ServerRoot/usr/sbin /Library/Apple/usr/bin /Users/administrator/.cargo/bin     

可以看到/usr/local/bin排在/usr/bin之前。

而我手动安装 Python 3.9.1 后,执行 which python3命令可以看到,python3命令执行的路径则在/usr/local/bin目录下:[2]

       /usr/local/bin/python3     

因此系统只会加载 /usr/local/bin下的 python3。

针对此,我们可以再验证一下:执行

       type -a python3     

来查看依据环境变量PATH下能查找到python3命令的所有执行文件的路径。

比方说在我的 Mac 上的是

       python3 is /usr/local/bin/python3 python3 is /Library/Frameworks/Python.framework/Versions/3.9/bin/python3 python3 is /usr/local/bin/python3 python3 is /usr/bin/python3     

只有排在最前的会首先加载,也就是/usr/local/bin下的python3

苹果的 macOS 开发工程师们明知道大多数用 Python 的用户都会将解释器的目录设置在/usr/local/bin目录下,为何在/usr/bin塞入一个单独的二进制执行文件,而不是链接?

我个人最初觉得,这样设计是为了迎合某些 Linux 用户的编程习惯,因为这些人编写 .py 的脚本的时候,知道 Shell 解释器和一些工具的必需执行文件基本上要放在/usr/bin目录下,会习惯性调用 Linux 内部的 Python,放到 macOS 上也一样。

但这个猜想似乎无法解释的通。后来我在不经意间有了新的发现:谜底竟然藏在xcode-select命令的帮助文件里。[3]

很多使用 Homebrew 的朋友,在首次安装 CLDT 的时候,都用到xcode-select这个命令:

       xcode-select --install     

xcode-select这个命令的主要作用,其实是为了方便开发者在安装了多个版本的 Xcode 下(尤其是安装有 Beta 版本的 Xcode,不在默认安装位置/Applications的时候)切换不同的开发者目录,从而可以用不同版本的 CLDT 通过脚本和 makefile 进行有针对性的编译。

由此设计的/usr/bin/python3这个可执行文件,就是从已经激活的开发者目录里查找并运行相匹配的 Python 版本。

相比 Windows 和某些 GNU/Linux 发行版找不到命令时简单粗暴的“直接报错”,这个让众多用户无法察觉到的设计,才是 macOS 的巧妙所在。

至此,这个问题才算真正解决了。

说真话,整个发现的过程虽然花了我很长的时间,但还是很值得回味的。


针对题主的提问,希望再啰嗦两点——

第一点是 macOS 内置的 Python 2 的消失。

Python 2 的最后一个版本是 2.7.16,已经于 2020 年的头一天就被官方停止支持了,但首次不支持 Python 2 的 macOS 版本是 Monterey 12.3 (21E230)。

对于该版本之前的 macOS,因为 Python 2 依然存在,仍可以用python关键字来调用它。

第一次使用该命令时会显示一个警告:

WARNING: Python 2.7 is not recommended. This version is included in macOS for compatibility with legacy software. Future versions of macOS will not include Python 2.7. Instead, it is recommended that you transition to using 'python3' from within Terminal.
(警告:不推荐使用 Python 2.7。此版本包含在 macOS 中以与旧版软件兼容。未来的 macOS 版本将不再包含 Python 2.7。相反,建议您从终端过渡到使用“python3”。)

以及当安装了旧版的 pip package 时,你会看到如下的信息:

DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.
(声明:Python 2.7 将于 2020 年 1 月 1 日到期,请升级您的 Python,因为自此日起将不再维护 Python 2.7。pip 的未来版本将会放弃对 Python 2.7 的支持。)

这说明从 2020 年 1 月 1 日到 2022 年 3 月 16 日 Monterey 12.3 发布的这段时间内,macOS 内置 Python 2 的目的是为了让开发者进行老旧软件的过渡。

但自从 macOS Monterey 12.3 后,Python 2 已从系统中消失,因此只能通过python3命令来调用 Python 3,原有的关键字python不再可用。

如果想经常使用python关键字来调用 Python 3,请首先用 vim 或 nano 编辑~/.zshenv文件(若使用的 Shell 为 Bash 则编辑~/.bash_profile文件);

然后在其中加入如下的一行:

       alias python='python3'     

保存后再执行source ~/.zshenv( 若为 Bash 则执行source ~/.bash_profile) ,重启终端即可生效。

另外需要说明的一点是,macOS 有一个安全机制,即系统完整性保护(System Integrity Protection,SIP),用来保护 macOS 的系统文件不受篡改,当然这个保护可以关闭,但会一定程度上降低 macOS 的安全性。即使关闭了 SIP,/usr/bin目录下的文件仍然不能删除,哪怕 root 用户也不行,因此题主也不可能删得了这个二进制的文件python3

(这个细节也体现了 macOS 系统的健壮性)

✄- - - - - - - - - - - - - - - - -

退一步想,假如/usr/bin下的文件像 Linux 一样可以通过 root 权限删除,那么在运行程序的时候,会导致无法预料的错误,甚至是系统的严重破坏。

Linux 上的sudo rm -rf /*就是一个很惨痛的例子,不光所有的用户文件都会被删除,而且内核依赖的文件也因删除而彻底无法启动系统。

✄- - - - - - - - - - - - - - - - -

然而,对于题主来说,为了去掉这个多余的 Python 3.8.2,最佳的解决方法就是卸载命令行开发者工具,这个方法就在前面说过了。

当然这个问题的解决方案不止一种,比方说可以修改PATH环境变量,或用 Anaconda。

如果你是第一次接触 Anaconda 的话,可以把 Anaconda 的 environment 理解为一个盛装 Python 的容器,而且 Python 的版本可以不同,pip package 则可以单独安装。

不同的是,执行命令

       which python     

时,base 环境下,返回的结果不是系统 Python 2 的解释器目录,而是下面的这个:

       ~/opt/anaconda3/bin/python     

其他创建的环境下则是:

       ~/opt/anaconda3/envs/[自定义环境名]/bin/python     

其中“~”代表你自己的用户文件夹。

python3命令则不受影响。

之前做了一些数据挖掘相关的东西,为了激活不同的环境,我会用 iTerm2 创建不同的配置文件,配合 Anaconda 使用。但比较郁闷的是 Tensorflow 死活配置不好,这一点非常想吐……

最后放一张很有意思的图。

不说了,我先笑一会儿……

参考

  1. ^ 更进一步,为了真实探究这个二进制可执行文件其中的工作原理,就需要借助反汇编了,不过我这里我的能力有限,但从反汇编的内容中看到了四个关键字符串,其中有两个分别是“llvm-gcc”和“clang”,目测与编译器有关。如有擅长逆向工程的高手,可给我补充。
  2. ^ 这是一个替身,它指向的原身为:/Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9。链接文件与原文件其实起同等的作用的。
  3. ^ 可以通过使用“man xcode-select”来查看 xcode-select 命令的帮助文件。



  

相关话题

  你写过哪些真正生产可用的 Python 装饰器? 
  学python在老师全用mac的情况下有必要换成mac吗? 
  Python中如果判断一个文件是不是jpg的图片? 
  macOS 内建的「黑体-繁/简」系列(常州华文)有什么缺点? 
  在 PC 领域,Windows 能战胜 macOS 的最大原因是否在于游戏领域的优势? 
  python学习一定用pycharm吗? 
  作为一个 Emacs、终端、浏览器的重度用户,在考虑价格因素的情况下,你是否认为 Mac OS 比 Linux 发行版更值得使用? 
  为什么在知乎macOS用户只要黑半句Windows就招来围攻,而对待Linux却只有技术层面的反驳? 
  微软 Excel 原生适配苹果 M1 系列 Mac,这将为用户带来哪些好的体验? 
  Python中如果判断一个文件是不是jpg的图片? 

前一个讨论
在酒店隔离期间,该如何保持健康?
下一个讨论
2021 年了,机器/深度学习还有哪些坑比较好挖?





© 2024-11-22 - tinynew.org. All Rights Reserved.
© 2024-11-22 - tinynew.org. 保留所有权利