机器学习之python基础(五)
综述
这一系列博客是记录我在学习python和机器学习的过程中的一些实践过程和体会,学习python时用到的参考书籍是《python学习手册 第四版》,即《learning python》的中文版。学习机器学习时所用的主要参考书籍是《机器学习实战》,还参考了CSDN博客平台上博客名为zouxy09的部分博客文章(博客后面附有url链接),实现其中的各种算法所使用的程序语言是python,实验平台是Ubuntu14.04,所使用的python版本是2.7.6。如果有博友想要与我进行交流可以在博客后面留言,或者发邮件到我的邮箱zouchaobin@foxmail.com。由于python3.0以后的版本与python3.0之前的版本有较大改变,所以为了某些代码的兼容性(如print函数),也为了便于直接使用《python学习手册》中的源代码(这本书的源代码是基于python3.x的),我决定采用以下处理方式:
from __future__ import print_function from __future__ import division
在每个代码文件的开头加入以上两行代码,这样的话就可以使用python3.x的print函数和除法运算了,这样便于将这些代码稍加修改就能移植到python3.x的平台上。
python类
在python中,面向对象程序设计(OOP)完全是可选的,并且在初学阶段不需要使用类(class),不使用类也可以做许多事情,并且可以快速开发和维护,但是实际上类可以大量减少开发时间,对于那些需要长期维护的大型软件来说是必要的。类可以被继承,python中的超类(C++中的基类)与子类(C++中的派生类)是继承和派生的关系,可以最大程度上重用代码;可以将许多类型组合到一起成为新的类型;可以重载运算符,在最大程度上满足用户的需求。
python中的类使用起来十分简单明了,没有太多的语法杂质,复杂性比C++/java等大大降低,python中大多数类的使用都可以简化成以下表达式:
objec.attribute
上面整个语句在整个执行过程中等同于:找出attribute首次出现的地方,先搜索object,然后是该对象之上的所有类,从下至上,从左至右。换句话说,取出属性只是简单地搜索“树”而已。
如下图所示:
I1,I2是类C1的子类,C1是超类C2和超类C3的子类,C1继承了C2和C3的所有属性,I1和I2继承了C1的所有属性,那么在这个树中,当I2调用object.attribute进行属性搜索时的搜索顺序为:I2,C1,C2,C3,I1则为I1,C1,C2,C3。如下所示:
I1.x和I2.x两者都会在C1中找到x并停止搜索,因为C1比C2位置更低(事实上C1已经重新定义了x属性来取代了从C2中继承的属性x)。
I1.y和I2.y两者都会在C1中找到y,因为这里是y唯一出现的地方。
I1.z和I2.z两者都会在C2中找到z,因为C2比C3更靠左。
I2.name会找到I2中的name,不需要“爬树”。
编写类树:
1,每个class语句会生成一个新的类对象。
2,每次类调用时,就会产生一个新的实例对象。
3,实例自动连接至创建了这些实例的类。
4,类连接至超类的方式是将超类列在类头部的括号内,其从左至右的顺序会决定树中的次序。
下面是一个简单的类实验:
类person的定义如下:
person类包含名字和年龄两个属性,采用了__init__函数来构造对象。class person: def __init__(self, n, a): self.name = n self.age = a def set_name(self,n): self.name = n def set_age(self,a): self.age = a def display(self): print('name:', self.name, 'age:', self.age, sep=' ')
运行结果如下:# -*- coding: utf-8 -*- from __future__ import print_function from __future__ import division from class_person import person p = person('Tom', 22) p.display() p.set_name('Bob') p.set_age(23) print(p.name) print(p.age)
类最大的优点体现在代码的重用上,代码的重用在类中体现为类的继承,但是需要注意的是类的封装性要好。本类的变量原则上只能由本类的属性方法可以直接访问,其继承类(子类)要想访问超类(基类)的变量必须通过属性方法来访问,而不可以直接操作,这样可以有更好的封装性。下面这个实例说明了类的继承方式和方法,首先有一个超类Person,这个超类有2个子类Staff和Student,这2个子类又有一个公共的子类Staff_student,继承关系如下图所示:
下面分别是4个类的源代码:
# -*- coding: utf-8 -*- class Person: def __init__(self, n, a): self.name = n self.age = a def set_name(self,n): self.name = n def get_name(self): return(self.name) def set_age(self,a): self.age = a def get_age(self): return(self.age) def display(self): print('name:',self.name) print('age',self.age)
<pre name="code" class="python"># -*- coding: utf-8 -*- from class_person import Person class Staff(Person): def __init__(self,n,a,j,p): #继承的属性 self.person = Person(n, a) #新的属性 self.job = j self.pay = p def set_name(self,n): self.person.set_name(n) def get_name(self): return(self.person.get_name()) def set_age(self,a): self.person.set_age(a) def get_age(self): return(self.person.get_age()) def set_job(self, j): self.job = j def get_job(self): return(self.job) def set_pay(self, p): self.pay = p def get_pay(self): return(self.pay) def display(self): self.person.display() print('job:',self.job) print('pay:',self.pay)
# -*- coding: utf-8 -*- from class_person import Person class Student(Person): def __init__(self, n, a, m, s): #继承的属性 self.person = Person(n, a) #新的属性 self.major = m self.school = s def set_name(self,n): self.person.set_name(n) def get_name(self): return(self.person.get_name()) def set_age(self,a): self.person.set_age(a) def get_age(self): return(self.person.get_age()) def set_major(self,m): self.major = m def get_major(self): return(self.major) def set_school(self,s): self.school = s def get_school(self): return(self.school) def display(self): self.person.display() print('major:', self.major) print('school:', self.school)
# -*- coding: utf-8 -*- from class_staff import Staff from class_student import Student class Staff_student(Staff, Student): def __init__(self, n, a, j, p, m, s, m_s): #继承的属性 self.staff = Staff(n,a,j,p) self.student = Student(n,a,m,s) #新的属性 self.marry_status = m_s def set_name(self,n): self.staff.set_name(n) def get_name(self): return(self.staff.get_name()) def set_age(self,a): self.staff.set_age(a) def get_age(self): return(self.staff.get_age()) def set_job(self, j): self.staff.set_job(j) def get_job(self): return(self.staff.get_job()) def set_pay(self, p): self.staff.set_pay(p) def get_pay(self): return(self.staff.get_pay()) def set_major(self,m): self.student.set_major(self,m) def get_major(self): return(self.student.get_major()) def set_school(self,s): self.student.set_school(s) def get_school(self): return(self.student.get_school()) def set_marry_status(self, yes_or_no): self.marry_status = yes_or_no def get_marry_status(self, yes_or_no): return(self.marry_status) def display(self): self.staff.display() self.student.display() print("marry status:", self.marry_status)
测试程序如下:
<pre name="code" class="python"># -*- coding: utf-8 -*- from __future__ import print_function from __future__ import division print('----------------') print("staff:") from class_staff import Staff sta = Staff('Tom', 22, 'teacher', 2000) sta.display() sta.set_name('Tom Tomas') sta.set_job('engineer') sta.set_pay(40000) print(">>>>after modifing...") sta.display() print('----------------') print("student:") from class_student import Student stu = Student('Bob', 23, 'Automation', 'UESTC') stu.display() stu.set_name('Bob J') stu.set_age(18) stu.set_school('USTC') print(">>>>after modifing...") stu.display() print('----------------') print("staff_student:") from class_staff_student import Staff_student sta_stu = Staff_student('Merry', 25, 'teacher', 3000, 'Automation', 'UESTC', 'no') sta_stu.display() sta_stu.set_name('Merry Obama') sta_stu.set_age(28) sta_stu.set_job('professor') sta_stu.set_pay(100000) sta_stu.set_marry_status('yes') print(">>>>after modifing...") sta_stu.display()
在我看来,每一个类都应该受到保护,不能在类外直接访问类的成员或属性,应该通过类定义的属性方法来访问和修改。比如上面在类中如果要访问name属性,则应该通过get_name依次往上访问到Person内部的name属性。
以下是运行结果:
python中的类同样还有许多的高级方法,但作为基础学习此处按下不表,更多有关python类的学习请参考《python学习手册》第四版。