一、定义和使用类
1.类的定义
在面向对象的程序设计中,类是创建对象的基础,描述了所创建对象共有的属性和方法。它同时也有接口和结构,接口可以通过方法与类或对象进行互操作,而结构表现出一个对象中有什么样的属性。这些都为面向对象编程的3个最重要的特性(封装性、继承性、多态性)提供了实现手段。
类的定义就像函数定义,只是用class语句替代了def语句,同样是在执行class的整段代码后这个类才会生效。进入类定义部分后,会创建出一个新的局部作用域,后面定义的类的数据属性和函数方法都是属于此作用域的局部变量。
2.类的使用
定义一个类,格式如下。
class 类名:
属性列表
方法列表
在用class语句创建类时,只要把所需的属性列表和方法列表列出即可。
>>>class Cat():
... """一次模拟猫咪的简单尝试"""
... name = 'tesila' # 属性
... age = 3 # 方法
... def sleep(self):
... """模拟猫咪被命令睡觉"""
... print('%d岁的%s正在沙发上睡懒觉。'%(self.age, self.name))
... def eat(self,food):
... """模拟猫咪被命令吃东西"""
... self.food = food
... print('%d岁的%s在吃%s'%(self.age, self.name,self.food))
尽管只有一些简单的方法,但是需要注意的地方比较多。首先根据约定,在Python中,首字母大写的名称指的是类(Car),这个类定义的括号中是空的,因为是从空白来创建这个类(Python 2.0中没有括号);如果名称是两个单词,那么两个单词的首字母都要大写,例如class HotDog,这种被形象地称为“驼峰式命名”;函数和方法没有区别,每个人的习惯不同而已,函数名称一般用小写字母或者下划线符号连接,如“new_car”。
最后可能发现,类的函数(方法)的参数都有一个self参数,并默认为第1个参数,这也是在编程时需要注意的地方。
二、绑定self
Python的类的方法和普通的函数有一个很明显的区别,就是类的方法必须有个额外的参数(self),并且在调用这个方法的时候不必为这个参数赋值。Python类方法的这个特别参数指代的是对象本身,而按照Python惯例,它用self来表示。
对刚才创建的类稍加修改,查看效果。
>>>class Cat():
... def sleep(self):
... print(self)
>>>new_cat = Cat()
>>>print(new_cat.sleep())
<__main__.Cat object at 0x00000000098656D8>
self代表当前对象的地址,能避免非限定调用时找不到访问对象或变量。当调用sleep等函数时,会自动把该对象的地址作为第1个参数传入;如果不传入地址,程序将不知道该访问哪个对象。
self名称也不是必需的,在Python中,self不是关键字,可以定义成a、b或其他名字。例如利用my_address代替self,一样不会出现错误。
>>>class Test:
... def prt(my_address):
... print(my_address)
... print(my_address.__class__)
>>>t = Test()
>>>t.prt()
<__main__.Test object at 0x000000000980AF60>
<class '__main__.Test'>
简而言之,self需要定义,但是在调用时会自动传入;self的名字并不是规定死的,但最好还是按照约定使用self。self总是指调用时的类的实例。
三、 掌握类的专有方法
无论任何类,都有类的专有方法,它们的特殊性由代码就能看出来,通常是用双下划线“__”开头和结尾。
访问类或者对象(实例)的属性和方法,要通过点号操作来实现,即object.attribute,当然也可以实现对属性的修改和增加。
>>>class Example():
... pass
>>>example = Example()
>>>dir(example)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>>dir(Example)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
可以看到,用dir函数可以查看类的属性和方法。由于在定义类的函数里面只有pass语句,所以列出的结果中都以双下划线“__”开头和结尾。
常用的类的专有方法
类的专有方法 | 功 能 | 类的专有方法 | 功 能 |
__init__ | 构造函数,在生成对象时调用 | __call__ | 函数调用 |
__del__ | 析构函数,释放对象时使用 | __add__ | 加运算 |
__repr__ | 打印,转换 | __sub__ | 减运算 |
__setitem__ | 按照索引赋值 | __mul__ | 乘运算 |
__getitem__ | 按照索引获取值 | __div__ | 除运算 |
__len__ | 获得长度 | __mod__ | 求余运算 |
__cmp__ | 比较运算 | __pow__ | 乘方 |
__getitem__和__setitem,像普通的方法clear、keys和values一样,它只是重定向到字典,返回字典的值。通常不用直接调用它,而使用相应的语法让Python来调用__setitem__。每个文件类型都可以拥有一个处理器类,这些类知道如何从一个特殊的类得到元数据。一旦知道了某些属性(如文件名和位置),处理器类就知道如何自动地得到其他属性。
__repr__是一个专有的方法,只有当调用repr(instance)时被调用。repr函数是一个内置函数,它用返回一个对象的字符串表示。
__cmp__在比较类实例时被调用,通常可以通过使用“==”比较任意两个Python对象,不只是类实例。
__len__在调用len(instance)时被调用。len是Python的内置函数,可以返回一个对象的长度。字符串对象返回的是字符个数;字典对象返回的是关键字的个数;列表或序列返回的是元素的个数。对于类和对象,定义__len__方法,可以自己定义长度的计算方式,然后调用len(instance),Python则会将调用定义的__len__专用方法。
__del__在调用del instance[key]时调用,它会从字典中删除单个元素。
__call__方法让一个类表现得像一个函数,可以直接调用一个类实例。
__setitem__方法可以让任何类像字典一样保存键-值对。
__getitem__方法可以让任何类表现得像一个序列。
任何定义了__cmp__方法的类都可以用==进行比较。在类的应用中,最常见的是将类实例化,再通过实例来执行类的专有方法。
四、练习
创建一个Car类,为其赋予车轮数(4)、颜色(red)的属性,并定义函数来输出“汽车有4个车轮,颜色是红色。”及“车行驶在学习的大道上。”,再调用类的方法(函数)。
参考代码:
class Car(): # 创建类
"""一次模拟汽车的简单尝试"""
wheelNum = 4 # 增加属性
color = 'red'
def getCarInfo(self,name): # 定义getCarInfo函数
self.name = name
print(self.name,'有%d个车轮, 颜色是%s。'%(self.wheelNum,self.color))
def run(self): # 定义run函数
print('车行驶在学习的大道上。')
new_car = Car() # 调用Car类
print(new_car.getCarInfo('Land Rover')) # 调用getCarInfo函数
print(new_car.run()) # 调用run函数
Python面向对象编程系列文章两周一更!
文章未经博主同意,禁止转载!