【问题标题】:Error "decoding str is not supported" Custom str Class Python错误“不支持解码 str”自定义 str 类 Python
【发布时间】:2021-11-07 20:39:15
【问题描述】:

我正在构建一个可以像开关一样工作的类;

这样的自定义类本来是一个带有内部列表的字符串,而该字符串标识了开关的当前位置(“on”),并且该列表涵盖了所有可能的位置([“on”,“off”, “中途”,“有点死,但仍在继续”,...];

在初始化此类的实例时,我会接受不定数量的可能位置;

因此代码

class switch(str):
    pos=[]
    def __init__(self,*positions):
        self.pos=[str(el) for el in positions]
        self=self.pos[0]
    def swap(self):
        try:
            self=self.pos[self.pos.index(self)+1]
        except IndexError:
            self=self.pos[0]

和电话

mood=switch("upbeat","depressed","horny")

这完全行不通。错误是这样的:

TypeError: decoding str is not supported

当然有更好的方法来制作这个 Switch 类(这只是一个快速插入的草稿),最终,我已经做到了;我仍然不明白这个错误的起源——通过谷歌搜索没有用——并且对此感到愤怒,我最终决定在 Stack 上注册并发布它。 大家怎么看呢?

谷歌搜索,似乎在尝试连接"str1","str2" 之类的字符串而不是"str1"+"str2" 之类的字符串时错误会关闭;那么我认为对 *positions 的事情保持怀疑是安全的,它不会将字符串解包为单独的变量,而是试图猜测我希望它们作为一个整体加入,但由于我没有使用 + 连接器而失败了.

这就是我想到的。

否则,如果我错了,我只会在使用格式和内容时看到错误弹出。在这种情况下,这很遥远。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请阅读How to Ask 和stackoverflow.com/help/minimal-reproducible-example 和meta.stackoverflow.com/questions/359146/…。我们需要看到足够多的代码,以便我们可以复制和粘贴它并自己查看问题;我们需要看到一个完整的异常回溯(复制和粘贴,从Traceback (most recent call last): 行开始,格式类似于代码)。
  • 顺便说一句,您班级中的pos=[] 不为实例“声明”pos 属性;它创建了一个单独的属性,该属性属于类本身,并且被实例的属性隐藏。此行无需声明任何内容,也没有任何目的。
  • 也就是说:从内置类型继承不会像您期望的那样工作,并且分配给self 不会修改对象(与b = [1]; a = b; a = [2] 相同的原因不会导致 b 变为 [2])。
  • 你不想创建一个字符串类型的类,因为你不能用你的类有意义地做所有字符串可以做的事情。您想创建一个封装字符串值的类,并带有一个获取该值的接口。一种可能性,特别适用于“多种恒定可能性之一”,是Enum 类型。
  • 谢谢!有几件事我不清楚。最后,我根据这些建议和马克的回答想出的最接近的解决方案是一个不继承 str 的类,具有一个字符串作为内部值和自定义 repr 和 eq 函数,以便它完全按照字符串子类的含义工作。不太明白你在第三条评论中写的原因,虽然

标签: python string concatenation typeerror unpack


【解决方案1】:

你可以继承str。但是,如果您传递的参数不止一个,则需要在 __new__() 处截获该参数,以便 python 在创建对象时不会尝试解释其他参数。

请注意,这只是为了演示 - 它不适用于您的问题

class switch(str):
    def __new__(cls, *content):
        return str.__new__(cls, content[0])

    def __init__(self, *positions):
        self.pos = [str(el) for el in positions]
    
mood=switch("upbeat", "depressed", "horny")

# prints as expected and has string methods
print(mood, mood.upper())
# upbeat UPBEAT

# has your instance attribute
print(mood.pos)
['upbeat', 'depressed', 'horny']

问题是字符串是不可变的。因此,如果想法是就地更改字符串的值,那么这从一开始就注定了。您可以为此使用collections.UserString。这就像一个字符串,但为您提供了一个 data 属性来存储实际值。有了这个,你的想法可能会奏效:

from collections import UserString

class Switch(UserString):
    def __init__(self, *positions):
        self.pos = [str(el) for el in positions]
        # store the actual string in .data
        self.data = self.pos[0]
        
    def swap(self):
        try:
            self.data = self.pos[self.pos.index(self)+1]
        except IndexError:
            self.data = self.pos[0]

    
mood=Switch("upbeat", "depressed", "horny")

# still acts like a string
print(mood, mood.upper())
# upbeat UPBEAT

# but now you can swap 
mood.swap()
print(mood, mood.upper())
# depressed DEPRESSED

【讨论】:

  • 谢谢!有问题。最后,我通过使用一个不继承 Str 或 UserString 的类来保持简单,它有一个像 data 这样的内部变量,并使其作为字符串工作(用于打印和比较,print(mood) 和mood=="happy") 我刚刚修改了它的 eq 和 repr 函数。就像它作为 str 子类一样工作!
  • 嗯,我忘记了UserString(以及UserList和UserDict)仍然存在。当无法从内置函数继承时,它们不是最初的解决方法吗?
  • 是的@KarlKnechtel,它们大部分都被贬值了(文档说“部分被取代”),因为您可以直接对这些类型进行子类化。但是,当您在上述特殊情况下需要包装器时,它们仍然很有用,(我不认为)可以通过直接子类来解决。
【解决方案2】:

我认为 Python 认为您正在使用 str() (https://docs.python.org/3/library/stdtypes.html#str) 的第二个构造函数。

例如switch(b"upbeat", "utf-8") 会起作用。

【讨论】:

  • 但是 OP 想要传入三个参数:switch("upbeat","depressed","horny")。这将如何在您的解决方案中发挥作用?
  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。
猜你喜欢
  • 2020-02-03
  • 1970-01-01
  • 2021-06-18
  • 2017-05-27
  • 1970-01-01
  • 2017-10-13
  • 2013-10-12
  • 2019-05-09
  • 1970-01-01
相关资源
最近更新 更多