面向对象编程python学习笔记-廖雪峰教程

面向对象的思想

和C++和JS一样,都存在一个模板(类)和实例(对象)

回顾下JS中创建对象的方式

直接用定义对象的实例:

1
2
3
4
5
6
7
dog={
name:'haha',
weight:40,
run:function(){
console.log('come on');
}
}

利用构造函数构造对象:

1
2
3
4
5
6
7
8
9
10
//利用对象传输参数
var hahaparam={
name:'haha',
weight=40
}
function dogClass(param){
this.name=paras.name
this.weight=paras.weight
}
haha=new dogClass(hahaparam)

JS就是利用对应的构造函数进行对象的创建
对于遗传多个对象,这里JS就用到了原型式继承(prototype inheritance)
JS利用这个可以减少函数的重复构建占用内存

具体的例子(来自 Head First JavaScript 程序设计 中的一个例子):

基础例子利用prototype将函数和变量拆分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Dog(name,breed,weight){
this.name=name;
this.breed=breed;
this.weight=weight;
};
Dog.prototype.species="Canine";
Dog.prototype.bark=function(){
if(this.weight>25){
console.log(this.name+"says Woof!");
}esle{
console.log(this.name+"says Yip!");
}
};
Dog.prototype.run=function(){
console.log("Run!");
}
Dog.prototype.wag-=function(){
console.log("Wag!");
};
var fido=new Dog("Fido","Mixed",38);
var fluffy=new DOg("Fluffy","Poodle",10);

fido.bark();
fluffy.bark();

fido.run();
fluffy.run();

原型式继承的应用:
如果以上面的Dog为基础变成表演犬,则只需继承即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function ShowDog(name,breed,weight,handler){
this.name=name;
this.breed=breed;
this.weight=weight;
this.handler=handler;
}
//这一句ShowDog就包含了上述Dog的run,bark,wag的方法属性
ShowDog=new Dog();
//定义属于自己的方法拓展
ShowDog.prototype.stack=function(){
console.log("Stack");
};
//最后要更正对应的容器关系
ShowDog.prototype.constructor=ShowDog;

值得一提的是上述的JS创建对象和操作对象都和C++一样有个this指针必须指向当前的对象

python对象的创建

简单的创建类

python对象的创建其实和JS中的构造函数一样(只不过叫做类,需要加个关键字class),例化对象的时候就像JS里面的构造函数例化函数一样,
来个简单的例子:

1
2
3
4
5
6
7
8
class Dog(object):
def __init__(self,name,weight,**params):
self.name=name
self.weight=weight
for k v in param.items():
setattr(self,k,v)

fido=Dog('fido',40,bark='Bark')

上面这个例子对于python的对象例化其实体现的十分清楚:

  1. 类的关键字是class,类名后面的小括号表示其父类(超类)的继承,简而言之 类名+(继承的父类)
  2. 每个类一般都有一个参数的输入例化对应的对象,所以都有一个init函数,其中的参数表的第一位必须是self,这个其实很像C++和JS里面的this指针,限定对应对象的变量
  3. 参数表里其实可以传入**params表示的字典序列,即可以输出不确定的参数,但是读取对应的键值需要调用迭代items
  4. 参数设定的函数setattr函数:setattr(object,name,value) 给设定对象的给定特性设置未value
  5. 对应setattr函数就有getattr(object,name) 查看对应的对象是否存在对应的特性

python类的私有化

python其实不存在私有,只是”名称变化术”,个人理解为伪私有化
python中的对方法或者特性的私有化,是在其名字前加入双下划线__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Secretive:
def __inaccessible(self):
print "Bet you can't see me..."
def accessible(self):
print "The secret message is:"
self.__inaccessible()

s=Secretive()
s.__inaccessible()
#不可访问
s.accessible()
#可以访问
s._Sercertive_inaccessible()
#是可以访问的

上述的例子说明在变量名前加双下划线,并不是真正的私有化,而只是翻译为单下划线+类名的形式,这样也是可以访问的(这强烈不建议如此使用)

