用class描述一个事物
现如今,再提起面向对象,早已经是尽人皆知的概念了。因此,我们接下来的内容,并不是告诉你什么是面向对象编程,而只是尽快帮助你了解那些耳熟能详的概念在Python中的表达方式,让你尽快开始用Python处理问题。
定义Class
首先,我们创建一个表示人的class Person
:
class Person:
"""A general person class"""
要注意的是,通常,在Python里,我们会在类定义的第一行,用一对triple double quotes,给类添加一个简短的说明。你也可以不写,但是如果你写了,就要使用""" """
这样的形式,而不要写成类似:'' / "" / ''''''
这样的形式。
其次,我们给Person
添加一些属性,在Python里,这个过程是伴随着类的构造函数一起完成的:
class Person:
"""A general person class"""
def __init__(self, name, age):
self.name = name
self.age = age
在上面的例子里,有三点是值得我们注意的:
第一、__init__
是个特殊的Python方法,表示类的构造函数;
第二、在Python里,方法的第一个表示对象自身的参数是显式的,它需要明确写在方法的参数列表里。而不像Java / Swift这种编程语言,类对象方法的第一个参数是隐藏的。稍后,我们就会看到,在class
里,每个类实例方法的第一个参数,都是self
,表示执行方法的对象本身,而当它放在__init__
中时,就表示正在创建的对象;
第三,我们可以直接在__init__
方法里给self
添加属性,而无需事先声明在类定义里。稍后,我们就会看到,把属性定义在在类里面是有其它含义的;
创建并使用类对象
定义好Person
之后,我们就能像这样创建对象并访问它的属性了,其实,在之前的内容里,我们已经多次进行过类似的操作:
mars = Person('Mars', 30)
print(mars.name) # Mars
print(mars.age) # 30
访问类对象属性
实际上,除了上面这种我们最熟悉的类对象访问方式之外,Python还提供了一些自己的方法,例如,查询对象是否包含某个属性的hasattr
函数:
print(hasattr(mars, 'name')) # True
读取和设置类对象属性的get/setattr
:
print(getattr(mars, 'name')) # Mars
setattr(mars, 'name', '10')
print(getattr(mars, 'name')) # 10
另外,Python还允许我们删除类对象的属性,像这样:
delattr(mars, 'name')
print(getattr(mars, 'name'))
'''
Traceback (most recent call last):
File "/Users/puretears/Desktop/tmp/OOBasics/OOBasics", line 11, in <module>
print(getattr(mars, 'name'))
AttributeError: 'Person' object has no attribute 'name'
'''
当然,删除之后,对应的属性就不能再访问了,否则就会看到上面注释中的错误。
为类对象定义方法
接下来,我们来看如何为类对象添加方法。基本上,和之前我们提过的定义函数是一样的,只不过,类对象方法的第一个参数,必须是self
,表示执行方法的对象,在Person
的定义里,我们继续添加下面的代码:
class Person:
# ...
def wakeup(self, at):
print('{0} wake up at {1} am'.format(self.name, at))
这样,在wakeup
的实现里,由于第一个参数是self
,我们就可以用self.name
这样的形式表示类对象属性,用不带self
的名字,表示一般参数了。
然后,我们就可以直接调用wakeup
方法,只不过在调用的时候,第一个参数要写在方法外部,其实就是对象本身而已:
mars.wakeup(7)
mars.wakeup(at=7)
# Mars wake up at 7 am
定义类的析构函数
在这一节最后,我们来看Python中,如何为类定义析构函数。Python中的对象,是通过引用计数管理的,当对象的引用计数为0的时候,就会立即被释放掉。为了定义类对象在回收的时候需要额外执行的代码,我们只要定义__del__
方法就好了:
class Person:
# ...
def __del__(self):
print(self.name + ' is reclaimed.')
然后,我们用下面的代码来试一下:
mars = Person('mars', 30)
eleven = mars
print(id(mars))
print(id(eleven))
del eleven
print('only 1 ref')
del mars
执行一下,我们应该可以看到下面的结果:
'''
4363213232
4363213232
only 1 ref
mars is reclaimed.
'''
从打印出来的id
结果可以看到,mars
和eleven
确实引用的是同一个对象。然后,当我们用del eleven
删掉其中一个引用的时候,并没有触发__del__
方法,然后,执行了print
语句。最后,在执行完del mars
之后,我们看到了mars is reclaimed.。