不多说,一图流
咳咳,正经的解释一下,首先这是一个很经典的问题。我们此处假设题主对面向对象以及建模不够了解,先说一说这个类与对象的基本概念(如果这部分已经了解的话可以直接跳到本回答的“当类与对象遇到 Python”部分)。
首先一个最典型的例子,设想一个国家有这么几个人:
通过这么一看,这三位看起来都有个共同的特点——都是人。没错,先别吐槽,我知道这是一句废话,但是咱们接下来用逻辑视角来尝试推演这个例子:
这实际上就是一种面向对象的思维方式。让我们回到这个问题上来——“何谓类与对象”?结合上面的例子应该是这样的:
这就是一个对类与对象最为简单的诠释。
然后我们再来看看对“类”的正经定义(来自英文维基: Class (knowledge representation) )
In knowledge representation, a class is a collection of individuals or objects. A class can be defined either by extension (specifying members), or by intension (specifying conditions), using what is called in some ontology languages like OWL. According to the Type–token distinction, the ontology is divided into individuals, who are real worlds objects, or events, and types, or classes, who are sets of real world objects. Class expressions or definitions gives the properties that the individuals must fulfill to be members of the class. Individuals that fulfill the property are called Instances.
其中比较重要的内容包含:
简单来说,类定义了一类个体和对象的概念,而对象则是这一概念下符合其模式的个体。
说到这里需要明确,类和对象本质上是一个无处不在的抽象概念,和包括 Python 在内的任何一门具体的高级语言或者建模工具无必然联系。换言之,只要有定义,有概念,就足以形成类(Class),而当一个个体满足类所描述的模式时,这一个体即为对象(Object)。
而当提到面向对象的概念,大家最熟悉的可能还是基于代码的形态,例如在 Java 中(此处部分写法并不标准,仅作示意用)
// definition of class Person public class Person { public final String name; public final String gender; public final String preference; public final int age; public final int height; public Person(String name, String gender, String preference, int age, int height) { this.name = name; this.gender = gender; this.preference = preference; this.age = age; this.height = height; } } // instantiation zhangSan = Person("Zhang San", "Male", "Female", 29, 173) liSi = Person("Li Si", "Male", "Anything", 32, 182) wangWu = Person("Wang Wu", "Female", "Male", 40, 165)
以及在 Python 中
# definition of class Person class Person: def __init__(self, name, gender, preference, age, height): self.name = name self.gender = gender self.preference = preference self.age = age self.height = height # instantiation zhang_san = Person("Zhang San", "Male", "Female", 29, 173) li_si = Person("Li Si", "Male", "Anything", 32, 182) wang_wu = Person("Wang Wu", "Female", "Male", 40, 165)
都是对上述例子的一种语言表示,也是我们所常说的类与对象。而在 Java 与 Python 中更多的例子与讲解可以参考这里:
先说结论:
dict
类型类似的映射结构比如通过这样的方式,就能知道一个对象里面都有啥,其中dir
函数可以展示一个类内部所包含的全部字段,__dict__
属性可以近似地视为包含主要属性,如下代码所示
class T: def __init__(self, x, y, z): self.x = x self._y = y self.__z = z def one_method(self, t): return self.x + self._y + self.__z + t t = T(1, 2, 3) print(dir(t)) print(set(dir(t)) - set(dir(object()))) print(t.__dict__) # ['_T__z', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_y', 'one_method', 'x'] # {'__weakref__', '__module__', '_y', '__dict__', 'x', '_T__z', 'one_method'} # {'x': 1, '_y': 2, '_T__z': 3}
没错,实际上在Python中,无论是方法还是属性(包括私有属性在内),本质上是差不多的,都是挂载在对象上的一个键值对。而当你去尝试调用一个对象的方法时,实际上也是在向该对象获取方法可执行对象(可以近似地理解为一个函数),然后再执行。
在上面的示例代码中,公有(public)和保护(protected)属性x
和_y
直接存在于对象中,私有属性__z
实质上以_T__z
的形式存在于对象中,连包括__init__
、one_method
在内的各个方法也均被包含在dir
函数的结果之内,此等现象足以大致说明Python对象的本质。
关于这部分其实学问还是很深的,OpenIDLab的研发人员也对这部分进行过一些微小的研究,欢迎进一步阅读。