TypeError: type.__new__() argument 2 must be tuple, not str - python-3.x

I get the following error when I run the piece of code below. I can clearly print the value of *strs on screen, which appears as string. But, when I do type(*strs), it throws TypeError: type.__new__() argument 2 must be tuple, not str. Can someone explain this behaviour?
strs = ["flower","flood","flight"]
print(*strs)
print(type(strs))
print(type(*strs))
Output:
Traceback (most recent call last):
print(type(*strs))
TypeError: type.__new__() argument 2 must be tuple, not str
flower flood flight
<class 'list'>
Process finished with exit code 1

The asterix operator in '*strs' unpacks the iterms in 'strs', which is a series of three strings. Your code ran into trouble when it tried to send those strings to the type() command, where type() was initialized by its __ new__() magic method.
type() has two forms:
1.) type(object) where the 'object' is an instance of some class.
2.) type(name, bases, dictionary) where 'bases' is a tuple that itemizes base classes, and a dictionary that contains definitions of base classes.
In your code, the use of the unpacking operation, *strs, resulted in type() being sent three arguments, so it was expecting a name, a tuple, and a dictionary. What it, and then __ new()__ got was three strings: A name (it received 'flower'), then another string, "flood", where it wanted a tuple. Here python threw the error and never made it to the third string, 'flight'.
We can duplicate the error with:
print(type("a","b","c"))
We can also see that either one or three (but not two) arguments were expected, with:
print(type("a","b"))
while the following command works just fine:
print(type("a"))
If you want to see the type of each member of *strs, first let it unpack to a list, then iterate through that list, printing the type of each member as you go.
mylist = [*strs]
for elm in mylist:
print(type(elm))
Does this answer the question of what caused that behavior and the error?

Related

PyCharm says there is no errors here, but when i run the code i get ValueError: too many values to unpack (expected 2)

enter code here
pizzas = ("4 seasons", "Neapolitan", "Pepperoni")
def display_pizzas(types):
types = list(types)
print(f"---PIZZAS({len(types)})---")
for p, x in types, range(0,len(types)):
print(f"{x}. Pizza {p}")
display_pizzas(pizzas)
im trying this weird syntax, PyCharm sees no errors here, but i get
Traceback (most recent call last):
File "...\main.py", line 9, in
display_pizzas(pizzas)
File "...\main.py", line 6, in display_pizzas
for p, x in rodzaje, range(0,len(rodzaje)):
ValueError: too many values to unpack (expected 2)
Nvm, i already found the solution whitch is:
enter code here
pizzas = ("4 seasons", "Neapolitan", "Pepperoni")
def display_pizzas(types):
types = list(types)
print(f"---PIZZAS({len(types)})---")
for p, x in zip(types, range(0,len(types))):
print(f"{x}. Pizza {p}")
bye
Maybe your new code works but it's not compiled in a pythonic way.
so I made a little refactor into your code.
you don't need to convert tuple types to the list because the tuple is already iterable you can use for loop without converting to list
instead of zip function you can user builtin enumerate
this is the whole code
from typing import Iterable
pizzas = ("4 seasons", "Neapolitan", "Pepperoni")
# refactoring Code
def display_pizzas(types: Iterable[str] = None):
print(f"---PIZZAS({len(types)})---")
for counter, pizza in enumerate(types):
print(f"{counter}. Pizza {pizza}")
display_pizzas(pizzas)

AttributeError: 'int' object has no attribute 'pop'

When writing list inside tuple, getting error:
AttributeError: 'int' object has no attribute 'pop'
fruits=('apple','banana', ['kiwi','grapes'])
fruits[1].pop()
fruits[1].append('rice')
print(fruits)
I am getting:
str object has no attribute pop
which is what I was expecting since fruits[1] is 'banana' which is a string and strings do not have a pop method.
If you look at the next line you will run into a similar issue since strings also don't have an append method.
If you remove both of those lines you shouldn't have any errors with just the list inside of the tuple.
fruits = ('apple','banana', ['kiwi','grapes'])
print(fruits)
Your issue is coming from you trying to pop a string, in the second line of your code - not from adding a list in the tuple. Now as tuples are immutable in python, you will need to convert it into a list if you wish to start modyfing what is inside of it. A simple example using your code is below.
fruits=('apple','banana', ['kiwi','grapes'])
fruits_list = list(fruits)
fruits_list.pop(1)
fruits_list.insert(1, 'rice')
fruits = tuple(fruits_list)
print(fruits)
You can read more about it here: pop/remove items out of a python tuple

how to put variable in python defaultdict call

