# Python \`\_\_str\_\_()\` Equivalent

**URL:** <https://es.discourse.group/t/python-str-equivalent/883>\
**Category:** 💡 Ideas\
**Created:** [July 21, 2021, 3:47pm UTC](https://es.discourse.group/t/python-str-equivalent/883 "2021-07-21T15:47:30Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![ethanlal04](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ethanlal04/32/918_2.png) [@ethanlal04](https://es.discourse.group/u/ethanlal04)\
**Post date:** [July 21, 2021, 3:47pm UTC](https://es.discourse.group/t/python-str-equivalent/883/1 "2021-07-21T15:47:30Z")

</div>

In Python, we can represent the object returned by a class as a string.

```javascript
class Person:
  def __init__ (self, name):
    self.name = name

  def __str__ (self):
    return f"Hello! My name is {self.name}!"

```

What if we could do something similar in Javascript? This could be used by libraries to describe a class without affecting its methods and properties. It doesn't need to be ` __str__ `.

Let me know what you think. Thank you 😀.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 21, 2021, 3:50pm UTC](https://es.discourse.group/t/python-str-equivalent/883/2 "2021-07-21T15:50:54Z")

</div>

This is already possible in Javascript today, through the special `.toString()` function - and many libraries already use it.

For example:

```javascript
> { toString: () => 'Hello' } + ' World!'
'Hello World!'
> String(new URLSearchParams({ a: 1, b: 2 }))
'a=1&b=2'

```

---

<div class="post-metadata">

**Author:** ![ethanlal04](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ethanlal04/32/918_2.png) [@ethanlal04](https://es.discourse.group/u/ethanlal04)\
**Post date:** [July 21, 2021, 3:56pm UTC](https://es.discourse.group/t/python-str-equivalent/883/3 "2021-07-21T15:56:37Z")

</div>

Hi @theScottyJam,

Sorry, isn't your example limited to an object? How can I do the same with a class?

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 21, 2021, 3:58pm UTC](https://es.discourse.group/t/python-str-equivalent/883/4 "2021-07-21T15:58:18Z")

</div>

All instances of classes are just objects, so if it works with an object, it works with a class.

```javascript
class MyClass {
  toString() {
    return 'Hello'
  }
}

const instance = new MyClass()
console.log(instance + ' World!') // Hello World!

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 21, 2021, 4:00pm UTC](https://es.discourse.group/t/python-str-equivalent/883/5 "2021-07-21T16:00:26Z")

</div>

Are you looking for `.toString()`, or `[Symbol.toStringTag]`, or in node, `[util.inspect.custom]()`?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 21, 2021, 4:07pm UTC](https://es.discourse.group/t/python-str-equivalent/883/6 "2021-07-21T16:07:38Z")

</div>

a class is an object too. for the constructor, you can have `static toString() {}`, and for the instances, `toString() {}`.

---

<div class="post-metadata">

**Author:** ![lightmare](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/lightmare/32/843_2.png) [@lightmare](https://es.discourse.group/u/lightmare)\
**Post date:** [July 21, 2021, 4:29pm UTC](https://es.discourse.group/t/python-str-equivalent/883/7 "2021-07-21T16:29:40Z")

</div>

Nitpicking here: don't conflate ` __repr__ ` with ` __str__ `. ` __repr__ ` is supposed to return a string that is ideally valid Python code for constructing that object; if that's not possible, at least some pseudo-code form. ` __str__ ` on the other hand, is expected to be free-form text.

```javascript
class Person:
  def __init__ (self, name):
    self.name = name
  def __repr__ (self):
    return f"{self. __class__. __name__ }({self.name!r})"
  def __str__ (self):
    return f"Hello! My name is {self.name}!"

```

---

<div class="post-metadata">

**Author:** ![ethanlal04](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ethanlal04/32/918_2.png) [@ethanlal04](https://es.discourse.group/u/ethanlal04)\
**Post date:** [July 21, 2021, 4:31pm UTC](https://es.discourse.group/t/python-str-equivalent/883/8 "2021-07-21T16:31:24Z")

</div>

@lightmare Sure, I'll change that.

---

<div class="post-metadata">

**Author:** ![ethanlal04](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ethanlal04/32/918_2.png) [@ethanlal04](https://es.discourse.group/u/ethanlal04)\
**Post date:** [July 21, 2021, 4:33pm UTC](https://es.discourse.group/t/python-str-equivalent/883/9 "2021-07-21T16:33:59Z")

</div>

@ljharb Just `.toString()`. I didn't know you could use that as ` __str__ `.

---

<div class="post-metadata">

**Author:** ![ethanlal04](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ethanlal04/32/918_2.png) [@ethanlal04](https://es.discourse.group/u/ethanlal04)\
**Post date:** [July 21, 2021, 4:44pm UTC](https://es.discourse.group/t/python-str-equivalent/883/10 "2021-07-21T16:44:06Z")

</div>

@theScottyJam Your example works fine, but this code...

```javascript
class Person {
  constructor(name) {
    this.name = name;
  }

  toString() {
    return `Hello ${this.name}!`;
  }
}

```

...produces this...

```javascript
const person = new Person("Joe");
console.log(person); // Person { name: 'Joe' }
console.log(person + "Elephant"); // Hello Joe!Elephant

```

Why doesn't it give me `Hello Joe` when I log person. Is there anything wrong with my code?

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 21, 2021, 4:46pm UTC](https://es.discourse.group/t/python-str-equivalent/883/11 "2021-07-21T16:46:54Z")

</div>

`.toString()` is what gets automatically called when an object needs to be turned into a string. `console.log()` doesn't turn things into strings before logging them out (which is why browsers are able to give you an interactive view of objects when you log them out). You can manually do it like this `console.log(String(person))`.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [July 21, 2021, 6:07pm UTC](https://es.discourse.group/t/python-str-equivalent/883/12 "2021-07-21T18:07:25Z")

</div>

While `toString()` should get you what you want 99.9% of the time, going deeper, string conversion can get a little more complicated. There's also the `valueOf()` and `[Symbol.toPrimitive](hint)` methods. When converting an object to a primitive (e.g. a string), any one of these methods can potentially be called. Which are called depends on their existence, the kind of conversion being performed, and potentially the value they return. Consider the following using both a toString and valueOf:

```javascript
class MyClass {
  toString() {
    return 'As string'
  }
  valueOf() {
    return 'As value'
  }
}

console.log('' + new MyClass) // As value
console.log(String(new MyClass)) // As string

```

When using string concatenation (via `+`) `valueOf()` was used, not `toString()`, however `toString()` was used with an explicit `String()` conversion. If we remove the `valueOf()`, we get `toString()` used for both.

```javascript
class MyClass {
  toString() {
    return 'As string'
  }
}

console.log('' + new MyClass) // As string
console.log(String(new MyClass)) // As string

```

... and this despite objects inheriting a default `valueOf()` from Object.prototype. So its not that a `valueOf()` doesn't exist here, rather that the default `valueOf()` returns `this` which is an object and not a primitive so the conversion falls back to using `toString()` instead because it demands a primitive value.

```javascript
const myObj = new MyClass // the version without its own valueOf()
console.log(myObj === myObj.valueOf()) // true

```

Which method is used first during conversion depends on what you're doing and if the first doesn't return a primitive, the other is used as a fallback. "What you're doing" is divided into 3 kinds of conversions: "string", "number", and "default". More specifically these are "hints" into how the operation is meant to perform the conversion which becomes more clear with the 3rd method `[Symbol.toPrimitive](hint)` . If present, this method supersedes all uses of `valueOf()` and `toString()` (not using them as fallbacks either) but comes with the benefit of having insight into the conversion `hint` through its argument.

```javascript
class MyClass {
  [Symbol.toPrimitive](hint) {
    console.log(`As primitive with hint: ${hint}`)
    return ''
  }
}

'' + new MyClass // As primitive with hint: default
String(new MyClass) // As primitive with hint: string
10 * new MyClass // As primitive with hint: number

```

In the `toString()`/`valueOf()` the "default" and "number" hints go to `valueOf()` first whereas the "string" hint starts with `toString()`. When using `[Symbol.toPrimitive](hint)`, they all go through that single method passing in the hint along with it. The biggest advantage here being that you can separate "default" from "number" conversions.

So if you want the most control over string and other primitive conversions, you might want to implement a `[Symbol.toPrimitive](hint)`. Otherwise, you should get by just fine with a `toString()`.

...anyway, theres more than you ever wanted to know about string conversion options for your class.

Bonus trivia: Though Object.prototype doesn't implement `[Symbol.toPrimitive](hint)`, some other builtins do, like Date objects. Dates implement one to reverse the precedence of their "default" `toString()` and `valueOf()` calls. For example where normally a `valueOf()` would be called first for a `"" + new Date`, instead `toString()` is.

```javascript
const date = new Date
console.log(date.toString()) // Wed Jul 21 2021 14:02:46 GMT-0400 (Eastern Daylight Time)
console.log(date.valueOf()) // 1626890566431
console.log("" + date) // Wed Jul 21 2021 14:02:46 GMT-0400 (Eastern Daylight Time)

// remove toPrimitive for default behavior
Object.defineProperty(date, Symbol.toPrimitive, { value: null });
console.log("" + date) // 1626890566431

```
