关于python:String的子类,当被调用时,将参数绑定到__init__的两个参数?

Sub-class of String, when called, binds argument to both parameters of __init__?

在Python2.7中,当使用一个字符串作为其参数,似乎将该字符串绑定到关于init("self"和"grasshopper")的论点。

方法可以定义为使用看似相同的自我和自我的结果。

我注意到,如果init被定义为接受三个参数——例如,"自我"、"蚱蜢"和"甲虫"——上课时间使用两个字符串参数(例如crazystring("spam"、"eggs"))运行会引发错误:

1
TypeError: str() takes at most 1 argument (2 given)

这就意味着"str"不仅仅是被继承的。通过类crazystring,但作为函数执行。

我不明白发生了什么,因此我感到不确定我是否应该写自己操作的方法或是自己。蚱蜢。或者是自我和自我,实际上是蝗虫。一样吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CrazyString(str):

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

    def backwards1(self):
        return self.grasshopper[::-1]

    def backwards2(self):
        return self[::-1]

if __name__ =="__main__":
    cs = CrazyString('spam')
    print cs
    print cs.grasshopper
    print cs.backwards1()
    print cs.backwards2()

当运行("python crazy.py")时,我得到以下输出:

1
2
3
4
spam
spam
maps
maps


这个答案有两部分:解释在哪里进行str初始化(因为您不调用str.__init__),解释"str在哪里存储字符串"。

首先,由于str是在C中实现的不可变类型,因此str.__init__实际上不涉及初始化字符串。还有另一个方法,__new__,python在__init__初始化之前调用它来创建一个类型的实例,对于像str这样的不可变类型,__new__创建预初始化的对象。(毕竟,如果__init__初始化了字符串,这将是一个突变。)

其次,self似乎是一个字符串,因为它应该是一个字符串。您从str继承,所以类的实例是str的实例;它们是字符串!你可以把它们像字符串一样切掉,把它们像字符串一样切掉,然后再把它们切掉,因为它们继承了str的所有东西。你不需要像人们有时期望的那样,用self.str之类的东西"触及底层字符串"。


因此,字符串"spam"在作为第二个参数传递给__init__之前,被__new__方法转换为"str"类型的对象。

如果一个__init__有任意数量的参数,但只有两个参数,那么调用CrazyString('spam')将失败,并以类型错误退出。这工作:

1
2
3
4
5
6
7
8
class CrazyString(str):
    def backwards(self):
        return self[::-1]

if __name__ =="__main__":
    cs = CrazyString('spam')
    print cs
    print cs.backwards()


在您的例子中,您遇到了使您陷入困境的__new__功能。

你应该做(未经测试的!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class CrazyString(str):

    def __new__(cls, grasshopper, beetle):
        return cls(grasshopper) # not sure if that works, maybe we have to use super() in any way...

    def __init__(self, grasshopper, beetle):
        self.grasshopper = grasshopper
        self.beetle = grasshopper

    def backwards1(self):
        return self.grasshopper[::-1]

    def backwards2(self):
        return self[::-1]

    def backwards3(self):
        return self.beetle[::-1]

if __name__ =="__main__":
    cs = CrazyString('spam')
    print cs
    print cs.grasshopper
    print cs.backwards1()
    print cs.backwards2()
    print cs.backwards3()