写在前面:笔记全部是跟着老师一起敲的代码,最近电脑瓦特了,所以只能用老爷机的日记本记下老师上课讲的东西,但我运行不了
特别感谢的是xx学院的的刘老师,我都是边看他的课,边学他一起敲代码,然后晚上自己看,自己理解,感谢老师。
OOP-python面向对象
- python的面向对象
- 面向对象编程
-基础
-公有私有
-继承
-组合、Mixin
- 魔法函数
-魔法函数概述
-构造类魔法函数
-运算类魔法函数
1、面向对象概述(objectoriented,oo)
- OOP思想
-接触到任意一个任务,首先想到的是任务这个事件的构成,是由模型构成的
- 几个名词
-OO:面向对象
-OOA:面向对象的分析
-OOD:面向对象的设计
-OOI:XXX的实现
-OOP:XXX的编程
-OOA->OOD->OOI:面向对象的实现过程
- 类和对象的概念
-类:抽象名词,代表一个集合,共性的事务
-对象:具象的事务,单个个体
-如果说“学生”是一个类,那么“单个学生”就是对象
- 类具有两个内容
-表明事务的特征,叫做属性(变量)
-表明事务的功能或动作,称为成员方法(函数)
2、类的基本实现
- 类的命名
-遵守变量命名的规范
-大驼峰(由多个单词构成,每个单词首字母大写,单词跟单词相连)
-尽量避开跟python内置函数相似的命名
- 如何声明一个类
-必须用class关键字
-类由属性和方法构成,其他不允许出现
-成员属性定义可以直接使用变量赋值,如果没有值,可以使用None
-案例01.py
-实例化类
变量 = 类名() #实例化了一个对象
-访问对象成员
-使用点操作符
obj.成员属性名称
obj.成员方法
-可以通过默认内置变量检查类和对象的所有成员
-对象所有成员检查
#dict前后各有两个下划线
obj.__dict__
-类所有的成员检查
#dict前后各有两个下划线
class_name.__ict__
#定义一个空的类
class Student():
#一个空类,pass代表直接跳过,此处必须有pass
pass
#定义一个对象
siqi = Student():
#再定义一个类,用来描述听python的学生
class PythonSstudent():
#用None给不确定的元素赋值
name = None
age = 18
course = "Python"
#注意 def doHomework的缩进层级
#注意 系统默认有一个self参数
def doHomework(self):
print("我在做作业")
#推荐在函数末尾使用return语句
return None
#实例化一个叫siqi的学生,是一个具体的人
siqi = PythonStudent()
print(siqi.name)
print(siqi.age)
#注意 成员函数的调用没有传递参数
siqi.Homework()
在下面设置好的OOP虚拟环境下运行代码,需要进行以下步骤
-1、python控制界面 File
-2、project interpreter
-3、往右看,点击小齿轮,添加add local
-4、左边选择anaconda
-5、右边点击existing environment,找到anaconda安装目录下的envs文件夹,点击里面刚创建好的OOP,里面点击bin文件夹。点击里面的python或者python3或者python3.6都可以,点击确定
运行时,右击debug
3、anaconda虚拟环境创建(linux环境与windows略有不同)
-anaconda主要是一个虚拟环境管理器
-conda list:显示anaconda安装的包
-conda env list:显示anaconda的虚拟环境列表
-conda creat -n OOP python=3.6:创建python版本为3.6的虚拟环境,名称为OOP
4、类和对象的成员分析
- 类和对象都可以储存成员,成员可以归类所有,也可以归对象所有
- 对象在访问成员时,只是访问其内容,不会重新储存一分新的成员在其自己的空间。
- 对象访问一个成员时,如果对象中没有该成员,尝试访问类中的同名成员,如果对象中有此成员,一定使用对象中的成员
- 创建对象的时候,类中的成员不会放入对象中,而是得到一个空对象,没有成员
- 通过对象对类中成员重新赋值或者添加成员时,只会保存在对象中,不会修改类成员
class A():
name = "siqi"
age = 18
def say(self):
self.name = "aaaa"
self.age = 200
#此时,A成为类实例
print(A.name)
print(A.age)
print(id(A.name))
print(id(A.age))
a = A()
print(a.name)
print(a.age)
print(id(a.name))
print(id(a.age))
此时上下两个id是一样的,指向同一片内存
5、关于self
- self 在对象的方法中表示当前对象本身,如果通过对象调用一个方法,那么该对象会自动传入到当前方法的第一个参数中
- self并不是关键字,只是一个用于接受对象的普通参数,理论上可以用任何一个普通变量名代替
- 方法中有self形参的方法称为非绑定类的方法,可以通过对象访问,没有self的称为绑定类的方法,只能通过类访问
- 使用类访问绑定类的方法时,如果类方法中国需要访问当前类的成员,可以通过__class__成员名来访问
class A():
name = "siqi"
age = 18
def say(self):
self.name = "aaaa"
self.age = 200
print("my name is {0}".format(self.name))
print("my age is {0}".format(self.age))
siqi = A()
siqi.say()
class Teacher():
name = "siqi"
age = 18
def say(self):
self.name = "houzi"
self.age = 19
print("my name is {0}".format(self.name))
print("my age is {0}".format(self.age))
def sayagain():
#调用类成员变量需要用__class__
print(__class__.name)
print(__class__.age)
print("i love pangqi")
t = Teacher()
t.say()
#调用绑定类参数必须使用类名
Teacher.sayagain()
#关于self的案例
class A():
name = "siqi"
age = 18
def _init_(self):
self.name = "aaa"
self.age = 200
def say(self):
print(self.name)
print(self.age)
class B():
name = "bbb"
age = 100
a = A()
a.say()
A.say()#报错
A.say(a)#此时,self被a替换
A.say(A)#此时,把A作为参数传入
A.say(B)#此时,传入额是实例B,因为B具有name和age属性,所以不会报错
以上代码,利用了鸭子模型(有翅膀,会呱呱叫,会游泳,就判定为是鸭子)
6、面向对象的三大特性
-封装
-继承
-多态
-6.1 封装
- 封装就是对对象的成员进行访问限制
-封装的三个级别:
- 公开,public
- 受保护的,protected
- 私有的,private
-public、private、protected不是关键字
- 判别对象的位置
- 对象内部
- 对象外部
- 子类中
- 私有的
- 私有成员时最高级别的封装,只能在当前类或对象中访问
- 在成员前面添加两个下划线就行
- python的私有并非真正的私有,是一种改名策略,是一种name mangling技术,可以使用对象._classname_attributename进行访问
#私有变量案例
class Person(): #name 是共有成员 name = "siqi" #age是私有成员 __age = 18 p = Person(): #name是公有变量 print(p.name) #age是私有的 print(p.__age)#报错 print(p._Person_age)不会报错,但不要使用
- 受保护的封装 protected
-受保护的封装是将对象成员进行一定级别的封装,然后,在类中或子类中可以进行访问,但是在外部不可以
-封装方法:在成员名称前添加一个下划线即刻
- 公开的,公用的 public
-公共的封装实际对成员没有任何操作,任何地方都可以访问
# 继承
- 继承就是一个类可以获得另一个类中的成员属性和方法
- 作用:减少代码,避免重复工作,增加代码的复用功能,同时可以设置类与类直接的关系
- 继承与被继承的概念:
-被继承的类叫父类,也叫基类
-继承的类叫,自类,也叫派生类
- 继承与被继承一定存在一个 is-a 的关系
语法例:
class Person(): name = "NoName" age = 0 def sleep(self): print("sleeping...") #父类写在括号里 class Teacher(Person): pass t = Teacher() print(t.name) print(Teacher.name)
- 继承的特征
-所有的类都继承自object类,即所有的类都是object类的子类
-子类一旦继承父类,则可以使用父类中除私有成员以外的所有内容
-子类继承父类后并没有将父类成员完全复制到子类中,而是通过引用关系访问
-子类中可以定义独有的成员属性和方法
-子类中定义的成员和父类成员如果相同,则优先使用子类成员
-子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用,可以使用 父类名.父类成员 的格式来调用父类恒源,也可以使用super().父类成员的格式来调用
class Person(): name = "NoName" age = 0 __score = 0 #考试成绩是秘密,只能自己知道 _petname = "qiqi" #小名,是保护的,子类可以用,但不能公用 def sleep(self): print("sleeping...") def work(self): print("make some money") #父类写在括号里 class Teacher(Person): name = "houzi" #子类和父类相同名称的成员 teacher_id = "9527"#子类中新定义的成员 def make_test(self)#子类中新定义的恒源 print("attention") def work(self): #扩充父类的work功能,只需要调用父类相应的函数 Person.work(self) #方法一 self.make_test() super().work()#方法二 self.make_test() t = Teacher() print(t.name) print(t._petname) print(t.work) #公开访问私有变量,报错 print(t.__score)#报错,不可访问
# 继承变量函数的查找顺序问题
-优先查找自己的变量
-没有则查找父类
-构造甘薯如果本类中没有定义,则自动查找调用父类构造甘薯#一会儿讲
-如果本类没有定义,则不能继续向上查找
- 构造函数
-是一类特殊的函数,在类进行实例化之前呢进行调用
-如果定了构造函数,则实例化时使用构造函数,不查找父类构造函数
-如果子类没有定义,则自动查找父类的构造函数
-父类的构造函数带参数,则构造对象的参数应该按父类参数构造
例:
#构造函数概念 class Dog(): #__init__就说构造函数 #每次实例化的时候,第一个被自动调用 def __init__(self): print("88755") kk = Dog() #继承中的构造函数-1 class Animal(): pass class BuAnimal(Animal): pass class Dog(BuAnimal): #__init__就说构造函数 #每次实例化的时候,第一个被自动调用 def __init__(self): print("88755") #实例化的时候,自动调用了Dog的构造函数 kk = Dog() #继承中的构造函数-2 class Animal(): pass class BuAnimal(Animal): def __init__(self): print("pgdog") class Dog(BuAnimal): #__init__就说构造函数 #每次实例化的时候,第一个被自动调用 def __init__(self): print("88755") #实例化的时候,自动调用了Dog的构造函数 #因为找到了构造函数,则不会再查父类的构造函数 kk = Dog() #cat没有写构造函数 class Cat(BuAnimal): pass #此时应该自动调用构造函数,因为cat没有构造函数,所以查找父类的构造函数,在BuAnimal时停止 c = Cat() #继承中的构造函数-3 class Animal(): pass class BuAnimal(Animal): def __init__(self,name): print("pgdog i {o}".format(name)) class Dog(BuAnimal): #__init__就说构造函数 #每次实例化的时候,第一个被自动调用 def __init__(self): print("88755") #实例化的时候,自动调用了Dog的构造函数 #因为找到了构造函数,则不会再查父类的构造函数 kk = Dog() class Cat(BuAnimal): pass #!!此时报错,因为父类的构造函数需要两个参数,而此时只给了一个 c = Cat() - super -super不是一个关键字,是一个类 -super的作用是获取MRO(method resolution order)列表中的第一个类 -super与父类没有任何直接关系,但通过super可以调用父类 -super:使用两个方法,参见在构造函数中调用父类的构造函数 例: print(type(super)) help(super)