In a python defaultdict object (like obj1), I can call obj1['hello','there'] and get item. but when the input list is variable (for example: input_list), how I can call obj1[input_list]?
when I call obj1[input_list], python raise this error:
TypeError: unhashable type: 'list'
when use obj1[*input_list], python returns:
SyntaxError: invalid syntax
So what is the correct way to put list as variable in defaultdict?
The error TypeError: unhashable type: 'list' states that list is not hashable, but a dict always needs a hashable key!
If you test my_normal_dict[2,3] you can see that it actually treats these two numbers as the tuple (2,3) because the error is KeyError: (2, 3), so you need to input a hashable iterable like a tuple.
For example, my_dict[tuple(my_list)] should work, as long as all the elements of the tuple itself are hashable!
Note though: If your list is large, it may be relevant that this needs to copy all elements into a tuple.

Python parse list of dictionaries TypeError: string indices must be integers

I have HTML form input field that returns a list of dictionaries I want to get values from using PYthon in Django View.
The form returns:
request.POST['tags'] returns => [{"value":"summer"},{"value":"winter"}]
When I try interating through it using [tag['value'] for tag in request.POST['tags']] to get values, I get TypeError: string indices must be integers.
However, if I manually copy the input field results to command line and go line by line it works as expected:
>>> test = [{"value":"summer"},{"value":"winter"}]
>>> test
>>> [{'value':'summer'},{'value':'winter'}]
>>> [tag['value'] for tag in test]
>>> ['summer', 'winter']
What is happening?
Updated to add print of 3 different request.POST results:
request.POST => <QueryDict: {'tags': ['[{"value":"summer"},{"value":"winter"}]']}>
request.POST.values => <bound method MultiValueDict.values of <QueryDict: {
'tags': ['[{"value":"summer"},{"value":"winter"}]']}>>
request.POST[tags] => [{"value":"summer"},{"value":"winter"}]
https://docs.djangoproject.com/en/2.2/ref/request-response/#querydict-objects
QueryDict.__getitem__(key)
Returns the value for the given key. If the key has more than one value, it returns the last value. Raises django.utils.datastructures.MultiValueDictKeyError if the key does not exist. (This is a subclass of Python’s standard KeyError, so you can stick to catching KeyError.)
You will have to user getlist() when you have multiple values for the same key:
[tag['value'] for tag in request.POST.getlist('tags')]
https://docs.djangoproject.com/en/2.2/ref/request-response/#django.http.QueryDict.getlist
QueryDict.getlist(key, default=None)
Returns a list of the data with the requested key. Returns an empty list if the key doesn’t exist and a default value wasn’t provided. It’s guaranteed to return a list unless the default value provided isn’t a list.
EDIT
Okay, I can see the issue now. You are not sending a list to your arg tags, you are sending a string that represents a list.
If I am not missing anything else the following should work:
import json
tags = json.loads(request.POST['tags'])
[tag.get('value') for tag in tags]

Iterating thru list for lxml form submission

I'm pretty new to Python and even more new to lxml, but what I'm trying to do seems really simple but I can't figure out what I'm doing wrong.
I have this code with the goal of feeding a list of values (list object ISBN) to lxml to submit to a search field:
for i in ISBN:
page.forms[0].fields['_nkw'] = ISBN[i]
blah blah blah
I get this error after running:
Traceback (most recent call last):
page.forms[0].fields['_nkw'] = ISBN[i]
TypeError: list indices must be integers, not str
Obviously there has to be a way to iterate through a list of values to feed to a form, but clearly I don't know it :)
EDIT: FYI the code works fine when replacing ISBN[i] with hard input.
EDIT 2: contents of ISBN list object as requested:
['9781608319053', '9780321558237', '9781932735413', '9781416059516', '9781437708257', '9780781780582', '9781437701517', '9780323065801', '9780890420256', '9780323079334', '9781599417042', '9780781771535', '9781416031215', '9780312601430', '9780781775250', '9781591263333', '9780071748896', '9780133669510', '9781416045748', '9780781771566', '9781437728019', '9780323065849', '9781416066675', '9780735579965', '9780323078917', '9781437735826', '9781603595681', '9780321696724', '9780321558145', '9781933107981', '9780138024611']
The trouble is with your loop over and use of the ISBN variable. You don't need to be indexing it during your assignment, since i already holds an element of the list, extracted as part of the loop. You're getting an exception because you can't index a list with a string, even if that string came out of the list itself.
Instead, use page.forms[0].fields['_nkw'] = i.
Or if you need the index into the ISBN list for later code that you haven't shown, keep the assignment as it is, and change the loop declaration to:
for i in range(len(ISBN)):

Resources