类和对象

关键字class后面跟着类名,类名通常是大写字母开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承下来的类。比如创建一个雇员类

class Employee(object):

如果Employee有父类,object的位置放父类。类的继承后面的帖子解释,父类子类的关系就是字面的意思。没有父类放object,也可以写成:

class Employee:

类起到模板的作用,创建时可以把一些认为公共的东西写进类定义中去,python通过一个特殊的__init__方法函数在创建实例时对实例进行初始化。initinitiate初始化的简写,前后都有两个下划线。两个下划线表明属于类私有,只能在类内部被访问。__init__方法函数的第一个参数永远都是self,意指创建的对象本身:

def __init__(self):

__init__方法函数的内部定义类生成的实例所应该具备的属性。雇员类Employee生成的具体雇员的属性应该跟雇员的基本信息有关,比如姓surname、名fname、工资salary、电子邮件email。既然这些属性属于对象的,那么引用时就要在前面加上指代对象本身的self,即self.surnameself.fnameself.salaryself.email。它们初始化的值由外界的实参通过形参赋进来,所以函数头的形参部分需要添加接受实参的形参:

def __init__(self, surname, fname, salary):

然后对属性进行初始化:

self.surname = surname 

属性和形参的名字不必相同。

self.email类自己内部解决(数据封装),能在类内部解决尽量在类内部解决,没有外界干扰可以降低出错的几率。

因为姓名的使用率比较高,再添加一个fullname的属性,方便后续使用。

class Employee:

    def __init__(self, surname, fname, salary):
        self.fname = fname
        self.surname = surname
        self.salary = salary
        # 形参接收实参后,对属性进行赋值

        self.fullname = self.fname + ‘ ‘ + self.surname
        # 这里用的是属性self.fname,而不是形参,只在初始化属性fname时用外面传进来的数据,之后都用类内部的数据(以属性的形式)
        self.email = self.fname + '.' + self.surname + This email address is being protected from spambots. You need JavaScript enabled to view it.'

用这个类生成对象时,会自动调用__init__这个特殊的方法函数。__init__()定义四个形参,参数self比较特殊,调用时不用给实参,所以生成对象时只需要给三个实参:

# 生成两个对象

employee1 = Employee('Harry', 'Potter', 4000)

employee2 = Employee('Bilbo', 'Baggins', 6000)

输出对象的基本信息(属性汇总),有了类就不需要在print()里每个对象都做一次信息汇总了,做成类的方法函数成为类自带的能力,需要时调用即可。

在类里定义一个汇总对象基本信息的方法函数infoSummary(),对象的方法函数的第一个参数都是self,指代对象自身。对属性的引用类外用employee1.fullname,类内的方法函数里用self.fullname

def info_summary(self):

   return '{}, {} \n{}\n'.format(self.fullname, self.salary, self.email)

在类外将汇总信息输出:

print(employee1.info_summary())

print(employee2.info_summary())

屏幕上的显示是:

Harry Potter, 4000

This email address is being protected from spambots. You need JavaScript enabled to view it.

Bilbo Baggins, 6000

This email address is being protected from spambots. You need JavaScript enabled to view it.

一般情况下,除了表现特别突出的员工,大多数员工每年涨工资的幅度是固定的,假定这个公司的涨幅为4%raiseAmount = 1.04)。公司涨幅是属于公司的,不属于个体员工,延伸到类和对象就是raiseAmount是类属性,不是对象属性。类属性在方法函数外定义,用Employee.raiseAmount引用,用在涨工资的方法函数raise_salary()里:

class Employee:

    raiseAmount = 1.04

    ……

    def raise_salary(self):

         self.salary = self.salary * Employee.raiseAmount

员工对象调用方法函数raise_salary()工资涨4%,可有一名叫比尔博(Bilbo Baggins)的员工历经千万苦拿回精灵宝钻,4%的涨幅怎好面对如此的汗马功劳!怎么说也得8%嘛。对象的属性可以在类外添加和修改(安全隐患):

employee2.raiseAmount = 1.08

这样对象employee2比尔博就有别于其他雇员对象,有了自己的对象属性raiseAmount了。如果print(employee2.raiseAmount),显示的会是1.08

那么print(employee1.raiseAmount)是多少呢?Employee类里有一个类属性raiseAmount,没有定义对象属性raiseAmount,所以employee1也没有自己的对象属性raiseAmountpython解释器的处理方法是:先找对象employee1的属性,找不到会去找employee1所属的Employee类有无raiseAmount属性,所以employ1.raiseAmount的值为1.04

比尔博的工资增长率现在是1.08,但涨工资调用方法函数raise_salary()给他加工资时用的增长率却是Employee.raiseAment,即还是1.04,可见方法函数raise_salary()内计算工资增长时的增长率用类属性是不妥的,应改成对象属性:

def raise_salary(self):

   self.salary = self.salary * self.raiseAmount

   # self.raiseAmount对象属性,对象的属性里找不到,就去类属性里找

类属性属于类所有,所有实例共享类属性。尽量避免对象属性和类属性同名,同名的情况下,对象属性会屏蔽掉类属性,有时会产生难以发现的错误。

有些情况下非得类属性不可,比如统计雇员数目的属性employeeNum,初值为0,放在初始化__init__自加1

class Employee:

   employeeNum = 0

    ……

   def __init__(self, first, surname, salary):

    ……

      Employee.employeeNum += 1

    ……

每生成一个实例(会调用方法函数初始化__init__()),类属性employeeNum会自加1,生成employee1employee2之后,Employee.employeeNum的值变为2

总结一下,一共提到了三种属性:类属性(如employeeNum);所有对象都有的属性(如framesurname……),一般在方法函数__init__定义;某个对象的专有属性(比如employ2的专有属性raiseAmount,生成对象后在类外添加。

查看类和对象的属性和方法函数可以任选以下方法:

# 简练版

print(employee1.__dict__)

print(Employee.__dict__)

print(dir(employee1))

print(dir(Employee))

# 详细全面版

print(help(Employee))

print(help(employee1))

即将推出的Python ABC教程对PythonABC视频内容进行了梳理,修正了发现的错误、对代码做了些许优化、替换掉视频中的英文注释、替换掉国内不能访问的资源……敬请关注,谢谢