【问题标题】:What is meant by "classes themselves are objects"?“类本身就是对象”是什么意思?
【发布时间】:2011-09-22 20:34:24
【问题描述】:

我只是在阅读有关类的 Python 文档;它说,在 Python 中“类本身就是对象”。这与 C#、Java、Ruby 或 Smalltalk 中的类有何不同? 这类类与其他语言相比有哪些优缺点?

【问题讨论】:

    标签: python class oop object


    【解决方案1】:

    在 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
    

    【讨论】:

    • 在java中你可以这样创建一个类的新实例:Object o = C.newInstance();
    【解决方案2】:

    声明一个类就是声明一个变量:

    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——不是一个对象,不能作为一个对象来操作。这是静态类型语言所固有的。

    【讨论】:

      【解决方案3】:

      在 C# 和 Java 中,类不是对象。它们是类型,在这些语言是静态类型的意义上。确实,您可以获得代表特定类的对象 - 但这与类本身不同。

      在 python 中,看起来像一个类的东西实际上也是一个对象。

      它的解释 here 比我做的要好得多:)

      【讨论】:

        【解决方案4】:

        主要区别在于它们意味着您可以轻松地将类作为对象进行操作。 Java 中提供了相同的功能,您可以在其中使用Class 的方法来获取有关对象类的信息。在 Python、Ruby 和 Smalltalk 等语言中,语言的动态特性让您可以“打开”类并对其进行更改,这有时被称为“猴子补丁”。

        就我个人而言,我不认为这些差异有什么大不了的,但我相信我们可以就此展开一场好的宗教战争。

        【讨论】:

          【解决方案5】:

          类是对象,因为它们可以像任何对象一样在 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#)不同。

          最后,类和任何对象一样,都是由类构建的。正如一个对象是从一个类构建的一样,一个类也是从一种称为元类的特殊类构建的。您可以编写自己的元类来更改类的定义方式。

          【讨论】:

            【解决方案6】:

            类作为对象的另一个优点是对象可以在运行时改变它们的类:

            >>> 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__ 这样的属性。

            【讨论】:

              【解决方案7】:

              由于这个问题有一个 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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-02-16
                • 1970-01-01
                • 2011-06-12
                相关资源
                最近更新 更多