Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I can't use join for a list of objects that implement __str__?

I am studying duck typing in Python,I know that if you implement some special methods for a class, you can happily use the built-in class methods

for example:

class A:
    def __init__(self,l):
        self._l = l
    def __iter__(self):
        return iter(self._l)

If I do this ,I can use for...in..,zip, and some other methods that is built in and also can do some other stuffs, like implement __setitem__() ,so I can use random.choice,random.shuffle,and I feel python is so cool,but then I find this problem,I want to use join to print some objects that I implemented their __str__ methods,but it won't work

I find that this is because when we use join,we write it like ';'.join(l),so the duck typing trick won't work for it,because it use str's methods rather than the objects will be joined

But why?since many build in methods designed to friendly to duck typing,why not 'join'?

@SethMMorton is point my doubts,thank you I know I can use ';'.join([str(i) for i in l]) to solve my problem,but I don't know why python don't do it itself?

like image 931
Tarjintor Avatar asked Mar 09 '23 08:03

Tarjintor


2 Answers

Answering the "why": Everything in Python is convertible to str, as even without __str__, the repr of the object is used when a str form is requested. Python may be flexible, but what you're describing is weak typing (which Python doesn't do in general), not duck typing. The presence of __str__ means you can coerce to a string, but it doesn't mean "is a string".

Allowing arbitrary iterables to be iterated with for loops, zip, etc. isn't weak typing, because it's a common interface with no ambiguity; iterables iterate the same way, even if they might produce different types.

Actual weak typing is dangerous, because it can allow errors to pass silently. It's particularly noticeable in Python 3. If automatic coercion to str was allowed, and you did:

iterable_of_bytes_objects = b'123', b'456'

','.join(iterable_of_bytes_objects)

You'd silently produce "b'123',b'456'", when odds are, you just forgot the leading b on the join string, and meant:

b','.join(iterable_of_bytes_objects)

Or maybe you meant to produce a string but forgot to decode the bytes. Or maybe you wanted the repr of each object, or the str, or whatever. Python has no idea, and per the Zen of Python (import this):

In the face of ambiguity, refuse the temptation to guess.

as well as:

Explicit is better than implicit.

Coercing automatically hides errors and involves heuristic guesswork about what people "probably want". If you want to coerce, that's what ','.join(map(str, iterable)) is for, but it means you opted in to a specific form of coercion, and it's assumed you know what you're doing, which matches the other Zen requirements:

Errors should never pass silently.

Unless explicitly silenced.

like image 120
ShadowRanger Avatar answered Apr 01 '23 06:04

ShadowRanger


This isn't a problem with duck-typing. It's a problem with the items contained in your custom series class. You will get the same error if you try to join a numeric range(). Instead do this:

';'.join(str(i) for i in l)

This is explained clearly in the documentation for string.join(iterable): "Return a string which is the concatenation of the strings in the iterable iterable."

like image 34
Craig Avatar answered Apr 01 '23 07:04

Craig