一、类和对象
1、面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数
在python中,用变量表示特征,用函数表示特征,类是变量和函数的结合体,对象是变量与方法(指向类的函数)的结合体
1 ''' 2 class 类名: 3 '类的文档字符串' 4 类体 5 ''' 6 7 #我们创建一个类 8 class Data: 9 pass
2、类的两种作用(属性引用和实例化)
2.1属性引用(类名、属性)
>>> Garen.camp #引用类的数据属性,该属性与所有对象/实例共享 'Demacia' >>> Garen.attack #引用类的函数属性,该属性也共享 <function Garen.attack at 0x101356510> >>> Garen.name='Garen' #增加属性 >>> del Garen.name #删除属性
2.2实例化(__init__,self)
类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
class Garen: #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄; camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia; def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻击力58...; self.nickname=nickname #为自己的盖伦起个别名; self.aggressivity=aggressivity #英雄都有自己的攻击力; self.life_value=life_value #英雄都有自己的生命值; def attack(self,enemy): #普通攻击技能,enemy是敌人; enemy.life_value-=self.aggressivity #根据自己的攻击
实例化:类名+括号
>>> g1=Garen('草丛伦') #就是在执行Garen.__init__(g1,'草丛伦'),然后执行__init__内的代码g1.nickname=‘草丛伦’等
self的作用是在实例化时自动将对象/实例本身传给__init__的第一个参数
3、对象的相关知识
对象是关于类而实际存在的一个例子,即实例
>>> g1=Garen('草丛伦') #类实例化得到g1这个实例,基于该实例我们讲解实例相关知识 >>> type(g1) #查看g1的类型就是类Garen <class '__main__.Garen'> >>> isinstance(g1,Garen) #g1就是Garen的实例 True
对象/实例本身只有数据属性,但是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法,绑定方法唯一绑定一个对象,同一个类的方法绑定到不同的对象上,属于不同的方法,内存地址都不会一样
4、类的名称空间与对象/实例名称空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:数据属性和函数属性
其中类的数据属性是共享给所有对象的
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
二、继承与派生与组合
1、继承的定义:
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
在Python3中,所有类都默认继承object,都是新式类。
在Python2中,有经典类和新式类。
没有继承object类以及object的子类的类都是经典类。
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass1 pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
查看继承
使用<类名.__base__>查看类的第一个父类
使用<类名.__bases__>查看类的父类
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ #__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
>>> ParentClass1.__bases__ (<class 'object'>,) >>> ParentClass2.__bases__ (<class 'object'>,)
class People: pass class Animal: pass class Student(People,Animal): pass print(Student.__bases__) #(<class '__main__.People'>, <class '__main__.Animal'>) print(People.__bases__) #(<class 'object'>,) print(Animal.__bases__) #(<class 'object'>,) print(Student.__base__) #<class '__main__.People'>
继承也是为了解决代码重复的问题,减少代码冗余。
继承是用来创建新的类的一种方式。
继承是一种什么“是”什么的关系。
2、派生
定义:当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。这就是类的派生。
class Riven(Hero): camp='Noxus' def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类 print('from riven') def fly(self): #在自己这里定义新的 print('%s is flying' %self.nickname)
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值。
class Riven(Hero): camp='Noxus' def __init__(self,nickname,aggressivity,life_value,skin): Hero.__init__(self,nickname,aggressivity,life_value) #调用父类功能 self.skin=skin #新属性 def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类 Hero.attack(self,enemy) #调用功能 print('from riven') def fly(self): #在自己这里定义新的 print('%s is flying' %self.nickname) r1=Riven('锐雯雯',57,200,'比基尼') r1.fly() print(r1.skin) ''' 运行结果 锐雯雯 is flying 比基尼 '''
class People: #定义父类 def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def walk(self): print('%s is walking' %self.name) def foo(self): print('from father %s' %self.name) class Teacher(People): #继承父类 def __init__(self,name,age,sex,level,salary): #新建__init__方法 People.__init__(self,name,age,sex) #还使用父类的方法 self.level = level #新增的内容 self.salary = salary def tech(self): #子类特有的函数属性 print('%s is teaching ' %self.name) def foo(self): People.foo(self) print('from Teacher') #对父类的函数属性引用和新增 class Student(People): def __init__(self,name,age,sex,group): People.__init__(self,name,age,sex) self.group = group def study(self): print('%s is studying'%self.name) t=Teacher('egon',18,'male',10,3000) print(t.salary) t.tech() t.foo() ''' 3000 egon is teaching from father egon from Teacher '''
3、组合
软件重用的重要方式除了继承之外还有一种方式,即:组合。
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Date: #定义一个关于日期的类 def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print('出生于%s年 %s月 %s日'%(self.year,self.mon,self.day)) class Teacher: #定义一个老师的类 def __init__(self,name,age,year,mon,day): self.name = name self.age = age self.birth = Date(year,mon,day) #使用Date的类 def teach(self): print('%s is teaching'%self.name) t=Teacher('egon',18,1990,12,11) t.birth.tell_birth() ''' 出生于1990年12月11日
组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同。
4、继承的方式和组合的方式
继承的方式:
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师。
>>> class Teacher: ... def __init__(self,name,gender): ... self.name=name ... self.gender=gender ... def teach(self): ... print('teaching') ... >>> >>> class Professor(Teacher): ... pass ... >>> p1=Professor('egon','male') >>> p1.teach() teaching
组合的方式:
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程。
class BirthDate: def __init__(self,year,month,day): self.year=year self.month=month self.day=day class Couse: def __init__(self,name,price,period): self.name=name self.price=price self.period=period class Teacher: def __init__(self,name,gender): self.name=name self.gender=gender def teach(self): print('teaching') class Professor(Teacher): def __init__(self,name,gender,birth,course): Teacher.__init__(self,name,gender) self.birth=birth self.course=course p1=Professor('egon','male', BirthDate('1995','1','27'), Couse('python','28000','4 months')) print(p1.birth.year,p1.birth.month,p1.birth.day) print(p1.course.name,p1.course.price,p1.course.period) ''' 运行结果: 1 27 python 28000 4 months '''