文章目录
Python基础-面向对象
1.编程的分类:
-
面向过程
-
函数式编程
-
面向对象
1.1面向过程
所谓过程就是解决问题的一个步骤,一步一步的按照流程走,有先后顺序。它的整个设计过程就好比流水线,思维上比较机械化。
优缺点:
-
优点:
- 复杂的问题流程化,将问题简化。
-
缺点:
- 拓展性不好,
1.2 面向对象
核心是对象。
定义:
-
对象是一个数据以及相关行为的集合
-
面向对象是功能上指向建模对象
通过数据和行为方式来描述交互对象的集合。
在Python中,一切皆为对象。
优缺点:
-
优点:
- 解决程序的拓展性
-
缺点:
- 复杂度远高于面向过程
- 交互式解决问题,无法准确预测结果
在现实世界中以我们为例
object1: Tom 特征: school=zucc name=tom age=20 sex=male 技能: eat sleep study object2: Nicole 特征: school=zucc name=Nicole age=21 sex=male 技能: eat sleep study sing
类就是类别总类
对象就是特征合技能的统一体
类是这一系列相似对象的特征和技能的结合
对于现实世界,现有个体(对象),才有类型,对于程序,先有类,才有对象
2.面向对象的编程
oop(object oriented programming)
其实是一种程序设计思想。oop把对象作为程序的一个基本单元,一个对象就包含了数据和操作数据的函数。
在Python中,所有数据类型都可以视为对象,同时也可以自定义对象。
自定义对象数据类型就是面向对象中类(class)的概念
demo:
假如要处理学生的成绩。为了表示学生的成绩:
- 面向过程
stu1={'name':'Tom','score':99}
stu2={'name':'Nicole','score':23}
利用函数来实现:
def find_score(stu):
print(stu['name'],':',stu[score])
2.1类的定义
类是用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
定义:
class calssname(object):
'dicstring'
class_statement
2.2创建一个空类
类的命名:大驼峰式(变量名称的单词的首字母大写)
class The_First:
pass #相当于一个占位符
类的作用是一个模板,我们可以在创建实例的时候,把一些我们认为必须要绑定的属性填写进去。这时就通过
__init__方法,在创建实例的时候,绑定相关的属性。
在类中定义方法时,第一个参数必须是‘self’
self代表的是实例,而非类。
__init__方法:
- 为对象初始化自己独有的特征
- 该方法中可以有任意的Python代码,但是不能有返回值
2.3类中的概念
- **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- **数据成员:**类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- **局部变量:**定义在方法中的变量,只作用于当前实例的类。
- **实例变量:**在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- **实例化:**创建一个类的实例,类的具体对象。
- **方法:**类中定义的函数。
- **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
2.4数据封装
class Student:
def __init__(self,name,score):
self.name=name
self.score=score
def find_score(self):
print(self.name,':',self.score)
stu1=Student('Ton',99)#实例化过程
stu1.find_score()
我们通过_init_()让stu1实例,拥有了相关数据,如果要访问这些数据,我们可以在Student类的内部定义相关函数来访问数据,以此’封装’数据
这些封装的数据的函数和Student是相互关联的,他们被称之为方法。
类的两个作用:
- 属性引用
- 类名.属性
- 实例化
- 类名加上一个括号,它能够自动触发__init__函数的运行,进而为每个实例定制自己的特征。
2.5类命名空间与对象,实例的空间
创建一个类就会创建一个实例的空间用来存储定义的所有实例的名字(属性)
类的属性可以分为:静态(在类中定义的变量)和动态(定义在类中的方法)两种
静态属性共享给所有对象,动态属性是绑定到所有对象
2.6类三大特性:
- 继承
- 多态
- 封装
2.6.1继承
在面向对象的编程中,当我们定义一个新类的时候,可以从某个现有的类继承,新的类被称之为子类(SubClass)
而被继承的类称为基类,父类,超类(base class ,father class,super class)
比如,我们定义一个动物类(Animal),其有一个run()方法如下:
class Animal(object):
def run(self):
print('Animal is running.')
class other(object):
pass
class Dog(Animal): #Dog类继承了Animal类,单继承
pass
class Cat(Animal):
pass
class Husky(Animal,other):
pass #多继承,父类之间用逗号分开,其父类不能为其他类的子类
dog=Dog()
cat=Cat()
dog.run()
cat.run()
'''
Animal is running.
Animal is running.
'''
继承的查看:
print(Class.name__bases__)
#没有基类,Python类默认继承object类,object是Python所有类的基类,提供一些常见方法的实现
2.6.2多态
当子类和父类存在相同的方法时,子类的方法覆盖父类的方法,在运行代码时,总会调用子类与父类相同名的方法。
理解多态,首先要对数据类型在进行说明。定义一个类的时候实际上是定义了一张数据类型。我们自定义的数据类型和Python自带的没什么区别
class Animal(object):
def run(self):
print('Animal is running.')
class Dog(Animal):
def run(self):
print('Dog is running') #当子类和父类存在相同的方法时,子类的方法覆盖父类的方法
class Cat(Animal):
pass
dog=Dog()
cat=Cat()
dog.run()
cat.run()
'''
Dog is running
Animal is running.
'''
li=list()
print(isinstance(li,list)) #isinstance(x,y)判断变量x是不是y类型
print(isinstance(dog,Animal))
print(isinstance(dog,Dog))
'''
True
True
True
'''
对于一个变量,我们只要知道它的父类型,无需知道子类型,就可以放心地调用相关的方法。运行时具体的方法是作用在子类型还是在父类型上,有我们的对象觉得
也就是说,调用时只管调用,不管细节
当我们新增一个子类是,只用保证相关方法的编写正确,就不用管原来的代码是如何调用的
—>'开闭’原则:
- 对拓展开发:允许新增子类
- 对修改封闭:不需要修改依赖父类类型的函数
总结:
继承可以一级级继承下来。任何类都可以追溯到object这个根类,这些继承关系像树
2.6.3封装
隐藏对象的属性和实现细节,仅提供公共访问的方式,其优点在于:
可以将变化隔离
便于使用
提高数据安全性
提高复用性
封装原则:
-
将不需要对外提供的内容隐藏起来
-
隐藏属性,提供工作方法对其进行访问
—>私有方法,私有变量—>私有属性
用双下划线开头将属性隐藏起来,设置为私有属性
3类属性的补充内容
- 类属性的查看:
- dir(类名),返回为一个列表
- 类名._dict_,返回为一个字典
3.1特殊的类属性
类名.__name__ #返回类名
类名.__doc__ #返回说明文档
类名.__base__#返回类的第一个父类
类名.__bases__#返回所有父类构成的元组
类名.__module__#类定义所在模块
类名.__class__#实例所对应的类
类名.__dict__ #类的字典属性
总结:
class Classname:
def__init__(self,para1,appra2)
self.对象属性1=para1
self.对象属性2=para2
def 方法名1(self):
pass
def 方法名2(self):
pass
obj=classname(para1,para2) #对象实例化,括号内传参一一对应,结果是返回对象obj
obj.对象属性1 # 查看对象属性
obj.方法名 #调用类的方法
3.2对象之间的交互:
假如先定义两个类:
class person():
def __init__(self,name,attack,life_value)
self.name=name
self.attack=attack
self.life_value=life_value
def attack(self,dog):
dog.life_value-=self.aggressivity
class dog:
def __init__(self,name,breed,attack,life_value)
self.name=name
self.breed-breed
self.attack=attack
def bite(self,people):
people.life_value-=self.attack
per=person('jack',10,1000)
dog=dog('Jeorry','Husky',8,1000)
print(dog.life_value)
per.attack(dog)
print(dog.life_value)
3.3私有属性
在类的内部,可以有属性和方法,而外部代码就可以通过直接调用实例变量的方法来操作数据。这样,隐藏了内部的复杂逻辑。
例如在Student类中
class Student:
def __init__(self,name,score):
self.name=name
self.score=score
def find_score(self):
print(self.name,':',self.score)
stu1=Student('Ton',99)
stu1.find_score()
stu1.score=91
stu1.find_score()
'''
Ton : 99
Ton : 91
'''
从这里可以看出,外部代码可以自由修改一个实例的属性(name,score)
那么如何让内部属性不被外部访问,在属性的名称前面加两个下划线即可,这样这个属性就变成了一个私有属性只有内部可以访问
demo:
class Student:
def __init__(self,name,score):
self.__name=name
self.__score=score
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self,score):
self.__score=score
def find_score(self):
print(self.__name,':',self.__score)
stu1=Student('Ton',99)
stu1.find_score() #输出一次作为标本
# print(id(stu1.score)) #尝试获取stu1.score地址 报错,找不到
stu1.score=91 #尝试修改stu1.score
print(stu1.score) #输出stu1.score
print(id(stu1.score))
stu1.find_score() #第二次输出作为比较
stu1.set_score(80) #用内部的set_score函数进行修改
stu1.find_score() #第三次输出用作比较
#print(stu1.__score) #报错,无法找到
print(stu1._Student.__score)#成功访问
stu1._Student.__score=70 #修改
stu1.find_score()
'''
Ton : 99
91 #stu1.score=91
1499231808 #地址
Ton : 99 #其内部值仍为99 ,使用stu1.score=91修改失败
Ton : 80 #使用set_score 修改成功
80
Ton : 70
'''
3.4鸭子类型
-
不要求有严格的继承关系,一个对象,只要‘看起来像鸭子,走起路来还是像鸭子。’
也就是说,如果要编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观和行为像的,但与其无任何关系的全新对象
比方说,利用标准库中定义的各种’与文件类似‘的对象,尽管这些对象的工作方式像文件,但他们并没有继承内置对象文件的方法
class TestFile: def read(self): pass def Write(self): pass class OperFile: def read(self): pass def write(self): pass
就可以放心调用相关的方法。运行是具体的方法就是作用在子类型上海市父类型上,由我们的运行对象决定。
class Animal(object):
def run(self):
print('Animal is running.')
def run_twice(animal):
animal.run()
animal.run()
run_twice(test)
'''
Animal is running.
Animal is running.
'''