31

I get an error type object argument after ** must be a mapping, not tuple.

I have this code: create_character = player.Create(**generate_player.generate())

this is player.py module:

class Create(object):

    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

this is generate_player.py module:

import prompt

def generate():

    print "Name:"
    name = prompt.get_name()
    print "Age:"
    age = prompt.get_age()
    print "Gender M/F:"
    gender = prompt.get_gender()

    return name, age, gender

The prompt module is just bunch of raw_inputs that return either string or integers (int for age).

Why is it returning tuples? When I run print type in generate_player module I get string, int, string for my arguments.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user3056783
  • 2,265
  • 1
  • 29
  • 55

3 Answers3

34

The ** syntax requires a mapping (such as a dictionary); each key-value pair in the mapping becomes a keyword argument.

Your generate() function, on the other hand, returns a tuple, not a dictionary. You can pass in a tuple as separate arguments with similar syntax, using just one asterisk:

create_character = player.Create(*generate_player.generate())

Alternatively, fix your generate() function to return a dictionary:

def generate():
    print "Name:"
    name = prompt.get_name()
    print "Age:"
    age = prompt.get_age()
    print "Gender M/F:"
    gender = prompt.get_gender()

    return {'name': name, 'age': age, 'gender': gender}
user8808265
  • 1,893
  • 1
  • 17
  • 25
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    I just found out using `create_character = player.Create(*generate_player.generate())` is what I need. Thanks! – user3056783 Apr 11 '14 at 11:29
  • How is mapping defined here? In other words, can I make any class **-unpackable? Same question for *-unpackables – Bananach Jan 27 '20 at 13:11
  • 2
    @Bananach: See [mapping](https://docs.python.org/3/glossary.html#term-mapping), so anything that has the [`collections.abc.Mappings` methods](https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes). `*` requires an [iterable](https://docs.python.org/3/glossary.html#term-iterable). – Martijn Pieters Jan 27 '20 at 13:41
11

You just want a single asterisk:

create_character = player.Create(*generate_player.generate())

You're passing a sequence of arguments, for which you use one asterisk. The double-asterisk syntax is for passing a mapping, for instance to do something like this:

player.Create(**{'name': 'Richie', 'age': 21, 'gender': 'male'})
RichieHindle
  • 272,464
  • 47
  • 358
  • 399
1

FWIW, in my case I left a comma , at the end of the definition of the dictionary, e.g.,

params = {...}, 

f(**params)

and params is a 1-tuple now with the dictionary being its element, hence the error... Removing the comma resolves it.

Mustafa Aydın
  • 17,645
  • 4
  • 15
  • 38