5

I declare a class Employee and a list consist of it:

class Employee():
    def __init__(self, _name):
        self.name = _name
    def get_name(self):
        return self.name

Tom   = Employee("Tom")
Karl  = Employee("Karl")
John  = Employee("John")

employee_list = [Tom, Karl, John]

Now I want to have a list of their name by applying get_name in a map:

name_list = map(get_name, employee_list)


Traceback (most recent call last): File "ask.py", line 13, in <module> 
    name_list = map(get_name, employee_list) 
NameError: name 'get_name' is not defined

How could get_name be not defined?

How do I do to apply member function in a map?

Mazdak
  • 105,000
  • 18
  • 159
  • 188

6 Answers6

3

map(get_name, employee_list)in your code is equivalent to

[get_name(employee) for employee in employee_list]

not [employee.get_name() for employee in employee_list]

You should declare a get_name method outside of Employee class:

def get_name(employee):
    return employee.name

or an easier way with Lambda:

name_list = map(lambda employee: employee.name, employee_list)

Rahn
  • 4,787
  • 4
  • 31
  • 57
2

You have to call the method from the instance. You can use a lambda for this

name_list = map(lambda e: e.get_name(), employee_list)
salomonderossi
  • 2,180
  • 14
  • 20
2

This should be done using a list comprehension:

names = [employee.get_name() for employee in employee_list]

Additionally, I would suggest you to shorten the way you create the employee_list as well by not assigning intermediate variable names, but directly creating the instances inside the list literal:

employee_list = [Employee("Tom"), Employee("Karl"), Employee("John")]

This could be further shortened by using a list comprehension again:

employee_list = [Employee(name) for name in ("Tom", "Karl", "John")]
Byte Commander
  • 6,506
  • 6
  • 44
  • 71
2

While all other answers are correct, all miss one particular feature of python: "instance method" can be called in a "class method" manner, passing class instance as a first parameter. So (at least in python2.7), the following works just fine:

map(Employee.get_name, employee_list)

Refer to this SO question for some details on why and how it works.

Community
  • 1
  • 1
J0HN
  • 26,063
  • 5
  • 54
  • 85
1

Colleagues, thank you for the discussion, it helped me. I only want to note that map creates an generator iterator, not a list. So, an complete analogue is

(get_name(employee) for employee in employee_list)

instead of

[get_name(employee) for employee in employee_list]

For example, this is essential when you do not want (cannot) keep all data in memory:

for L in map(str.strip,open("huge_file")):
    do_something(L)
  • To be pedantic, `map` creates a `map` object, which is an *iterator* but not a generator (although for most cases the distinction is irrelevant) – juanpa.arrivillaga Jun 16 '22 at 20:05
0

map calls a function, but get_name() is a method. If you really want to use map then you can take advantage of the way that Python implements methods: they are equivalent to calling the function as an unbound method with the object as the first self argument:

name_list = map(Employee.get_name, employee_list)

To access the method without binding it to a specific instance you need to access through on the class. Note that this won't work correctly if you have a variety of subclasses of Employee and get_name is overridden.

The more Pythonic way is, as others have said, to use a list comprehension, but if you want to go 'Pythonic' then you shouldn't be using an accessor method at all: you should just be accessing the name attribute for a simple value like this, or turn it into a property if you need more complex access:

names = [employee.name for employee in employee_list]
Duncan
  • 92,073
  • 11
  • 122
  • 156