
On Thu, 22 Dec 2022 at 04:14, Christopher Barker <pythonchb@gmail.com> wrote:
On Wed, Dec 21, 2022 at 8:54 AM Chris Angelico <rosuav@gmail.com> wrote:
I think both of those will call self.__str__, which creates a recursion -- that's what I'm trying to avoid.
I'm sure there are ways to optimize this -- but only worth doing if it's worth doing at all :-)
Second one doesn't seem to.
class Str(str): ... def __str__(self): ... print("str!") ... return "spam" ... def __repr__(self): ... print("repr!") ... return "SPAM" ... s = Str("ham") f"{s}" str! 'spam' "".join((s,)) 'ham'
hmm -- interesting trick -- I had jumped to that conclusion -- I wonder what it IS using under the hood?
From the look of things, PyUnicode_Join (the internal function that handles str.join()) uses a lot of "reaching into the data structure" operations for efficiency. It uses PyUnicode_Check (aka "isinstance(x, str)") rather than PyUnicode_CheckExact (aka "type(x) is str") and then proceeds to cast the pointer and directly inspect its members. As such, I don't think UserString can ever truly be a str, and it'll never work with str.join(). The best you'd ever get would be explicitly mapping str over everything first:
s2 = UserString("eggs") "-".join(str(s) for s in [s, s2]) str! 'spam-eggs'
And we don't want that to be the default, since we're not writing JavaScript code here. ChrisA