我是Python新手。致力于扩展旧模块。到目前为止,它有一个返回 str
的函数。 (阻塞 shell 命令的输出)。现在我需要该函数也能够返回一个对象,以便以后可以对其进行操作(检查非阻塞 shell 命令的输出)。因此,该函数现在返回我的类的一个实例,该实例是我从 str
派生的子类。为了向后兼容。然而,问题是,当这样的对象传递给 os.path.isdir 时,它总是返回 False,即使该字符串是有效路径
import os
class ShellWrap(str):
def __new__(cls, dummy_str_value, process_handle):
return str.__new__(cls,"")
def __init__(self, dummy_str_value, process_handle):
self._ph = process_handle
self._output_str = ""
def wait_for_output(self):
# for simplicity just do
self._output_str = "/Users"
def __str__(self):
return str(self._output_str)
def __repr__(self):
return str(self._output_str)
def __eq__(self,other):
if (isinstance(other, str)):
return other == str(self._output_str)
else:
return super().__eq__(self,other)
>>> obj = ShellWrap("",None)
>>> obj.wait_for_output()
>>> print(type(obj))
... <class '__main__.ShellWrap'>
>>> print (ShellWrap.__mro__)
... <class '__main__.ShellWrap'>
(<class '__main__.ShellWrap'>, <class 'str'>, <class 'object'>)
>>> print(type(obj._output_str))
... <class 'str'>
>>> print(obj)
... /Users
>>> print(obj._output_str)
... /Users
>>> obj == "/Users"
... True
令我困惑的是:
>>> print(os.path.isdir(obj))
... False **<<-- This one puzzles me**
print(os.path.isdir("/Users"))
... True
我尝试添加 PathLike 继承并实现另一个 dunder,但没有成功:
class ShellWrap(str,PathLike):
....
def __fspath__(self):
return self._output_str
似乎还有一个dunder我未能实现。但哪个?
但是,我确实在调试器中看到了一些奇怪的东西。当我戴上 watch obj
- 它说它是一个类 str
但调试器显示的值不带引号(与其他“纯”字符串不同)。
手动向调试器中的字符串添加引号 - 使其可以工作,但我猜编辑字符串可能会创建一个新对象,这次是纯 str。
我错过了什么?
编辑:在意识到(参见已接受的答案)我尝试做的事情是不可能的之后,我决定挑战必须子类化 str
的决定。 。 所以现在我的类没有继承任何东西。它只是实现 __str__, __repr__ and __fspath__
这似乎就足够了!显然只要str
继承就在那里——它获得优先权,dunders不会被调用,它会欺骗一些库去获取str值的底层C存储
最佳答案
考虑os.path.isdir
的来源。当您传入 obj 时,您可能会触发该值错误,因为您要评估的字符串是字符串子类的属性,而不是子类应该表示的字符串。您必须在 str
的源代码中多花点功夫才能找到要覆盖的正确成员。
编辑:解决此问题的一种可能方法是动态使用 __init__
。也就是说,在__new__
中完成渲染路径字符串所需的一切,并在该方法中返回类之前,将output_str
设置为一个属性。现在,在您的 __init__
中,以 self.output_str
作为唯一参数调用 super().__init__
。
关于Python str 子类表示一个不是真正字符串的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61860526/