Python str子类表示一个非实字符串的值

Python str子类表示一个非实字符串的值,python,string,class,inheritance,subclass,Python,String,Class,Inheritance,Subclass,我是python的新手。正在扩展旧模块。到目前为止,它有一个返回str(阻塞shell命令的输出)的函数。现在,我需要该函数也能够返回一个对象,以便以后可以对其执行操作(检查非阻塞shell命令的输出)。因此,函数现在返回我的类的一个实例,为了向后兼容,我从str子类化了它。然而,问题是,当这样一个对象被传递到os.path.isdir时,它总是返回False,即使字符串是有效的路径 import os class ShellWrap(str): def __new__(cls,

我是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
似乎还有一个dunder我没能实现。但是哪个呢

然而,我确实在调试器中看到了一些奇怪的东西。当我把手表放在
obj
上时,它说它属于类
str
,但调试器显示的值没有引号(与其他“纯”str不同)。 在调试器中手动向字符串添加引号可以使其工作,但我想编辑字符串可能会创建一个新对象,这次是纯str

我错过了什么


Edit:在意识到(参见接受的答案)我试图做的是不可能的之后,我决定挑战必须将
str子类化的决定。所以现在我的类没有继承任何东西。它只实现了
\uuuuu str\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!显然,只要str继承存在,它就会获得优先权,dunders就不会被调用,并且它会欺骗一些库去获取str值的底层C存储

使用字符串的C代码访问由
str
类管理的实际字符串数据,而不是您正在编写的方法。它不关心您是否将另一个字符串作为属性附加到对象,或者您是否覆盖了一组方法。它比
您的对象更接近
str.\uuuuuuwhater.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(您的对象)
,尽管它

在本例中,相关的C代码是
os.stat
调用
os.path.isdir
委托给的,但是几乎任何使用字符串的东西都将使用用C编写的东西,在某个点直接访问
str
数据


您希望对象的数据是可变的-
wait\u\u输出是可变的-
但是您不能对从
str
继承的对象部分进行突变,这才是重要的数据。

您试图做的是不可能的

使用字符串的C代码访问由
str
类管理的实际字符串数据,而不是您正在编写的方法。它不关心您是否将另一个字符串作为属性附加到对象,或者您是否覆盖了一组方法。它比
您的对象更接近
str.\uuuuuuwhater.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(您的对象)
,尽管它

在本例中,相关的C代码是
os.stat
调用
os.path.isdir
委托给的,但是几乎任何使用字符串的东西都将使用用C编写的东西,在某个点直接访问
str
数据

您希望对象的数据是可变的——
wait___\u输出是可变的,但您不能对从
str
继承的对象部分进行突变,这才是重要的数据。

考虑
os.path.isdir
的源代码。当您传入
obj
时,可能会触发该值错误,因为您要计算的字符串是字符串子类的属性,而不是该子类应该表示的字符串。您必须在
str
的源代码中多做一些工作,以找到要覆盖的正确成员

编辑:一种可能的解决方法是动态使用
\uuuu init\uuu
。也就是说,获取在
\uuuuu new\uuuuu
中呈现路径字符串所需的所有操作,并在该方法中返回类之前,将
output\u str
设置为属性。现在,在您的
\uuuu init\uuuu
中,调用
super()。\uuuu init\uuuuu
,将
self.output\u str
作为唯一参数。

考虑
os.path.isdir
的源代码。当您传入
obj
时,可能会触发该值错误,因为您要计算的字符串是字符串子类的属性,而不是该子类应该表示的字符串。您必须在
str
的源代码中多做一些工作,以找到要覆盖的正确成员


编辑:一种可能的解决方法是动态使用
\uuuu init\uuu
。也就是说,获取在
\uuuuu new\uuuuu
中呈现路径字符串所需的所有操作,并在该方法中返回类之前,将
output\u str
设置为属性。现在,在您的
\uuuu init\uuuu
中,调用
super()。\uuuu init\uuuu
,将
self.output\u str
作为唯一参数。

尝试
os.path.isdir(str(obj))
,看看它是否正确works@Luka谢谢我知道它有效,但我不能。我不允许在课外更改代码。我需要构建一个与str完全兼容的类…如果您使用PathLike,在
\uuuufspath\uuuuuuuu
中,您可以
返回str(self.\u output\u str)
,否?自从
>>打印(type(obj.\u output\u str)),它不会改变任何东西
尝试
os.path.isdir(str(obj))
,看看它是否works@Luka谢谢我知道它有效,但我不能。我不允许在课外更改代码。我需要构建一个与str完全兼容的类…如果您使用PathLike,在
\uuuufspath\uuuuuuuu
中,您可以
返回str(self.\u output\u str)
,否?自从
>>打印(type(obj.\u output\u str)),它不会改变任何东西 >>> print(os.path.isdir(obj))
... False **<<-- This one puzzles me**
print(os.path.isdir("/Users"))
... True
class ShellWrap(str,PathLike):
   ....
   def __fspath__(self):
      return self._output_str