一、编程的两大思想
(1)面向过程
事物比较简单,用简单的线性思维即可解决
(2)面向对象
事物比较复杂,用简单的线性思维无法解决
(3)两者之间的关系
在面对复杂的问题时,宏观上是使用面向对象,但具体到微观操作,还是要用面向过程的方式来进行解决。
二、类的定义
类就是类别,使用类的方法能够帮助我们快速理解和判断事物的性质。例如我们之前学习过的数据类型,不同的数据类型属于不同的类,可以使用内置函数type查看数据类型。
三、对象的定义
相同的类中的不同的个例,就称为实例或者是对象。
四、类的创建
(1)类名
创建类,首先需要一个类名,类名可以由一个单词组成,也可以有多个单词组成,但每个单词的首字母需要大写。
(2)类的组成
①类属性
②实例方法
③静态方法
④类方法
⑤初始化方法
#类的创建
class Student:
location='湖北' #直接写在类里面的变量,成为类属性
#初始化方法
def__init__(self,name,age)
self.name=name
self.age=age
#在类之内定义的是方法,在类之外定义的是函数
#实例方法
def study(self):#这里的self必须得加
print('学生在学习')
#静态方法
@staticmethod
def method():#在静态方法中可以不加self
print('静态方法')
#类方法
@classmethod
def cm(cls):#类方法里面要加cls
print('类方法')
#在类之外定义的,下面这个就是函数
def play:
print('学生想玩耍')
五、对象的创建
对象的创建又被称为类的实例化
格式:实例名=类名()
#类的创建
class Student:
location='湖北' #直接写在类里面的变量,成为类属性
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类之内定义的是方法,在类之外定义的是函数
#实例方法
def study(self):#这里的self必须得加
print('学生在学习')
#静态方法
@staticmethod
def method():#在静态方法中可以不加self
print('静态方法')
#类方法
@classmethod
def cm(cls):#类方法里面要加cls
print('类方法')
#在类之外定义的,下面这个就是函数
def play():
print('学生想玩耍')
student1=Student('A',18)
#实例方法
print(student1.name)
print(student1.age)
#实例属性
#方法一,对象名加实例方法名
student1.study()
#方法二,类名.实例方法名(对象名)
Student.study(student1)
运行结果
六、类属性、类方法、静态方法
(1)类属性:类中方法外的变量称为类属性,可以被该类的所有对象所共享。
(2)类方法:就是使用@classmethod修饰的方法,使用类名直接访问的方法。
(3)静态方法:就是使用@staticmethod修饰的方法,使用类名直接访问的方法。
(4)访问类属性
根据上面的代码的这一块
class Student:
location='湖北' #直接写在类里面的变量,成为类属性
#初始化方法
def ``````
因为location是在类中方法外的变量,所以location就是类属性,也就是说可以被该类的所有对象所共享。
#类的创建
class Student:
location='湖北' #直接写在类里面的变量,成为类属性
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类之内定义的是方法,在类之外定义的是函数
#实例方法
def study(self):#这里的self必须得加
print('学生在学习')
#静态方法
@staticmethod
def method():#在静态方法中可以不加self
print('静态方法')
#类方法
@classmethod
def cm(cls):#类方法里面要加cls
print('类方法')
#在类之外定义的,下面这个就是函数
def play():
print('学生想玩耍')
student1=Student('A',18)
#实例方法
print(student1.name)
print(student1.age)
#实例属性
print(student1.location)
#对类属性进行修改
Student.location='武汉'
print(student1.location)
运行结果
(5)调用类方法
形式:类名.类方法名
#类的创建
class Student:
location='湖北' #直接写在类里面的变量,成为类属性
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类之内定义的是方法,在类之外定义的是函数
#实例方法
def study(self):#这里的self必须得加
print('学生在学习')
#静态方法
@staticmethod
def method():#在静态方法中可以不加self
print('restday')
#类方法
@classmethod
def cm(cls):#类方法里面要加cls
print('好想休息')
#在类之外定义的,下面这个就是函数
def play():
print('学生想玩耍')
student1=Student('A',18)
#调用类方法
Student.cm()
运行结果:
(6)调用静态方法
形式:类名.静态方法名
#类的创建
class Student:
location='湖北' #直接写在类里面的变量,成为类属性
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类之内定义的是方法,在类之外定义的是函数
#实例方法
def study(self):#这里的self必须得加
print('学生在学习')
#静态方法
@staticmethod
def sm():#在静态方法中可以不加self
print('restday')
#类方法
@classmethod
def cm(cls):#类方法里面要加cls
print('好想休息')
#在类之外定义的,下面这个就是函数
def play():
print('学生想玩耍')
student1=Student('A',18)
#调用静态方法
Student.sm()
运行结果
静态方法没有任何默认参数,类方法有默认参数。
七、动态绑定属性和方法
一个类可以创建多个属于该类的实例对象,每个实例对象的属性值不同。
(1)Python是动态语言,在创建对象之后,可以动态的绑定属性,例如:
#动态绑定属性和方法
#首先定义类
class Student:
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类里面定义的函数叫做方法
def study(self):
print(self.name,'在学习')
#定义实例化对象
student1=Student('A',18)
student2=Student('B', 20)
#为stu1动态绑定新的属性,比如说成绩属性
student1.scores=500 #创建对象后,在初始化方法之后进行的绑定
print(student1.name,student1.age,student1.scores)
print(student2.name,student2.age,student2.scores)
运行结果
解释,name和age是在初始化定义里面定义的属性,所以说是所有对象都有的属性。在创建完成之后,新绑定的属性只属于当前所绑定的对象。
(2)除了能够动态绑定属性外,还可以动态绑定方法。
类里面的方法,是所有实例对象都可以用的。
例如,定义在类里的方法,所有实例对象都可以调用。
#动态绑定属性和方法
#首先定义类
class Student:
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类里面定义的函数叫做方法
def study(self):
print(self.name,'在学习')
#定义实例化对象
student1=Student('A',18)
student2=Student('B', 20)
#动态绑定方法
#首先是调用在类里面定义的方法
student1.study()
student2.study()
# def show():
# print('定义在类之外的,称为函数')
# #绑定
# student1.show=show #仅仅将show绑定student1,而不绑定student2
#
# student1.show()
# student2.show()
运行结果
例如,定义在类之外的函数,只有绑定实例对象之后,才能使用。
#动态绑定属性和方法
#首先定义类
class Student:
#初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
#在类里面定义的函数叫做方法
def study(self):
print(self.name,'在学习')
#定义实例化对象
student1=Student('A',18)
student2=Student('B', 20)
#动态绑定方法
#首先是调用在类里面定义的方法
student1.study()
student2.study()
def show():
print('定义在类之外的,称为函数')
#绑定
student1.show=show #仅仅将show绑定student1,而不绑定student2
student1.show()
student2.show()
运行结果
即student2并没有绑定show方法。
八、面向对象编程语言的特征
(1)封装
封装的目的是提高程序的安全性。它指得是将属性和方法包装到对象中。然后在方法内部对属性进行操作,在类对象的外部调用方法。
class Atm:
#(1)将属性和方法包装到对象中
def __init__(self,money):
self.money=money
#在类内部定义的是方法
def draw(self):
print('正在取款中')
atm=Atm('1w')
#在类对象的外部调用方法。
atm.draw()
print(atm.money)
运行结果
如果某个属性不希望在类对象的外部被访问,那么使用两个–,来表示该属性的私有。
class Student:
def __init__(self,name,age):
self.name=name
#不希望在类对象的外部被访问,但是在内部是可以访问的
self.__age=age
def display(self):
print(self.name,self.__age)
#创建实例对象
student1=Student('A',18)
#因为show是类内部的方法,所以说年龄可以显示
student1.display()
运行结果
尝试在外部访问类属性
class Student:
def __init__(self,name,age):
self.name=name
#不希望在类对象的外部被访问,但是在内部是可以访问的
self.__age=age
def display(self):
print(self.name,self.__age)
#创建实例对象
student1=Student('A',18)
#因为show是类内部的方法,所以说年龄可以显示
# student1.display()
print(student1.name)
print(student1.__age)
它会显示名字是A,但是没有年龄这个属性。
运行结果
但这不代表不能使用,只是使用的方法和直接使用name这个属性是不同的。
使用方法,第一步找到实例化对象的所有属性
#第一步,找到实例化对象的所有属性
print(dir(student1))
发现有一个_Student__age的属性
使用
print(student1._Student__age)
进行访问
完整代码
class Student:
def __init__(self,name,age):
self.name=name
#不希望在类对象的外部被访问,但是在内部是可以访问的
self.__age=age
def display(self):
print(self.name,self.__age)
#创建实例对象
student1=Student('A',18)
#因为show是类内部的方法,所以说年龄可以显示
# student1.display()
print(student1.name)
#第一步,找到实例化对象的所有属性
# print(dir(student1))
#第二步根据属性提示进行访问
print(student1._Student__age)
运行结果
但是看到使用__不希望被访问的对象,最好还是不要进行访问。
(2)继承
①继承则提高了代码的复用性
Python支持多继承,也就是说一个子类,可以有多个父类。在定义子类时,必须在其构造函数中调用父类的构造函数。如果一个类没有继承任何类,那么就默认继承object。语法格式如下。
#语法格式
class 子类类名 (父类1,父类2):
pass
示例
#继承
#定义父类,person类
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age)
#学生——子类
class Student(Person):
def __init__(self,name,age,scores):
super().__init__(name,age)#继承person父类
self.scores=scores
#教师——子类
class Teacher(Person):
def __init__(self,name,age,techyear):
super().__init__(name,age)#继承person父类
self.techyear=techyear
#创建不同类的实例对象
student=Student('a',18,500)
teacher=Teacher('b',50,30)
student.info()#继承父类里面的方法
teacher.info()
运行结果
像姓名和年龄都是从父类中继承过来的。
②除此之外,还有多继承的方式
例如
class A(object):
pass
class B(object):
pass
class(A,B):
pass
③方法重写
方法重写的意思是如果子类对继承来自于父类的某个属性或者是对父类的方法不满意,那么可以在子类中对方法进行重新编写。子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法。
比如说,在本文最开始继承的实例代码中,调用父类中的方法,只输出了名字和年龄,为了输出其他信息,就需要进行方法重写。
#继承
#定义父类,person类
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age)
#学生——子类
class Student(Person):
def __init__(self,name,age,scores):
super().__init__(name,age)#继承person父类
self.scores=scores
#方法重写
def info(self):
print(self.scores)
#教师——子类
class Teacher(Person):
def __init__(self,name,age,techyear):
super().__init__(name,age)#继承person父类
self.techyear=techyear
#创建不同类的实例对象
student=Student('a',18,500)
teacher=Teacher('b',50,30)
student.info()#继承父类里面的方法
teacher.info()
运行结果
根据运行结果发现,方法重写后,只出现了分数,之前从父类继承过来的方法和年龄都没有了,根据之前的讲解,如果需要这些信息,子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法。
#继承
#定义父类,person类
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age)
#学生——子类
class Student(Person):
def __init__(self,name,age,scores):
super().__init__(name,age)#继承person父类
self.scores=scores
#方法重写
def info(self):
super().info()
print(self.scores)
#教师——子类
class Teacher(Person):
def __init__(self,name,age,techyear):
super().__init__(name,age)#继承person父类
self.techyear=techyear
#创建不同类的实例对象
student=Student('a',18,500)
teacher=Teacher('b',50,30)
student.info()#继承父类里面的方法
teacher.info()
运行结果
同理,再给教师添加一些信息。
#继承
#定义父类,person类
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age)
#学生——子类
class Student(Person):
def __init__(self,name,age,scores):
super().__init__(name,age)#继承person父类
self.scores=scores
#方法重写
def info(self):
super().info()
print(self.scores)
#教师——子类
class Teacher(Person):
def __init__(self,name,age,techyear):
super().__init__(name,age)#继承person父类
self.techyear=techyear
def info(self):
super().info()
print(self.techyear)
#创建不同类的实例对象
student=Student('a',18,500)
teacher=Teacher('b',50,30)
student.info()#继承父类里面的方法
teacher.info()
运行结果
④object类
object类是所有类的父类,也就是说所有类都有object类的属性和方法。这里我们可以定义一个类,但是不创建属性,使用内置函数dir()去查看属性。
#创建类
class Student:
pass
#实例化对象
stu=Student()
#使用内置函数dir查看属性
print(dir(stu))
运行结果
不查不知道,一查吓一跳,为什么没有创建属性,为什么还有那么多的属性呢。这是因为object()是所有类的父类,所有类都可以继承object的属性。
对于object有一个__str__()方法,用于返回一个对于“对象的描述”。对应于内置函数str()经常用于print()方法,利用该方法可以查看对象的信息,因此,经常会使用__str__()进行重写。
例如:
现在使用print(),输出的是内存地址,
#创建类
class Student:
def
#实例化对象
stu=Student()
print(stu)
运行结果
现在需要输出属性值,那么我们就采用__str__方法进行重写。
#创建类
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return "我叫'%s',今年%d岁了"%(self.name,self.age)
#实例化对象
stu=Student('a',18)
print(stu)
运行结果
(3)多态
多态则提高了程序的可扩展性和可维护性。多态,顾名思义,就是具有多种形态。也就是说即便不知道一个变量所引用的对象是什么类型,仍然可以通过变量调用的方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法。
动态语言的特征,不需要去关注对象是哪个类,只需要关心对象的行为
例如
class Animal(object):
def eat(self):
print('动物会吃')
#定义子类,继承父类
class Dog(Animal):
#方法重写
def eat(self):
print('狗吃骨头')
class Cat(Animal):
# 方法重写
def eat(self):
print('猫吃鱼')
class Person(object):
def eat(self):
print('人吃饭')
#定义函数,调用类里面的eat方法
def fun(object):
object.eat()
#调用函数
fun(Animal())
fun(Dog())
fun(Cat())
#不关注对象有没有类,只关注对象的行为
fun(Person())
运行结果
九、特殊方法
(1)_ _ add _ _
通过方法重写,使得对象具有加法的性质。
没有使用_ _ add _ _重写,进行相加。
class Student():
def __init__(self,name):
self.name=name
student1=Student('A')
student2=Student('B')
c=student1+student2
print(c)
运行结果
不支持这种相加操作。
使用add方法重写
class Student():
def __init__(self,name):
self.name=name
def __add__(self, other):
return self.name+other.name
student1=Student('A')
student2=Student('B')
c=student1+student2
print(c)
print(student1.__add__(student2))
运行结果
(2)_ _len _ _
可以通过方法重写,得到对象的长度。
未进行方法重写。
class Student():
def __init__(self,name):
self.name=name
# def __len__(self):
# return len(self.name)
student1=Student('张三')
print(len(student1))
运行结果,报错
没有长度
进行方法重写
class Student():
def __init__(self,name):
self.name=name
def __len__(self):
return len(self.name)
student1=Student('张三')
print(len(student1))
运行结果
(3)_ _ new _ _ 用于创建对象
(4) _ _ add _ _ 用于对创建的对象进行初始化
十、特殊属性
(1) _ _ dict _ _
获得类对象或者实例对象所绑定的所有属性和方法,输出结果是一个字典
class A:
pass
class B:
pass
class Student(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例对象
student=Student('A',18)
#查看实例对象的属性
print(student.__dict__)
#查看类对象的属性
print(Student.__dict__)
运行结果
具体分析,如果是一个实例化对象,就是看到了属性。
如果是一个类对象,那就可以查看属性和方法
(2)_ _ class_ _
输出的是实例化对象所属的类
class A:
pass
class B:
pass
class Student(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例对象
student=Student('A',18)
#输出实例化对象所属的类
print(student.__class__)
运行结果
(3)bases
输出类对象所属的父类
class A:
pass
class B:
pass
class Student(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例对象
student=Student('A',18)
#输出类对象所属的父类
print(Student.__bases__)
运行结果
(4)base
输出离得近的那个父类
class A:
pass
class B:
pass
class Student(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例对象
student=Student('A',18)
#输出类对象所属的最近父类
print(Student.__base__)
运行结果
(5)mro
输出类的层次结构
class A:
pass
class B:
pass
class Student(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例对象
student=Student('A',18)
#输出类对象所属的最近父类
print(Student.__mro__)
运行结果
(6)subclasses
查看某一个类的子类
class A:
pass
class B:
pass
class Student(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例对象
student=Student('A',18)
#输出类对象所属的最近父类
print(A.__subclasses__())
运行结果
十一、类的赋值
变量之间的赋值操作,只是形成两个变量,但是实际上还是指向同一个对象,内存地址都还是相同的。
class Name:
pass
class Age:
pass
class Student:
def __init__(self,nama,age):
self.name=name
self.age=age
#创建实例化对象
name1=Name()
#将name1的值赋值给name2
name2=name1
print(name1)
print(name2)
运行结果
十二、浅拷贝
python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象。
class Name:
pass
class Age:
pass
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例化对象
name=Name()
#将name1的值赋值给name2
age=Age()
student1=Student(name,age)
#浅拷贝
import copy
student2=copy.copy(student1)
print(student1,student1.name,student1.age)
print(student2,student2.name,student2.age)
运行结果
根据运行结果发现student1和student2是不同的对象,但包含的子对象是相同的,也就是前面所说的源对象与拷贝对象会引用同一个子对象。
十三、深拷贝
使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同。(也就是说源对象和拷贝对象都需要重新拷贝一份)
class Name:
pass
class Age:
pass
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
#创建实例化对象
name=Name()
#将name1的值赋值给name2
age=Age()
student1=Student(name,age)
#深拷贝拷贝
import copy
student2=copy.deepcopy(student1)
print(student1,student1.name,student1.age)
print(student2,student2.name,student2.age)
运行结果
发现,不仅源对象和拷贝对象不同,源对象和拷贝对象的子对象也是不同的。
十四、总结