一、基本概念
Python目的:力求提供简单、够用的语法功能,所以你会看到其面向对象比较简单,不像其他面向对象语言(Java等)提供了大量繁杂的面向对象的特征!
了解:面向对象的程序设计语言的两个重要概念!
(0)辨析面向对象和面向过程
面向过程 面向对象(oop:object oriented programming)
面向过程:---侧重于怎么做?
1.把完成某一个需求的 所有步骤 从头到尾 逐步实现
2.根据开发要求,将某些功能独立的代码封装成一个又一个函数
3.最后完成的代码,就是顺序的调用不同的函数
特点:
1.注重步骤和过程,不注重职责分工
2.如果需求复杂,代码变得非常复杂
3.开发复杂的项目的时候,没有固定的套路,开发难度很大
面向对象:----侧重于谁来做?
相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
1.在完成某一个需求前,首先确定职责--要做的事(方法)
2.根据职责确定不同的对象,在对象内部封装不同的方法(多个)
3.最后完成代码,就是顺序的让不同的对象调用不同的方法
特点:
1.注重对象和职责,不同的对象承担不同的职责
2.更加适合对复杂的需求变化,是专门应对复杂项目的开发,提供固定的套路
3.需要在面向过程的基础上,再学习一些面向对象的语法
面向过程--->侧重于怎么做?
面向对象--->测中于谁来做?
小结:
(1)类的概念
把握:严谨的定义和自定义理解!
类:大概就是一些具有相同属性的对象的集合的抽象描述,可以理解某种概念!
类:是一类具有相同特征或行为的事物的一个统称!
(2)对象的概念
对象:按照类的模版所创建的一个具体的实例(体)!
明确:
创建出来的对象叫做类的实例!
创建对象的动作(过程)叫做实例化!
类与对象是个性和共性的关系!
(3)类的定义
类名:是合法的标识符即可,满足大驼峰命名规范,类名由有意义的单词连缀组成,单词首字母大写,其余小写,单词之间没有任何的分割符号
说明:懒的画图,随手copy了一张!
备注:python3.x系列的版本会自动的继承超类object,即不需要手动的继承!
# ":"作为类体的开始,统一缩进的内容作为类体!
class LibraySystem(object):
# pass语句作为占位符号
pass
#说明:空类没有太大的意义!
类的作用:定义变量、创建对象、派生子类!
(3)类的成员
核心:变量和方法
修饰符扩展:类变量、实例变量、私有方法、类方法、实例方法、静态方法、类变量、私有变量、实例变量
常见的修饰符:@关键字、以双下划线开头、以双下划线结尾、以双下划线开头和结尾(python内置)的
说明:具体的表现形式后面讲解!
(4)对象的创建和方法的调用
class Person:
'类定义说明文档,放在类声明之后,类体之前'
# python的内置方法-->构造方法
# 说明:如果没有自定义构造方法来初始化对象,则默认是只包含一个self参数的__init__函数
# self参数:被绑定到构造方法的初始化"对象上"!
def __init__(self, name):
self.name = name
print('%s被创建' %(self.name))
# 没有被特殊修饰的就是实例方法
def say(self, linux):
print('hello' + linux)
# 创建对象返回的是一个引用
person=Person('老李')
# 调用方法-->对象.方法(参数)
person.say('linux')
# 访问变量-->对象.变量名
print(person.name)
注意:Python的没有方法重载,即相同的函数名,不同的函数列表的函数!
方法中self参数理解:哪一个对象调用的方法,self就是哪一个对象的引用,self就是调用者本身!
1)在封装的方法内部,self就表示当前调用方法对象自己
2)在调用方法的时候,程序员不需要传递self参赛(定义的时候,第一个参数默认是self,自动绑定!
谁调用(发起),self就是谁(那个对象)!
明确:只是一个形式参数,可以随意命名,只是约定俗成(规范),具有更好的可读性而已!
(4)Python的动态语言特性和内置方法的使用
4.1)动态特性
变量:对象动态的增加和删除变量
class Person:
def __init__(self, name):
self.name = name
p = Person('wzj')
#(1)增加属性
p.height = 175
print(p.height)
# (2)删除属性
del p.height
print(p.height)
# 说明:只是针对这个对象而言的!
方法:动态的添加方法
# (0)定义一个类
class Person:
def __init__(self, name):
self.name = name
# (1)自定义一个函数
def define(self):
print('为对象动态的增加一个方法', self)
# (2)动态增加方法
p = Person('猫腻')
# 说明:foo只是一个变量,存储的是函数的引用!
p.foo = define
# 调用方法
p.foo(p)
# 说明:dir可以看到一个对象或者类的成员
print(dir(p))
说明:这个案例有助于理解类体中方法的self参数的含义,这个是类体外针对象的!
注意:动态的增加方法,python不会自动将调用者绑定到第一个参数中,所以需要自己指定!
需求:借助其它模块,后续
4.2)内置方法
特点:以__开头和结尾的
class Person:
def __init__(self, name):
self.name = name
# 强调:返回必须是一个字符串
# 说明:重写了object基类的方法,不希望打印对象的地址值!
def __str__(self):
return "不用地址数值,而是自定义%s" % (self.name)
# 对象销毁前做的扫尾工作,把对象从内存中销毁(垃圾回收)
def __del__(self):
print('%s 走了' % (self.name))
print(Person('老李'))
print(Person('老吴'))
关于自动绑定self的方法再强调几点:
说明:根据第一个参数出现的位置不同,第一个参数绑定的对象略有不同
构造方法中:表示引用构造方法正在初始化的对象!
实例方法中:引用调用该方法的对象!
self的作用:引用当前方法的调用者(对象)!
了解:self表示所代表的对象是不确定的,但是类型是确定的,只有在方法被调用的那一刻,它所代表的对象才确定!
self的应用:对象的一个方法依赖于另一个方法-
class Person:
def __init__(self, name):
self.name = name
def run(self):
print('跑得快')
def drink(self):
# 错误的方法调用(省略了self)
# run()
# 正确的方法调用,区别于Java!
self.run()
########说明:上述所讲的都是##########
(5)方法细讲
5.1)实例方法:类体中定义的一般方法!
说明:由于与实例挂钩,所以与对象有直接的联系,又因为对象是由类创建的,所以实例方法有两种调用方式
class Person:
def __int__(self):
print('hello')
def run(self):
print(self,'正在跑')
# (1)实例调用方法
Person().run()
# (2)类调用实例方法
Person.run(Person())
# 疑惑:二者的内存空间竟然一致,会不会是Python版本的问题
区别:类调用实例方法,Python不会自动为第一个参数绑定调用者,而对象调用实例方法会!
注意:不管是哪种方式调用实例方法都会进行对象的初始化!
5.2)类方法和静态方法
class Person:
@classmethod
# 说明:cls会自动绑定到类本身!
def run(cls):
print('类方法',cls)
@staticmethod
# 说明:静态方法如果想绑定参数,需要手动绑定!
def static(p):
print('静态方法',p)
# (1)调用类方法-->会自动绑定到第一个参数
# 方式1
Person.run()
# 方式2
Person().run()
# (2)调用静态方法-->不会自动绑定到第一个参数
# 方式1
Person.static(Person())
# 方式2
Person().static(Person())
说明:虽然可以通过类或者对象来调用静态和类方法,但是推荐使用类来调用!
区别:静态方法不管哪种方式的调用都不会自动绑定,都不会调用构造方法!
练习
class Toy(object):
# 类属性
count = 0
def __init__(self, name):
self.nama = name
# 说明:调用类方法时回创建对象
# self.count +=1
Toy.count += 1
@classmethod
def show_toy_count(cls):
# 类方法可以调用类属性
print('玩具的数量 %d' % (cls.count))
# 测试-->创建玩具对象
toy1 = Toy('乐高')
toy2 = Toy('小米')
# 调用类方法-->注意调用方式!
Toy.show_toy_count()
应用场景:工厂模式
由静态方法引出的函数装饰器
5.3)私有方法
备注:私有方法在讲解Python面向对象的三大特性的风转时讲解!
明确一点:不是绝对私有的(与Java比较)
理解:类的命名空间和全局空间!
函数和类的方法区别:看是在类的命名空间还是全局空间中!
(6)变量的细讲
6.1)类变量和实例变量
需求:类变量和实例变量的读取和修改
class Person:
# (1)定义一个实例变量
name = '老李'
age = 18
# (2)定义实例方法
def fun(self, name):
# 说明1:下面赋值语句(name)不是对类变量的赋值,而是定义新的实例变量
self.name = name
# 说明2:由于在对象中找不到此变量,所以会在类变量中寻找age!
print("%s的年龄也是%d" % (self.name, self.age))
# (1)类变量
# 读取方式:类名调用
print(Person.name)
print(Person.age)
# 修改方式
Person.name = 'kangkang'
print(Person.name)
# (2)实例变量
# 读取:实例变量(第一次调用该方法的时候)
p = Person()
p.fun('wzj')
# 修改:由于对象中已经有此实例变量,此时就是修改
p.name = '老吴'
print(p.name)
# 说明:由于Python是动态语言,赋值语句往往意味着定义新的实例变量!
类变量:在类命名空间中定义的变量就是类变量!
6.2)私有变量
说明:后续讲到封装的时候再讲解