Python网络爬虫技术与实战
上QQ阅读APP看书,第一时间看更新

1.9.1 类和对象

面向对象的思想中提出了两个概念,即类和对象。类是对某一类事物的抽象描述,是一种抽象的数据类型,一种模板。而对象用于表示现实中该类事物的个体,也就是具体化了类的描述。它们的关系是,对象是类的具体实例,类是对象的模板。对象根据类创建,一个类可以创建多个对象。比如定义了一个学生类,那么通过类创建出来的小明、小王就叫对象。

1.类的定义

在Python中使用class关键字定义一个类,类的主体由属性(变量)和方法(函数)组成。首先,通过定义一个学生类来学习一下Python类的定义方法。

【例1-90】用Python定义一个学生类


# -*- coding:utf-8 -*-
# 类的创建
class Student(object):
    count = 0                       # 类属性
    
    def __init__(self, name, age):  # __init__为类的构造函数
        self.name = name            # 实例属性
        self.age = age              # 实例属性

    def output(self):                      # 实例方法
        print self.name
        print self.age

上述例子中Student是类名,__init__()函数是构造函数,count、name、age是类中定义的属性,output(self)是类中定义的方法。

2.对象的创建和使用

定义完Student类之后,就可以创建对象。一个对象被创建后,会包含3个方面的特性:对象的句柄、属性和方法。对象的句柄用于区分不同的对象,当对象被创建后,该对象会获取一块存储空间,存储空间的地址即为对象的标识。Python创建对象的方法是通过类名加圆括号的方式。

【例1-91】Student类的实例化


#类的创建
class Student(object):
    count = 0                              # 类属性
    
    def __init__(self, name, age):         # __init__为类的构造函数
        self.name = name                   # 实例属性
        self.age = age                     # 实例属性

    def output(self):                      # 实例方法
        print self.name
        print self.age
       
if __name__ == '__main__':
    stu1 = Student('Zhangsan',18)          # 使用Student类对象stu1
    print "stu1.name = %s" % (stu1.name,)  # 输出stu1.name = Zhangsan
    print "stu1.age = %d" % (stu1.age,)    # 输出stu1.age = 18
    stu1.output()                          # 利用对象stu1调用output方法

实例化对象之后,就可以通过对象直接调用对象的属性和方法。但需要注意的是,对象调用方法时,不需要给参数self赋值,self参数用于表示指向实例对象本身。上述的例子中仅介绍了类的基本实例属性和实例方法的定义,实际上实例变量还区分私有属性和公有属性,还有类变量等概念。同时类中的方法还包括静态方法、类方法。

3.类属性和实例属性

类的属性是对数据的封装,类中定义的属性包括实例属性、类属性两种。上述例1-91中count变量属于类属性,name、age属于实例属性。类变量可以在该类的所有实例中被共享。二者在定义和使用上的区别主要如下:

1)类属性定义在类中,实例属性通常定义在构造函数__init__内。


class Student(object):
    count = 0                              # 类属性
    
    def __init__(self, name, age):         # __init__为类的构造函数
        self.name = name                   # 实例属性
        self.age = age                     # 实例属性

2)类属性属于类本身,可以通过类名进行访问/修改。


# 类的创建
class Student(object):
    count = 0   # 类属性
        
if __name__ == '__main__':
    Student.count = 100
    print "Student.count = %d" % (Student.count,) # 输出Student.count = 100

3)类属性也可以被类的所有实例访问/修改。


# -*- coding:utf-8 -*-
# 类的创建
class Student(object):
    count = 0                                  # 类属性
    
    def __init__(self, name, age):             # __init__为类的构造函数
        self.name = name                       # 实例属性
        self.age = age                         # 实例属性
      
if __name__ == '__main__':
    stu1 = Student('Zhangsan',18)              # 使用Student类对象stu1
    stu1.count = 100
    print "stu1.count = %s" % (stu1.count,)    # 对象stu1获取类属性,stu1.count = 100

4)实例属性只能通过实例访问。


# -*- coding:utf-8 -*-

# 类的创建
class Student(object):
    count = 0                                  # 类属性
    
    def __init__(self, name, age):             #__init__为类的构造函数
        self.name = name                       # 实例属性
        self.age = age                         # 实例属性
      
