什么是“一等”对象?

What are "first-class" objects?

提问人:Federico A. Ramponi 提问时间:10/29/2008 最后编辑:Sabito stands with UkraineFederico A. Ramponi 更新时间:5/23/2023 访问量:82641

问:

在给定的编程语言中,什么时候对象或其他东西被称为“一流”,为什么?它们与它们不是的语言有什么不同?

当一个人说“一切都是对象”(就像在 Python 中一样)时,他们真的意味着“一切都是一流的”吗?

与 Python 语言无关

评论


答:

235赞 9 revs, 2 users 98%Brian R. Bondy #1

简而言之,这意味着对对象的使用没有限制。这和 任何其他对象。

第一类对象是一个实体,可以动态创建、销毁、传递给函数、作为值返回,并具有编程语言中其他变量所具有的所有权限。

根据语言的不同,这可以 暗示:

  • 可表示为匿名文本值
  • 可存储在变量中
  • 可存储在数据结构中
  • 具有内在身份(独立于任何给定名称)
  • 与其他实体具有可比性
  • 可作为过程/函数的参数传递
  • 可作为过程/功能的结果返回
  • 在运行时可构造
  • 可打印
  • 可读性
  • 在分布式进程之间可传输
  • 可在正在运行的进程之外存储

来源

但是,在 C++ 中,函数本身不是第一类对象:

  • 您可以覆盖 '()' 运算符,从而可以拥有一个对象函数,这是第一类。
  • 函数指针是一流的。
  • Boost Bind、Lambda 和 Function 确实提供了一流的函数

在 C++ 中,类不是第一类对象,但这些类的实例是。在 Python 中,类对象都是第一类对象。(有关作为对象的类的更多详细信息,请参阅此答案)。

下面是 Javascript 第一类函数的示例:

// f: function that takes a number and returns a number
// deltaX: small positive number
// returns a function that is an approximate derivative of f
function makeDerivative( f, deltaX )
{
    var deriv = function(x)
    { 
       return ( f(x + deltaX) - f(x) )/ deltaX;
    }
    return deriv;
}
var cos = makeDerivative( Math.sin, 0.000001);
// cos(0)     ~> 1
// cos(pi/2)  ~> 0

来源

不是第一类对象的实体称为第二类对象。C++ 中的函数是二等函数,因为它们不能动态创建。

关于编辑:

编辑。当一个人说“一切都是 一个对象“(就像在 Python 中一样),他做到了 确实意味着“一切都是 头等舱“?

术语“对象”可以松散地使用,并不意味着是一流的。将整个概念称为“第一类实体”可能更有意义。但在 Python 中,他们的目标是让一切都变得一流。我相信发表你发言的人的意图是头等舱。

评论

4赞 Sudip Bhandari 7/5/2017
您能举一些非“一流”对象的例子吗?
1赞 Mike B 2/13/2019
@SudipBhandari我想知道同样的事情,最后偶然发现了关于这个主题的有用的维基百科文章:一等公民/对象。我发现罗宾·波普尔斯通的定义特别有用。(顺便说一句,发布 WP 文章可能看起来非常明显,但我没有意识到这是一个基本的编程语言概念)
0赞 KetDog 12/14/2020
有人可以举一个匿名文字值的例子吗?
2赞 Alex M. 6/28/2021
@Papaya-Automaton:当然,几乎所有的基元类型:整数、字符串、浮点数、布尔常量 “” 和 “”。根据语言的不同,您可能还有更多(例如,C 中的数组或 Scheme 中的列表)。truefalse[1,2,3]'(1 2 3)
20赞 Konrad Rudolph 10/29/2008 #2

“头等舱”意味着您可以以通常的方式对它们进行操作。大多数时候,这只是意味着您可以将这些一等公民作为参数传递给函数,或者从函数返回它们。

这对于对象来说是不言而喻的,但对于函数甚至类来说并不总是那么明显:

void f(int n) { return n * 2; }

void g(Action<int> a, int n) { return a(n); }

// Now call g and pass f:

g(f, 10); // = 20

这是 C# 中的一个示例,其中函数实际上不是第一类对象。因此,上面的代码使用一个小的解决方法(即称为 的泛型委托)将函数作为参数传递。其他语言,如 Ruby 或 Python,允许将类和代码块视为普通变量(或者在 Ruby 的情况下,常量)。Action<>

3赞 questzen 10/29/2008 #3

IMO,这是用于用自然语言描述事物的隐喻之一。该术语主要用于将函数描述为第一类对象的上下文中。

如果您考虑面向对象的语言,我们可以为对象赋予各种功能,例如:继承、类定义、传递给其他代码部分的能力(方法参数)、存储在数据结构中的能力等。如果我们可以对通常不被视为对象的实体做同样的事情,例如 java 脚本中的函数,则此类实体被视为第一类对象。

这里的一等基本上意味着,不作为二等(有退化的行为)处理。从本质上讲,嘲笑是完美的或无法区分的。

29赞 S.Lott 10/29/2008 #4

“当一个人说'一切都是对象'(就像在Python中一样)时,他真的是指'一切都是一流的'吗?

是的。

Python 中的一切都是正确的对象。即使是其他语言中的“原始类型”的东西。

你会发现一个对象实际上有一个相当丰富和复杂的界面。2

>>> dir(2)
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__str__', '__sub__', '__truediv__', '__xor__']

因为一切都是 Python 中的一等对象,所以晦涩难懂的特殊情况相对较少。

例如,在 Java 中,有些原始类型(int、bool、double、char)不是正确的对象。这就是为什么 Java 必须引入 Integer、Boolean、Double 和 Character 作为第一类类型的原因。对于初学者来说,这可能很难教 - 为什么原始类型和类必须并存并不明显。

这也意味着一个对象的类本身就是一个对象。这与 C++ 不同,在中,类在运行时并不总是具有不同的存在。

type 是对象,它有方法、属性和类型。2type 'int'

>>> type(2)
<class 'int'>

内置类型的类型是对象。这也具有方法和属性。inttype 'type'

>>> type(type(2))
<class 'type'>

评论

1赞 Keith Pinson 3/15/2013
现代 Python 也是如此。在旧的 Python(版本 1?在我的时代之前)中,您无法继承 .因此,“旧式”与“新式类”(在 3 中,不再有旧式类)。int
2赞 Tristan Bodding-Long 2/4/2021
这在现代 python 中甚至不是真的。忽略为什么这会有用,所有按位/布尔运算符都不是第一类对象。尝试。语言语法中仍有一些位不能分配给变量,也不能用作第一类对象。dir(&)
19赞 Federico A. Ramponi 1/7/2009 #5

摘自《计算机程序的结构和解释》第2A讲(1986年)中的一张幻灯片,其中引用了克里斯托弗·斯特雷西(Christopher Stracey)的话:

一等公民的权利和特权:

  • 由变量命名。
  • 作为参数传递给过程。
  • 作为过程的值返回。
  • 合并到数据结构中
3赞 Martin 3/2/2023 #6

一个简单的理解方法是问: 什么不是“头等舱”?

在 Python 中,例如运算符喜欢或不是一流的。+*

您可以直接使用运算符:

2+2
"foo"+"bar"
2*3
"bla"*3

但是您不能将运算符分配给变量:

operator = +
operators = [+,*]

这也意味着:你不能将运算符作为函数参数传递,因为......

...操作员不是一流的。