概念理解#1 第一类公民(First-class Citizen)

In programming language design, a first-class citizen (also object, entity, or value) in a given programming language is an entity which supports all the operations generally available to other entities. These operations typically include being passed as a parameter, returned from a function, and assigned to a variable. – Wikipedia

意思是说,第一类公民、第一类对象(不特指面向对象里的"对象”)、第一类实体、第一类值(这些概念都是一个,只是叫法不同)是支持其他实体所有操作的实体。这里有两个地方要展开:

  1. 实体与其他实体
    通常实体是指各种各样的数据类型和值,比如对象、类、函数、字面量等,一般讨论都是指函数是不是第一类对象(first-class object)

  2. 操作
    这些实体所具有的操作有:

    1. 可以作为变量或者数据结构存储
    2. 可以作为参数传递给方法/函数
    3. 可以作为返回值从函数/方法返回
    4. 可以在运行期创建
    5. 有固有身份

“固有身份”是指实体有内部表示,而不是根据名字来识别,比如匿名函数,还可以通过赋值叫任何名字。大部分语言的基本类型的数值(int, float)等都是第一类对象;但是数组不一定,比如C中的数组,作为函数参数时,传递的是第一个元素的地址,同时还丢失了数组长度信息。对于大多数的动态语言,函数/方法都是第一类对象,比如Python,但是Ruby不是,因为不能返回一个方法。第一类函数对函数式编程语言来说是必须的。

这个概念是1960s中期Christopher Strachey提出的,虽然没有严格定义,他对比了Algol中的实数(real numbers)和子程序(procedures):

First and second class objects. In Algol, a real number may appear in an expression or be assigned to a variable, and either may appear as an actual parameter in a procedure call. A procedure, on the other hand, may only appear in another procedure call either as the operator (the most common case) or as one of the actual parameters. There are no other expressions involving procedures or whose results are procedures. Thus in a sense procedures in Algol are second class citizens—they always have to appear in person and can never be represented by a variable or expression (except in the case of a formal parameter)…

Algol中,实数可以出现在表达式,或者被赋值给一个变量,两者(表达式,变量)都可以作为实际参数传递给子程序调用。但是子程序,只能作为一个操作数或者一个实际参数出现在另一个子程序调用中。没有表达式与子程序有关联,表达式的返回值也不能是子程序。所以从某种意义上来说,Algol中的子程序是二等公民,它们只能独自出现,不能被一个变量或者表达式表示(除非是形式参数)…

从这段历史背景里可以看出,第一类(first-class)与第二类(second-class),是借助于社会学概念中的一等和二等,来表示不同实体出现的位置(可以进行的操作)是不对等的。后来还出现了第三类和第四类公民,但是没有广泛传播。

Python示例:

def speak(): 
    print "first-class function"

#1 函数可以被赋值
parle = speak
parle()

def people(action):
    action()

#2 函数可以作为参数传递给函数
people(speak)

def parent_do():
    def child_do():
        print "child function"
    return child_do

#3 函数可以作为返回值从函数返回
#4 函数可以在运行时动态创建
do_func = parent_do()
do_func()

f1 = lambda x: x + 1
f2 = lambda x: x + 1

#5 函数有固有身份
print (f1 == f2)

你可能感兴趣的:(python)