if __name__ == '__main__':
    stu1 = Student('Zhangsan',18)              # 使用Student类对象stu1
    print "stu1.age = %d" % (stu1.age,)        # 利用stu1获取实例属性,stu1.age = 18
    #print "Student.age = %d" % (Student.age,) # 报错,不能通过类直接访问实例属性

5)当类属性与实例属性名称相同时,如果一个实例访问这个属性,那么实例属性会覆盖类属性,而当类访问时则不会。


# -*- coding:utf-8 -*-

# 类的创建
class Student(object):
    name = "Xiaoming"                          # 类属性
    
    def __init__(self, name, age):             # __init__为类的构造函数
        self.name = name                       # 实例属性
        self.age = age                         # 实例属性
      
if __name__ == '__main__':
    stu1 = Student('Zhangsan',18)                # 使用Student类对象stu1
    print "stu1.name = %s" % (stu1.name,)        # 输出Zhangsan
    print "Student.name = %s" % (Student.name,)  # 输出Xiaoming

4.实例方法、类方法和静态方法

自定义的一个类中,可能出现三种方法,即实例方法、静态方法和类方法,下面来看一下三种方法的定义和使用区别。

(1)实例方法

实例方法的第一个参数必须是“self”,实例方法只能通过对象调用。


# -*- coding:utf-8 -*-

# 类的创建
class Student(object):
    count = 0                                    # 类属性
    
    def __init__(self, name, age):               # __init__为类的构造函数
        self.name = name                         # 实例属性
        self.age = age                           # 实例属性

    def output(self):                            # 实例方法
        print self.name, self.age
        
if __name__ == '__main__':
    stu1 = Student('Zhangsan',18)                # 使用Student类对象stu1
    stu1.output()                                # 利用对象stu1调用output方法

其中,output()方法即为实例方法,必须带一个参数self,调用时不必给该参数赋值。

(2)类方法

类方法是将类本身作为操作对象的方法。类方法可以使用函数classmethod()或@classmethod修饰器定义。与实例方法不同的是,其将类作为第一个参数(cls)传递。类方法可以通过类名调用,也可以通过对象调用。代码如下:


# -*- coding:utf-8 -*-

# 类的创建
class Student(object):
    count = 0                                    # 类属性
    
    def __init__(self, name, age):               # __init__为类的构造函数
        self.name = name                         # 实例属性
        self.age = age                           # 实例属性
    
    @classmethod              # 方法一,定义类方法,调用类变量,getPrice中不带self参数
    def getCount(cls):
print cls.count

    def getCount2(cls):
        print cls.count
    tran_getCount2 = classmethod(getCount2)   # 方法二,定义类方法,调用类变量 
        
if __name__ == '__main__':
    Student.getCount()                        # 使用类名直接调用类方法
    stu1 = Student('Zhangsan',18)             # 使用Student类对象stu1
    stu1.getCount() # 利用对象stu1调用类方法

可见,类方法的使用和静态方法十分相似。如果某个方法需要被其他实例共享,同时又需要使用当前实例的属性,则定义为类方法。

(3)静态方法

静态方法使用函数classmethod()或@classmethod修饰器定义。定义和使用方式如下:


# -*- coding:utf-8 -*-

# 类的创建
class Student(object):
    count = 0                                 # 类属性
    
    def __init__(self, name, age):            # __init__为类的构造函数
        self.name = name                      # 实例属性
        self.age = age                        # 实例属性
    
    @staticmethod             # 方法一,定义类方法,调用类变量,getPrice中不带self参数
    def getCount():
        print Student.count

    def getCount2():
        print Student.count
    tran_getCount2 = staticmethod(getCount2)  # 方法二,定义类方法,调用类变量 
        
if __name__ == '__main__': 
    Student.getCount()                        # 使用类名直接调用静态方法
    stu1 = Student('Zhangsan',18)             # 使用Student类对象stu1
    stu1.getCount()                           # 利用对象stu1调用静态方法

这三种方法的主要区别在于参数,实例方法被绑定到一个实例,只能通过实例进行调用;但是对于静态方法和类方法,则可以通过类名和对象两种方式进行调用。