【发布时间】:2011-09-22 20:34:24
【问题描述】:
我只是在阅读有关类的 Python 文档;它说,在 Python 中“类本身就是对象”。这与 C#、Java、Ruby 或 Smalltalk 中的类有何不同? 这类类与其他语言相比有哪些优缺点?
【问题讨论】:
我只是在阅读有关类的 Python 文档;它说,在 Python 中“类本身就是对象”。这与 C#、Java、Ruby 或 Smalltalk 中的类有何不同? 这类类与其他语言相比有哪些优缺点?
【问题讨论】:
在 Python 中,类是对象,您可以将它们分配给变量、将它们传递给函数等,就像任何其他对象一样。例如
>>> t = type(10)
>>> t
<type 'int'>
>>> len(t.__dict__)
55
>>> t() # construct an int
0
>>> t(10)
10
Java 有Class 对象,它们提供了一些关于类的信息,但是你不能用它们来代替明确的类名。它们不是真正的类,只是类信息结构。
Class C = x.getClass();
new C(); // won't work
【讨论】:
声明一个类就是声明一个变量:
class foo(object):
def bar(self): pass
print foo # <class '__main__.foo'>
它们可以像任何变量一样被分配和存储:
class foo(object):
pass
class bar(object):
pass
baz = bar # simple variable assignment
items = [foo, bar]
my_foo = items[0]() # creates a foo
for x in (foo, bar): # create one of each type
print x()
并作为变量传递:
class foo(object):
def __init__(self):
print "created foo"
def func(f):
f()
func(foo)
它们可以由函数创建,包括基类列表:
def func(base_class, var):
class cls(base_class):
def g(self):
print var
return cls
class my_base(object):
def f(self): print "hello"
new_class = func(my_base, 10)
obj = new_class()
obj.f() # hello
obj.g() # 10
相比之下,Java 中的类有代表它们的对象,例如。 String.class,类名本身——String——不是一个对象,不能作为一个对象来操作。这是静态类型语言所固有的。
【讨论】:
在 C# 和 Java 中,类不是对象。它们是类型,在这些语言是静态类型的意义上。确实,您可以获得代表特定类的对象 - 但这与类本身不同。
在 python 中,看起来像一个类的东西实际上也是一个对象。
它的解释 here 比我做的要好得多:)
【讨论】:
主要区别在于它们意味着您可以轻松地将类作为对象进行操作。 Java 中提供了相同的功能,您可以在其中使用Class 的方法来获取有关对象类的信息。在 Python、Ruby 和 Smalltalk 等语言中,语言的动态特性让您可以“打开”类并对其进行更改,这有时被称为“猴子补丁”。
就我个人而言,我不认为这些差异有什么大不了的,但我相信我们可以就此展开一场好的宗教战争。
【讨论】:
类是对象,因为它们可以像任何对象一样在 Python 代码中进行操作。其他人已经展示了如何将它们传递给函数,允许它们像任何对象一样被操作。您可以这样做:
class Foo(object):
pass
f = Foo()
f.a = "a" # assigns attribute on instance f
Foo.b = "b" # assigns attribute on class Foo, and thus on all instances including f
print f.a, f.b
其次,像所有对象一样,类在运行时被实例化。也就是说,类定义是执行的代码,而不是在运行之前编译的结构。这意味着一个类可以“烘焙”只有在程序运行时才知道的东西,例如环境变量或用户输入。这些在声明类时被评估一次,然后成为类的一部分。这与需要以不同方式实现此类行为的编译语言(如 C#)不同。
最后,类和任何对象一样,都是由类构建的。正如一个对象是从一个类构建的一样,一个类也是从一种称为元类的特殊类构建的。您可以编写自己的元类来更改类的定义方式。
【讨论】:
类作为对象的另一个优点是对象可以在运行时改变它们的类:
>>> class MyClass(object):
... def foo(self):
... print "Yo There! I'm a MyCLass-Object!"
...
>>> class YourClass(object):
... def foo(self):
... print "Guess what?! I'm a YourClass-Object!"
...
>>> o = MyClass()
>>> o.foo()
Yo There! I'm a MyCLass-Object!
>>> o.__class__ = YourClass
>>> o.foo()
Guess what?! I'm a YourClass-Object!
对象有一个特殊的属性__class__,它指向它们作为实例的类。这是可能的,因为类本身就是对象,因此可以绑定到像__class__ 这样的属性。
【讨论】:
由于这个问题有一个 Smalltalk 标签,这个答案是从 Smalltalk 的角度来看的。在面向对象编程中,事情是通过消息传递来完成的。您向对象发送消息,如果对象理解该消息,它将执行相应的方法并返回一个值。但是首先如何创建对象?如果为创建对象引入了特殊语法,这将破坏基于消息传递的简单语法。这就是在 Java 等语言中发生的情况:
p = new Point(10, 20); // Creates a new Point object with the help of a special keyword - new.
p.draw(); // Sends the message `draw` to the Point object.
从上面的代码可以看出,该语言有两种完成工作的方式——一种是命令式的,另一种是面向对象的。相比之下,Smalltalk 具有仅基于消息传递的一致语法:
p := Point new: 10 y: 20.
p draw.
这里的new 是一个消息发送到一个名为Point 的单例对象,它是Metaclass 的一个实例。除了为语言提供一致的计算模型外,元类还允许对类进行动态修改。例如,以下语句将向Point 类添加一个新的实例变量,而无需重新编译或重新启动 VM:
Point addInstVarName: 'z'.
关于这个主题的最佳阅读是The Art of the Metaobject Protocol。
【讨论】: