当前位置: 首页 > 编程笔记 >

Python中的pathlib.Path为什么不继承str详解

严宏朗
2023-03-14
本文向大家介绍Python中的pathlib.Path为什么不继承str详解,包括了Python中的pathlib.Path为什么不继承str详解的使用技巧和注意事项,需要的朋友参考一下

起步

既然所有路径都可以表示为字符串,为什么 pathlib.Path 不继承 str ? 这个想法的提出在 https://mail.python.org/pipermail//python-ideas/2016-April/039475.html 可以看到,其中,还提出了将 p'/some/path/to/a/file' 返回 path.Path 实例的想法。

路径都是字符串吗?

从面向对象的继承的思想来看,如果 Path 继承自 str ,那么所有的路径都应该是字符串。但所有的路径都是字符串吗?答案是不。在 POSIX 的接口中,允许二进制字符串作为路径。也就是说路径还有二进制路径的形式存在。所以并不是所有路径都是字符串,尽管所有路径确实都能用字符串表示。

文件系统路径协议
基于上述原因,Python 提出了文件系统路径协议的提案 PEP-519 ,该协议提供str 或 bytes 来表示的文件系统路径。这个协议也就诞生了处理路径的 pathlib 模块 PEP-428,该模块遵守了路径协议并将路径视为对象。

协议的实现一般也是通过鸭子协议来满足,这点出发 Path 也没必要继承 str 。

不是字符串的Path使用上有什么影响

在 Python3.5 及以下将不能用 Path 作为open的参数:

import pathlib
p = pathlib.Path('a.txt')
content = open(p, 'r').read() # 换成 open(str(p), 'r') 可以运行

将会报错:

TypeError: invalid file: PosixPath('a.txt')

但这点在 Python3.6 得到的改善: https://docs.python.org/3/whatsnew/3.6.html#pep-519-adding-a-file-system-path-protocol

内置 open() 函数已更新为接受 os.PathLike 对象,os 和 os.path 模块中的所有相关函数以及大多数其他函数和类标准库都使用了文件路径系统协议。

>>> import pathlib
>>> with open(pathlib.Path("README")) as f:
...   contents = f.read()
...
>>> import os.path
>>> os.path.splitext(pathlib.Path("some_file.txt"))
('some_file', '.txt')
>>> os.path.join("/a/b", pathlib.Path("c"))
'/a/b/c'
>>> import os
>>> os.fspath(pathlib.Path("some_file.txt"))
'some_file.txt'

对于低版本的可以使用兼容性更好的:

with p.open('r') as f:
  content = f.read()

如果路径继承str会怎样

或者说如果我自己创建个路径类继承自 str ,这当然可以,也没人组织你,但我想从设计上阐述下这个做法的弊端。

一方面,这个做法会让路径隐式地视为字符串。不满足Python之禅的 显式胜于隐式 的理念。

另一方面也是比较重要的一点,这个做法淡化了 str 和 bytes 的界限,想想Python 2中二进制文本数据和文本数据的隐式兼容性导致了一个令人头疼的问题,将在这里又重新埋下隐患。这是倒退式的做法。

总结

对于路径类为什么不继承字符串,本文从路径的形式,路径协议,以及API设计解释了。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对小牛知识库的支持。

扩展阅读

  • Python-ideas: Making pathlib paths inherit from str
  • PEP 519 -- Adding a file system path protocol
  • PEP 428 -- The pathlib module -- object-oriented filesystem paths
  • What's New In Python 3.6 pep-519-adding-a-file-system-path-protocol
 类似资料:
  • 下面的代码引发: 线程“main”java.lang.ClassCastException中的异常:不能将类子级转换为类java.util.List(子级位于加载器“app”的未命名模块中;java.util.List位于加载器“bootstrap”的模块java.base中) 我真的不知道它为什么会这样做。我想我写的代码是正确的。 请帮助我理解这一点,以及如何解决这个问题。

  • 问题内容: 我有以下课程: 有没有搞错 ? 最糟糕的是我无法尝试super(),因为Exception是基于旧类的… 编辑:而且,是的,我试图切换继承/初始化的顺序。 EDIT2:我在Ubuntu8.10上使用CPython 2.4。您最近才知道这种信息很有用;-)。无论如何,这个小谜语已经让我的三个同事闭上了嘴。你会成为我今天最好的朋友… 问题答案: 两者和都在C中实现。 我认为您可以按照以下方

  • 问题内容: 为什么以下代码不起作用(Python 2.5.2)? 我想创建一个类似的类,但具有不同的功能。显然我的函数永远不会被调用。而是调用原始文件并失败,因为它需要3个参数,而我传入了一个。 这里发生了什么?这是一个线索吗? 谢谢! 问题答案: 关于其他几个答案,这与用C本身实现的日期无关。该方法不做任何事情,因为它们是 不可变的 对象,因此构造函数()应该完成所有工作。您会看到相同的行为将i

  • 问题内容: 例: Python是(非常)面向对象的,我不理解为什么对象不继承“ len”功能。另外,我一直在尝试错误的解决方案,因为它对我来说似乎是合乎逻辑的 问题答案: Guido的解释在这里: 首先,出于HCI的原因,我选择len(x)而不是x.len()(def len ()来得晚)。实际上,HCI有两个相互交织的原因: (a)对于某些运算,前缀表示法比后缀读得更好-前缀(和infix!)运

  • 问题内容: 我是Java编程语言的初学者,最近我研究了 构造函数 不能在Java中继承,有人可以解释 为什么 吗? 问题答案: 简而言之,构造函数不能被继承,因为在子类中它具有​​不同的名称(子类的名称)。 您只能执行以下操作: 相反,方法是使用“相同名称”继承的,可以使用。 理由如下:继承构造函数没有多大意义,因为类A的构造函数意味着创建类型A的对象,而类B的构造函数意味着创建类B的对象。 不过

  • C语言面向对象编程(二):继承详解 在 C语言面向对象编程(一) 里说到继承,这里再详细说一下。 C++ 中的继承,从派生类与基类的关系来看(出于对比 C 与 C++,只说公有继承): 派生类内部可以直接使用基类的 public 、protected 成员(包括变量和函数) 使用派生类的对象,可以像访问派生类自己的成员一样访问基类的成员 对于被派生类覆盖的基类的非虚函数,在派生类中可以通过基类名和