关于类的命名空间

所有位于class语句的代码都在特殊的命名空间执行(类命名空间)

1
2
3
4
5
6
7
8
9
class MemberCounter:
member=0
def __init__(self)
MemberCounter.member+=1
print "MemberCounter is" MemberCounter.member
m1=MemberCounter()
m2=MemberCOunter()
#结果 MemberCounter is 1
# MemberCounter is 2

这东西其实可以理解为JS里面原型公用的函数,类的全局变量,但是就像任何JS,C,C++一样局部同名变量可以屏蔽全局变量,请看例子:

1
2
3
4
5
m2.member='Change'
m1.member
m2.member
#结果 2
#Change

其实这一点,我理解和JS用构造函数实例化对象以后,各个对象都可以自己添加特性,如果重名直接覆盖原有的特性或者方法,这套路一样的
廖雪峰老师中的对此的理解:

类是模板,而实例则是根据类创建的对象。绑定在一个实例上的属性不会影响其他实例,但是,类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。

如果删除对应的m1.member,则能得到对应的类属性结果2

1
2
3
del m1.member
print m1.member
#结果2

python中类的继承

廖雪峰老师课程中关于python类的继承的例子:
如果已经定义了Person类,需要定义新的Student和Teacher类时,可以直接从Person类继承:

1
2
3
4
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender

定义Student类时,只需要把额外的属性加上,例如score:

1
2
3
4
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score

一定要用 super(Student, self).init(name, gender) 去初始化父类,否则,继承自 Person 的 Student 将没有 name 和 gender。
函数super(Student, self)将返回当前类继承的父类,即 Person ,然后调用init()方法,注意self参数已在super()中传入,在init()中将隐式传递,不需要写出(也不能写)。
super(父类,self)!!!!!

python中的类型判断函数

  1. isinstance(object,class) 确定对象是否属于该类
  2. issubclass(ClassA,ClassB) 确定A是否为B的子类
  3. type(object) 返回对象的类型
  4. 直接使用class特性直接可以查明对象属于哪个类:object.__class__

python中的多态

Python的多态和JS的MRO(method Resolution Order 方法判定顺序)一样的,对应子类中和其父类,祖父类重名的方法(函数),是从子类依次有里向外地查找对应的方法,以上面JS例化狗的例子修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dog(object):
def __init__(self,name,weight):
self.name=name
self.weight=weight
def Bark():
print "Say Woof!"

class ShowDog(Dog):
def __init__(self,name,weight,breed):
super(Dog,self).__init__(name,weight)
self.breed=breed
def Bark():
print "Say Yip!"

fluddy=ShowDog('Fluddy',10,'Poodle')
fluddy.Bark()
#输出结果 Say Yip!

多个超类的继承

简单的python示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Calculator:
def __init__(self,expression):
self.value=eval(expression)

class Talker:
def talk(self):
print 'Hi,my value is',self.value

class TalkingCalcuator(Caculator,Talker):
def __init__(self,expression):
super(Caculator,self).__init__(expression)
pass

tc=TalkingCalcuator('1+2*3')
tc.talk()

不清晰的话,则以廖雪峰老师中的习题为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
+-Person
+- Student
+- Teacher

是一类继承树;

+- SkillMixin
+- BasketballMixin
+- FootballMixin

是一类继承树。

通过多重继承,请定义“会打篮球的学生”和“会踢足球的老师”

给出代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Person(object):
pass

class Student(Person):
pass

class Teacher(Person):
pass

class SkillMixin(object):
pass

class BasketballMixin(SkillMixin):
def skill(self):
return 'basketball'

class FootballMixin(SkillMixin):
def skill(self):
return 'football'

class BStudent(Student,BasketballMixin):
pass

class FTeacher(Teacher,FootballMixin):
pass

s = BStudent()
print s.skill()

t = FTeacher()
print t.skill()

热评文章