differences between for...in JS and in Python

Asked

Viewed 182 times

2

in the following code in Python...

string = "abcd"
for i in string:
    print(i)
---------------
output:
a
b
c
d

and in Javascript

string = "abcd"
for(i in string)
    console.log(i)
---------------
output:
0
1
2
3

What makes returns different? It is possible to do the Python return type in JS and vice versa?

  • Related answer: https://answall.com/a/2515/64969

1 answer

2


Python has a for that since the beginning of language, in the 90s was a construct to traverse a sequence. A block that in other programming languages, or in generic terms, we call for each or for in. In particular he is quite different from a while, and will always traverse a sequence - be it the string of a string, a sequence of numbers in a list or an array, and so on.

The language is remarkably consistent with this, within its philosophy of providing the maximum value to do the little things right so that the developer can worry about his algorithm, and not get into a fight with the language. In cases, which are minority ,(though not rare) where the for or a numerical sequence or index of the elements of a sequence, one can use the functionalities range and enumerate of language.

To create the numeric return in Python, we usually use the enumerate method - since even with the index in hand, we will usually need the content of the sequence in that index:

for i, letra in enumerate("abcd"):
    print (i, letra)

---
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')

If you make a point of only having the numbers, just use range up to the length of the sequence:

for i in range(len("abcd")):
    print(i)

(although in general find for i in range(len(...)): is more an indication that the developer is used to another language and learning Python than a sign of good code - for the simple reason that you will almost always want the content of the sequence, and only in the minority of times the index - but almost never just the indexes - just try to think of an example of real problem that needs only the indexes to verify this)

Javascript, as well as other languages derived from the C language (Java, PHP, C#, C++, Objective C, Perl) actually has a for which is almost the same as a while, with the only difference that the initialization expression and the end condition are grouped. (compare for (i=0; i < 10; i++) {...} with i = 0; while (i < 10) {...; i++} .

At some point in the history of Javascript, they created the for in (I couldn’t find it when - it was already present in the first Ecmascript specification of 1997. Before that, Javascript was what each browser put as Javascript) - but instead of going through the elements of a sequence, they chose to return a numerical sequence to with a number for each key existing in the object - a choice made perhaps because it had no way to maintain consistency, since Javascript does not properly have sequences internally as the Python lists - both objects, as sequences as mappings are more or less interchangeable things in Javascript, means "soft":

> a = [0,1,2]
< [0, 1, 2]
> a["chave"] = "valor";
< "valor"
> a
< [0, 1, 2, chave: "valor"]

To maintain consistency, the for in Javascritp also returns indexes when the element is a string. The obvious way to go through the values associated with each index is to make an assignment in the first lines of the for:

for (i in palavra="abcd") {var letra=palavra[i]; console.log(letra);}

But there comes into play another Javascript idiosyncrasy - again because of the history of the language, it does not have a separation between "instances" and "classes" as in traditional object-oriented languages, working with the notion of prototypes, in which "Everything is an object with equal powers, and any object can be the prototype of another functioning as a 'class'". (In practice, you can run the entire Internet and not find any text that can show any advantage of this "object orientation by prototypes", instead of the well-defined use of classes and instances (the most that even the biggest fans of the idea can get is that "is not so bad"). Okay, well, the problem with this is that in a javascript object, there is not automatically a distinction between attributes that would be from the "prototype" of an object and the attributes of the object itself - as happens in Python that has distinct classes and instances. So if you run the line above to try to print letter by letter, you will have:

for (i in palavra="abcd") {var letra=palavra[i]; console.log(letra);}

>  a
>  b
>  c
>  d
>  ƒ (){var e=this.toString();if(!arguments.length)return e;var t=typeof arguments[0],n="string"==t||"number"==t?Array.prototype.slice.call(arguments):arguments[0];for(var i in n)e=e.replace(new RegExp("\…
>  ƒ (e,t){var n=this.toString();return e&&n.length>e&&(n=n.substr(0,e)+t),n}
>  ƒ (e){var t=this.lastIndexOf(e);return 0>t?[this]:[this.substr(0,t),this.substr(t)]}
>  ƒ (e){return this.indexOf(e)>-1}

That is: after the last letter index the attributes of the prototype of the string appear.

There’s a way around this by calling it the method .isOwnProperty of each key of for in:

for (i in palavra="abcd") {var letra=palavra[i]; if (!palavra.hasOwnProperty(i)) {continue;}  console.log(letra);}
>  a
>  b
>  c
>  d

Answer:

In practice, the way things work in Python is very practical, which made later developments in javascript or libraries try to improve the functionality of a for each. Then, at some point was introduced the for (elemento of object) (for of), that can extract elements from a sequence or object, and treat strings as sequences:

for (letra of "abcd") {console.log(letra)}
> 1 a
> 1 b
> 1 c
> 1 d

Continuing

... but the for of does not work for general objects - just arrays and strings (and maybe some other type of object):

for (element of {"a": "A", "b": "B"}) console.log(element);
> Uncaught TypeError: {(intermediate value)(intermediate value)} is not iterable at <anonymous>:1:17

In the historical search for a solution, before the for of there are other approaches: for type objects Array, there is a method forEach that runs through its elements. But since this is not part of the syntax of the language, but rather a method like any other, instead of opening a block with the commands to be executed, you pass a function that will be called for each element of the sequence. Since Javascript allows arbitrary inline functions, this is almost only a question of placing syntactic markings (function (parametro) {...} ) instead of just one block { ...} - but it has side effects, like the name this is resigned, there is another scope of variables, and etc...:

a.forEach(function (letra){ console.log(letra);})

>  a
>  b
>  c
>  d

Of course, there is still the drawback of this working for Arrays, but not working for strings, while in Python the two things (thinking of lists, instead of arrays), have the same interface of "sequences".

Then, by "popular demand", one of the most popular Javascript third-party packages, jQuery, implemented the "each" function that does the same as the "foreach" of the Array for any object. Since the chance is great that your page already includes jQuery in some way, you can use this method to iterate over generic object keys, as with Python dictionaries:

$.each({"a": "A", "b": "B"}, function (letra) {console.log(letra)} )
> a
> b

jQuery, keeping the Javascript tradition, cannot make this consistent for all obvious purposes, so despite its .each work for almost any object, does not work for strings. For strings you should even use the above answer, or find yet another module that does this.

  • the answer could not be better, clarified my doubts! thank you very much!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.