Python中的内置关键字类型是指函数还是类?

4

在大多数帖子中,人们经常说,如果type只有一个参数,那么它是一个内置函数,如果有三个参数,则是一个元类。

但在Python文档中,type的签名为:

class type(object)
class type(name, bases, dict)

那么,这是否意味着type是一个内置的类而不是内置的函数,即使它只提供了一个参数?


1
它不能同时是两者,但当传递一个参数时,它的行为类似于函数。 - Ry-
我认为这应该是你的答案:https://docs.python.org/3/library/stdtypes.html#bltin-type-objects - Abend
1
type 不是一个关键字。例如,forinas 是关键字。你不能将变量命名为 for,但可以将变量命名为 type(合法但强烈不建议!)。 - Paul Cornelius
3个回答

6

type 被称为“元类”,因为它是一个产生其他类(也称为类型)的类。它的行为就像一个普通的类。特别地,它具有相当于 Python 中这样的 __new__ 方法:

class type(object):

    def __new__(cls, *args):
        num_args = len(args)

        if num_args not in (1, 3):
            raise TypeError('type() takes 1 or 3 arguments')

        # type(x)
        if num_args == 1:
            return args[0].__class__

        # type(name, bases, dict)
        name, bases, attributes = args
        bases = bases or (object,)

        class Type(*bases):
            pass

        Type.__name__ = name

        qualpath = Type.__qualname__.rsplit('.', 1)[0]
        Type.__qualname__ = '.'.join((qualpath, name))

        for name, value in attributes.items():
            setattr(Type, name, value)

        return Type

Class = type('Class', (), {'i': 1})
instance = Class()

print(type(instance))  # -> Class
print(instance.__class__)  # -> Class
print(type(type(instance)))  # -> type
print(Class.i)  # -> 1
print(instance.i)  # -> 1

注意在实例化类时,新实例的值是从__new__返回的。 对于type__new__始终返回一个类型对象(也称为类)。这是一个扩展了int以使用-1作为默认值而不是0的类的示例:
def Int__new__(cls, *args):
    if not args:
        return cls(-1)
    return super(cls, cls).__new__(cls, *args)

Int = type('Int', (int,), {'__new__': Int__new__})

i = Int()
print(type(i))  # -> Int
print(i.__class__)  # -> Int
print(type(type(i)))  # -> type
print(i)  # -> -1

j = Int(1)
print(j)  # -> 1

要深入了解 type 的工作原理,可以查看 type_new 中的 C 代码。在那里你可以看到 (向下滚动几行) type(x) 是一个特殊情况,它会立即返回 x 的类型(也就是类)。当你执行 type(name, bases, dict) 时,将会调用类型创建机器。
更有趣的是,请尝试下面的内容:
type(object)
type(type)
isinstance(object, object)
isinstance(type, object)
type(1)
type(type(1))

2
Python中类和函数之间的区别不像其他语言那样明显。
您可以使用函数调用语法来调用实际函数,也可以使用具有__call__方法的类的实例,甚至覆盖__new__的类也可以像函数一样运行。
Python用于所有这些的词是可调用对象:您可以使用调用语法(foo())调用的对象,这将计算结果。
内置的type是可调用的。它可以被调用。
有时您会像使用函数一样处理type,它会起作用,因此您可以说它是一个函数。其他时候,您会像使用类一样对待它,因此您可以说它是一个类。实际实现不应该影响。
这就是鸭子类型的作用:如果它走起路来像只鸭子,叫起来像只鸭子,那么它一定是只鸭子。

2
所有类都是可调用的,无论它们是否覆盖了__new__。这个问题涉及到内置的type。鸭子类型是根据对象的行为而不是继承来分类的原则。与此无关。 - Paul Cornelius

1
内置的type函数总是返回一个类型对象,它基本上是一个类。无论是单参数形式还是三参数形式,都是如此。在单参数情况下,返回的对象是参数的类型(类)。在三个参数的情况下,返回的对象是一个新的类型对象(类)。在两种情况下,返回的对象都可以用来实例化新的对象(类的实例)。
有些类可以用作元类。这是使用type的三个参数形式的常见用例。但是,还有其他方法可以创建可用作元类的类,并且type的三个参数形式也有其他用途。
这与int并没有太大的区别,int是一个内置函数,返回一个int类型的对象。 int也是一个类的名称,可以用来创建新的对象:
>>> x = int()
>>> x
0
>>> type(x)
<class 'int'>

而且像类型一样,它有不止一种形式:

>>> y = int("A", 16)
>>> y
10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接