Olá Akhenaton, tudo bem com você?
Isso acontece devido ao tipo retornado pela função print() e pela função len() e os tipos de retorno esperado pelos dunders methods __str__ e __len__.
Primeiramente analisaremos o retorno da função print(), para isso criaremos uma função que tem como objetivo fazer o retorno da função print(), e usando a função type() verificamos o tipo de retorno.
def foo():
return print('bar')
print(type(foo()))
Resultado
bar
<class 'NoneType'>
Note que o retorno da função print() é do tipo NoneType. Para que o dunder method __str__ funcione corretamente ele deve retornar um valor do tipo string (str) o que não acontece quando retornamos a função print(), como a seguir, return print(self.url).
Agora analisaremos o retorno da função len(), criando uma função para analisar esse retorno de forma semelhante ao que fizemos anteriormente.
def foo():
return len('bar')
print(type(foo()))
Resultado
<class 'int'>
O retorno da função len() é do tipo int e para que o dunder method __len__ funcione corretamente ele deve retornar um valor do tipo int, assim quando usado o retorno como return len(self.url) estamos retornando o comprimento de uma string, um valor do tipo int.
Em resumo temos:
__str__: - Deve retornar o tipo
str, para isso podemos informar apenas o atributo self.url que contém uma representação da url como uma str.
__len__:- Deve retornar o tipo
int, para isso será necessário encontrarmo primeiramente o comprimento da url e retornar esse comprimento, para isso usamos len(self.url)
Fico à disposição em caso de dúvidas.
Abraços e bons estudos.
Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓. Bons Estudos!