这是不合逻辑的 python 行为吗?

Is this inconsequent python behaviour?

所以,我在查看 pathlib 源代码时注意到一些 os lib 函数被合并到 pathlib classes 中。我必须承认,我花了一点时间才理解它是如何工作的。

import os

class Foo:
    listdir = os.listdir
    join = os.path.join
    walk = os.walk

    def __init__(self, name):
        self.name = name

    def __fspath__(self):
        return self.name

curr = Foo('.')
pipo = Foo('pipo')

此 class 定义将 os 库的 listdir、join 和 walk 函数添加为 Foo class 上的方法。 Foo class 被识别为 PathLike 对象,因为它也有 __fspath__ 方法。

当调用 curr.join('bar') 时,它会将 curr 的名称“.”与 'bar' 连接起来。下面的代码显示了这种确切的行为,结果是我所期望的。

$ tree
.
├── pipo
│   └── clown
└── test.py

1 directory, 2 files
$

>>> curr.join("baz") 
./baz
>>>
>>> pipo.join("baz")
pipo/baz
>>>
>>> [x for x in curr.walk()]
[('.', ['pipo'], ['test.py']), ('./pipo', [], ['clown'])]
>>>
>>> [x for x in pipo.walk()]
[('pipo', [], ['clown'])]
>>>

然后我尝试了 listdir 函数...但它失败了。 listdir 函数显示不同的行为,我很困惑为什么?

>>>
>>> os.listdir()
['pipo', 'test.py']
>>>
>>> curr.listdir()
['pipo', 'test.py']
>>>
>>> os.listdir("pipo")
['clown']
>>>
>>> pipo.listdir()
['pipo', 'test.py']
>>> 

pipo 上的 listdir 方法显示与 curr 上的 listdir 相同的输出?

在我看来 joinwalk 接受自我引用但不知何故 listdir 不接受。为什么会这样?

function class 实现了 descriptor protocol,允许 os.path.join 作为实例方法。 os.listdir 不是 function 的实例;它是 builtin_function_or_method 的一个实例,它没有实现描述符协议。

curr.join(...) 等同于 Foo.join.__get__(curr, Foo)(...)curr.listdir() 等同于 Foo.listdir()curr.listdir 不存在,而 Foo.listdir 只是调用 listdir,而不是不存在的 listdir.__get__注意传递 curr 作为隐式第一个参数。