实例化一个类 - 有括号和无括号的区别

15

假设我有一个非常简单的类,如下所示:

class myClass:
    def __init__(self): 
        self.myProp = 2

如果我使用括号进行实例化,一切都按照我的期望工作:

>>> a = myClass()
>>> a.myProp
2

然而,如果在上述两行中我不使用括号,即:

>>> a = myClass

我遇到了以下错误:

>>> a.myProp
Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
a.myProp
AttributeError: class myClass has no attribute 'myProp'

如果我打印这个对象,

>>> a = myClass
>>> a

我理解

<class __main__.myClass at 0x0275C538>
似乎 `a` 是该类的实例,但某种方式没有初始化。在其他语言中,如果尝试将一个未初始化的类实例转换为对象,则会出现编译错误(例如,在 C# 中,`myClass a = new myClass();` 可以正常工作,但是 `myClass a = new myClass;` 会返回编译错误)。因此,我的问题是:从技术角度来讲,没有括号的 `a = myClass` 对象是什么?

不,它不是类的实例,它是类对象本身 - jonrsharpe
3个回答

14

a是类本身 -- 在Python中,类是一等对象1。你可以将它们作为参数传递,将它们别名为不同的名称(就像你在示例中所做的那样),然后你可以从当前命名空间中任何引用创建实例。

a = myClass  # a and myClass identical at this point.  The interpretter won't care which you use.
a_instance = a()  # instance of myClass

def make_instance(cls):
    return cls()

another_instance = make_instance(a)
yet_another_instance = make_instance(myClass)

你看,Python没有任何“编译时检查”,因为实际上——它根本没有编译时。Python代码在运行时解释执行。确实,当你导入某些东西时,可能会出现SyntaxError,但这仍然是在运行时发生的。
注:1. 此处无双关语。

这对我来说很有意义,因为它确实回答了我的问题,我会尽快接受它(SO仍然禁止我)。但我想问一下:有什么有用的方面吗?我的意思是,为什么我要将一个类转换为变量?我问这个问题是因为我无法清楚地想象它,并且希望通过一个简单的解释性示例来了解它。 - Matteo NNZ
2
@MatteoNNZ - 你不需要将一个类“转换为对象”;在Python中,类本身就是对象,包括函数、方法和字面量等。至于为什么要将类对象作为参数传递,可以考虑使用map的示例:map(str, [1, 2, 3])str就像myClass一样是一个类对象,在这种情况下用于从整数列表构建str实例的列表。 - user2555451
1
在将变量设置为类时,不涉及“强制转换”。实际上,类名只是另一个变量。MyClass没有任何特殊之处,它也适用于a。我经常使用这个功能,例如,我可以创建几个实现相同问题的不同算法的类,并传递函数我想要执行计算的类,以便函数可以专注于收集输入和输出。 - wkschwartz
感谢 @iCodez 和 wkschwartz 的解释,现在事情更清晰了。 - Matteo NNZ

11

它是对类本身的引用,而不是对类的实例的引用。注意区别:

>>> a = myClass
>>> a
<class __main__.myClass at 0x10cd1de20>
>>> b = myClass()
>>> b
<__main__.myClass instance at 0x10cd8efc8>

3

Python中的所有内容都是对象,因此都是类的实例,包括类本身。操作类或将其作为变量传递并没有什么特别之处。因此,您的变量aMyClass引用同一个对象,即MyClass对象。

>>> class R: pass # In Python 2, you would need class R(object): pass
>>> r = R()

现在我们有两个变量,Rrr是类R的一个实例。关键在于R是类type的一个实例,这就是为什么我们称R为类的原因。同时rR都是object类的实例,这就是为什么我们把它们都称作对象。而且Robject类的一个子类,因为R是一个类。
>>> isinstance(R, type)
True
>>> isinstance(r, R)
True
>>> issubclass(R, object)
True
>>> isinstance(r, object)
True
>>> isinstance(type, object)
True
>>> isinstance(type, type)
True

每个Python对象都是object的一个实例,每个Python类都是object的子类,同时每个Python类也是type的一个实例。
需要注意的是,我所说的情况适用于Python 3以及Python 2中的“新式”类。不必考虑Python旧式类。

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