this is gives a none values :
{%for i in l%}
<tr>
<td>{{con.hotel.i}}</td>
</tr>
{%endfor%}
while this works and give the correct values
{%for i in l%}
<tr>
<td>{{con.hotel1.0}}</td>
</tr>
{%endfor%}
this is gives a none values :
{%for i in l%}
<tr>
<td>{{con.hotel.i}}</td>
</tr>
{%endfor%}
while this works and give the correct values
{%for i in l%}
<tr>
<td>{{con.hotel1.0}}</td>
</tr>
{%endfor%}
Because it then will try to access the .i attribute. If you write .item, then it will first try to access .item, then ['item'] and finally try [int('item')], so for .0 that means it tries .0 which fails, ['0'] which fails as well, and then [int('0')], which will use the first item.
For hotel.i, it will thus first try hotel.i, then hotel['i'], and finally try to convert 'i' to an int, which will all fail.
It would be confusing to also try [item], since that would be confusing in case .item as attribute exists.
For jinja however, you can subscript, so:
{% for i in l %}
<tr>
<td>{{ con.hotel[i] }}</td>
</tr>
{% endfor %}