[python] Python 3 - ValueError: not enough values to unpack (expected 3, got 2)

I have a problem with my Python 3 program. I use Mac OS X. This code is running properly.

# -*- coding: utf-8 -*-
#! python3
# sendDuesReminders.py - Sends emails based on payment status in spreadsheet.

import openpyxl, smtplib, sys


# Open the spreadsheet and get the latest dues status.
wb = openpyxl.load_workbook('duesRecords.xlsx')
sheet = wb.get_sheet_by_name('Sheet1')

lastCol = sheet.max_column
latestMonth = sheet.cell(row=1, column=lastCol).value

# Check each member's payment status.
unpaidMembers = {}
for r in range(2, sheet.max_row + 1):
payment = sheet.cell(row=r, column=lastCol).value
if payment != 'zaplacone':
    name = sheet.cell(row=r, column=2).value
    lastname = sheet.cell(row=r, column=3).value
    email = sheet.cell(row=r, column=4).value
    unpaidMembers[name] = email


# Log in to email account.
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.ehlo()
smtpObj.login('[email protected]', '1234')


# Send out reminder emails.
for name, email in unpaidMembers.items()
body = "Subject: %s - przypomnienie o platnosci raty za treningi GIT Parkour. " \
       "\n\nPrzypominamy o uregulowaniu wplaty za uczestnictwo: %s w treningach GIT Parkour w ." \
       "\n\nRecords show  that you have not paid dues for %s. Please make " \
       "this payment as soon as possible."%(latestMonth, name, latestMonth)
print('Sending email to %s...' % email)
sendmailStatus = smtpObj.sendmail('[email protected]', email, body)

if sendmailStatus != {}:
    print('There was a problem sending email to %s: %s' % (email,
    sendmailStatus))
smtpObj.quit()enter code here

Problems starts when I am trying to add next value to the for loop.

# Send out reminder emails.
for name, lastname, email in unpaidMembers.items()
body = "Subject: %s - przypomnienie o platnosci raty za treningi GIT Parkour. " \
       "\n\nPrzypominamy o uregulowaniu wplaty za uczestnictwo: %s %s w treningach GIT Parkour w ." \
       "\n\nRecords show  that you have not paid dues for %s. Please make " \
       "this payment as soon as possible."%(latestMonth, name, lastname, latestMonth)
print('Sending email to %s...' % email)
sendmailStatus = smtpObj.sendmail('[email protected]', email, body)

Terminal shows error:

Traceback (most recent call last):
    File "sendDuesEmailReminder.py", line 44, in <module>
        for name, email, lastname in unpaidMembers.items():
ValueError: not enough values to unpack (expected 3, got 2)

This question is related to python python-3.x

The answer is


Since unpaidMembers is a dictionary it always returns two values when called with .items() - (key, value). You may want to keep your data as a list of tuples [(name, email, lastname), (name, email, lastname)..].


ValueErrors :In Python, a value is the information that is stored within a certain object. To encounter a ValueError in Python means that is a problem with the content of the object you tried to assign the value to.

in your case name,lastname and email 3 parameters are there but unpaidmembers only contain 2 of them.

name, lastname, email in unpaidMembers.items() so you should refer data or your code might be
lastname, email in unpaidMembers.items() or name, email in unpaidMembers.items()


In this line:

for name, email, lastname in unpaidMembers.items():

unpaidMembers.items() must have only two values per iteration.

Here is a small example to illustrate the problem:

This will work:

for alpha, beta, delta in [("first", "second", "third")]:
    print("alpha:", alpha, "beta:", beta, "delta:", delta)

This will fail, and is what your code does:

for alpha, beta, delta in [("first", "second")]:
    print("alpha:", alpha, "beta:", beta, "delta:", delta)

In this last example, what value in the list is assigned to delta? Nothing, There aren't enough values, and that is the problem.


1. First should understand the error meaning

Error not enough values to unpack (expected 3, got 2) means:

a 2 part tuple, but assign to 3 values

and I have written demo code to show for you:


#!/usr/bin/python
# -*- coding: utf-8 -*-
# Function: Showing how to understand ValueError 'not enough values to unpack (expected 3, got 2)'
# Author: Crifan Li
# Update: 20191212

def notEnoughUnpack():
    """Showing how to understand python error `not enough values to unpack (expected 3, got 2)`"""
    # a dict, which single key's value is two part tuple
    valueIsTwoPartTupleDict = {
        "name1": ("lastname1", "email1"),
        "name2": ("lastname2", "email2"),
    }

    # Test case 1: got value from key
    gotLastname, gotEmail = valueIsTwoPartTupleDict["name1"] # OK
    print("gotLastname=%s, gotEmail=%s" % (gotLastname, gotEmail))
    # gotLastname, gotEmail, gotOtherSomeValue = valueIsTwoPartTupleDict["name1"] # -> ValueError not enough values to unpack (expected 3, got 2)

    # Test case 2: got from dict.items()
    for eachKey, eachValues in valueIsTwoPartTupleDict.items():
        print("eachKey=%s, eachValues=%s" % (eachKey, eachValues))
    # same as following:
    # Background knowledge: each of dict.items() return (key, values)
    # here above eachValues is a tuple of two parts
    for eachKey, (eachValuePart1, eachValuePart2) in valueIsTwoPartTupleDict.items():
        print("eachKey=%s, eachValuePart1=%s, eachValuePart2=%s" % (eachKey, eachValuePart1, eachValuePart2))
    # but following:
    for eachKey, (eachValuePart1, eachValuePart2, eachValuePart3) in valueIsTwoPartTupleDict.items(): # will -> ValueError not enough values to unpack (expected 3, got 2)
        pass

if __name__ == "__main__":
    notEnoughUnpack()

using VSCode debug effect:

notEnoughUnpack CrifanLi

2. For your code

for name, email, lastname in unpaidMembers.items():

but error ValueError: not enough values to unpack (expected 3, got 2)

means each item(a tuple value) in unpaidMembers, only have 1 parts:email, which corresponding above code

    unpaidMembers[name] = email

so should change code to:

for name, email in unpaidMembers.items():

to avoid error.

But obviously you expect extra lastname, so should change your above code to

    unpaidMembers[name] = (email, lastname)

and better change to better syntax:

for name, (email, lastname) in unpaidMembers.items():

then everything is OK and clear.