目录
1、编程的两大思想,面向过程 VS 面向对象
1)面向过程和面向对象的区别:
- 面向过程,事物比较简单,可以用线性的思维去解决;
- 面向对象,事物比较复杂,使用简单的线性思维无法解决;
2)面向过程和面向对象的共同点:
- 都是解决实际问题的一种思维方式;
3)二者之间的关系:
- 解决复杂问题,通过面向对象方式,便于从宏观把握事物之间复杂的关系,方便分析整个系统;
- 具体到微观操作,仍然使用面向过程方式来处理;
- 如:想吃西红柿炒蛋,自己购买材料去做是面向过程;外卖下单购买,厨房接单制作,是面向对象;
2、类与对象
1)类
- 类别,多个类似事物组成的群体的统称,如人类,鸟类,动物类等;
2)数据类型
- 不同的数据类型属于不同的类;
- 使用内置函数查看数据类型;
# 不同的数据类型属于不同的类
print(type(100)) # <class 'int'>
print(type(50)) # <class 'int'>
print(type(10)) # <class 'int'>
3)对象
- 100,50,10都是int类之下包含的相似的不同个例,这个个例称为实例或对象;
- python中,一切皆对象;如字符串对象‘hello’,整数对象520,字典对象{'key':value},元组对象(10,20),列表对象[10,20]等;
3、类的创建
语法:
class Student:
pass
1)创建类
- Student为类的名称,由一个或多个单词组成,每个单词的首字母大写,其余小写;
- 类也占用内存空间,也有类型,也有value值;
# 创建类对象
class Student:
pass
print(id(Student)) # 占用了内存空间,1972126470016
print(type(Student)) # class类型,<class 'type'>
print(Student) # value值是<class '__main__.Student'>
2)类的组成
- 类属性,直接写在类里面的变量;
- 实例方法,在类外定义的是函数,在类内定义的是方法;
- 静态方法
- 类方法
创建学生类
# 创建学生类
class Student:
native_place = '吉林' # 类属性
def __init__(self, name, age): # 初始化方法
self.name = name # self.name是实例属性
self.age = age # 将局部变量age的值,赋值给self.age实例属性
# 实例方法
def info(self): # 传递的是类的对象self
print('我的名字叫:', self.name, '年龄是:', self.age)
# 类方法
@classmethod
def cm(cls): # 传递的是class
print('这是类方法')
# 静态方法
@staticmethod
def sm(): # 静态方法不允许传递值
print('这是静态方法')

在类外定义的是函数,在类内定义的是方法
# 类的方法和函数
# 类的方法
class Student:
def eat(self):
print('这是类的方法')
# 函数
def drink():
print('这是函数')
4、对象的创建
- 对象的创建,又称为类的实例化,类的实例创建;
- 有了实例,就可以调用类中的内容;
语法:
实例名 = 类名()
参考学生类
stu = Student('张三', 20)
print(id(stu)) # id = 1413659559584
print(type(stu)) # 对象的类型,<class '__main__.Student'>
print(stu) # 对象的id对应的16进制的地址,<__main__.Student object at 0x0000014924AD06A0>
print('-----------------')
print(id(Student)) # 2445954439664
print(type(Student)) # <class 'type'>
print(Student) # <class '__main__.Student'>
输出结果:
2443846615488
<class '__main__.Student'>
<__main__.Student object at 0x00000239009C01C0>
-----------------
2445954439664
<class 'type'>
<class '__main__.Student'>
Student是类对象,stu是实例对象;

调用方法的2种写法:
- 对象名.方法名(),如:stu.info()
- 类名.方法名(类的对象),实际就是方法定义处的self,如:Student.info(stu)
# 创建学生类
class Student:
native_place = '吉林' # 类属性
def __init__(self, name, age): # 初始化方法
self.name = name # self.name是实例属性
self.age = age # 将局部变量age的值,赋值给self.age实例属性
# 实例方法
def info(self): # 传递的是类的对象self
print('我的名字叫:', self.name, '年龄是:', self.age)
# 类方法
@classmethod
def cm(cls): # 传递的是class
print('这是类方法')
# 静态方法
@staticmethod
def sm(): # 静态方法不允许传递值
print('这是静态方法')
# 创建Student类的实例对象
stu = Student('jack', 20)
print(stu.name) # 实例属性
print(stu.age) # 实例属性
stu.info() # 调用实例方法
print('-------------------')
Student.info(stu) # 调用实例方法,另外一种写法
输出结果:
jack
20
我的名字叫: jack 年龄是: 20
-------------------
我的名字叫: jack 年龄是: 20
5、类属性,类方法,静态方法
- 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享;
- 类方法:使用@classmethod修饰的方法,使用类名直接访问的方法;
- 静态方法:使用@staticmethod修饰的方法,使用类名直接访问的方法;
# 创建Student类的实例对象
print(Student.native_place) # 访问类属性
Student.cm() # 调用类方法
Student.sm() # 调用静态方法
输出结果:
吉林
这是类方法
这是静态方法
类属性的使用方法
# 类属性的使用方法
print(Student.native_place)
stu1 = Student('张三', 10)
stu2 = Student('李四', 20)
print(stu1.native_place)
print(stu2.native_place)
print('-----修改类属性的值---------')
Student.native_place = '天津'
print(Student.native_place)
print(stu1.native_place)
print(stu2.native_place)
输出结果:
吉林
吉林
吉林
-----修改类属性的值---------
天津
天津
天津
6、动态绑定属性和方法
- python是动态语言,在创建对象之后,可以动态的绑定属性和方法;
- 一个Student类,可以创建N多个Student类的实例对象,每个实例对象的属性值不同;即stu1,stu2
- 一个Student类,只有一个类对象,即Student类对象
需求:只为stu1动态绑定性别属性,指向女;
- 创建对象stu1后,单独给这个对象stu1绑定一个属性gender;所以stu2是没有这个属性的;
1)动态绑定属性
# 动态绑定属性
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '在吃饭')
stu1 = Student('张三', 20)
stu2 = Student('李四', 30)
print('---------只为stu1动态绑定性别属性,指向女----------')
stu1.gender = '女'
print(stu1.name, stu1.age, stu1.gender)
print(stu2.name, stu2.age)
# print(stu2.gender) # stu2没有绑定属性gender,会报错,AttributeError: 'Student' object has no attribute 'gender'
输出结果:
张三 20 女
李四 30
2)动态绑定方法
# 动态绑定方法
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '在吃饭')
stu1 = Student('张三', 20)
stu2 = Student('李四', 30)
stu1.eat()
stu2.eat()
print('---------只为stu1动态绑定show()方法----------')
def show_stu1():
print('定义在类之外的,是函数')
stu1.show = show_stu1
stu1.show()
# stu2.show() # stu2没有绑定show()方法,所以调用show()会报错,AttributeError: 'Student' object has no attribute 'show'
输出结果:
张三在吃饭
李四在吃饭
---------只为stu1动态绑定show()方法----------
定义在类之外的,是函数
为stu1动态绑定属性和方法的示意图:

7、总结

二、面向对象的三大特征
1、封装
- 提高程序的安全性;
- 将数据(属性)和行为(方法)包装到类对象中;
- 在方法内部对属性进行操作,在类对象的外部调用方法;
- 无需关心方法内部的具体实现细节,从而隔离了复杂度;
- python中没有专门的修饰用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个“_”
# 封装
# 对汽车进行封装
class Car:
def __init__(self, brand):
self.brand = brand
def start(self):
print(self.brand, '品牌的车启动了')
car = Car('宝马X5')
car.start()
print(car.brand)
输出结果:
宝马X5 品牌的车启动了
宝马X5
属性不希望在类对象外部被访问,前边使用两个“_”
- 私有属性,不能直接被访问,报错,AttributeError: 'Student' object has no attribute '__age'
- 在类的外部可以通过 _类名__变量进行访问私有的属性,如_Student__age
# 属性不希望在类对象外部被访问,前边使用两个“_”
class Student:
def __init__(self, name, age):
self.name = name
self.__age = age # age不希望在类的外部被使用,所有加了两个_
def show(self):
print(self.name, self.__age)
stu = Student('张三', 20)
print(stu.name)
# print(stu.__age) # 私有属性,不能直接被访问,报错,AttributeError: 'Student' object has no attribute '__age'
stu.show()
print(dir(stu)) # 查看stu对象的所有属性
print(stu._Student__age) # 在类的外部可以通过 _类名__变量进行访问私有的属性,如_Student__age
输出结果:
张三
张三 20
['_Student__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'show']
20
2、继承
- 提高代码的复用性;
- 如果一个类没有继承任何类,则默认继承object;
- python支持多继承;
- 定义子类时,必须在子类的构造函数中调用父类的构造函数;
语法:
class 子类类名(父类1,父类2……):
pass
# 继承
class Person(object): # 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, stu_no):
super().__init__(name, age)
self.stu_no = stu_no
class Teacher(Person):
def __init__(self, name, age, teachofyear):
super().__init__(name, age)
self.teachofyear = teachofyear
stu = Student('张学生', 10, '1001')
teacher = Teacher('李老师', 20, 5)
stu.info()
teacher .info()
输出结果:
张学生 10
李老师 20
多继承,一个子类可以有多个父类
语法格式:
# 多继承
class A(object):
pass
class B(object):
pass
class sub(A, B):
pass
3、方法重写
- 如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写;
- 子类重写后的方法中,可以通过super().xxx()调用父类中被重写的方法;
- super().__init__(name, age) # 去执行父类中的构造方法,传入父类构造方法需要的参数
- super().info() # 去执行父类中的方法
# 方法重写
class Person(object): # 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, stu_no):
super().__init__(name, age) # 去执行父类中的构造方法
self.stu_no = stu_no # 执行子类自己的代码
def info(self): # 子类中方法重写
super().info() # 去执行父类中的方法
print('学号:{0}'.format(self.stu_no)) # 执行子类自己的代码
class Teacher(Person):
def __init__(self, name, age, teachofyear):
super().__init__(name, age)
self.teachofyear = teachofyear
def info(self): # 子类中方法重写
super().info()
print('教龄:{0}'.format(self.teachofyear))
stu = Student('张学生', 10, '1001')
teacher = Teacher('李老师', 20, 5)
stu.info()
teacher .info()
输出结果:
张学生 10
学号:1001
李老师 20
教龄:5
其他补充
类内部定义的变量,只在实例化后的对象中有效,哪个实例修改了,哪个实例可以获取到修改后的值,不影响其他未做修改的实例;
class Father(object):
var = 10
def __init__(self, name):
self.name = name
self.age = 18
if __name__ == '__main__':
father1 = Father('小明')
father2 = Father('小马')
father1.var = 20
print("father1.var的值为:", father1.var)
print("father2.var的值为:", father2.var)
输出结果:father1对象修改了var的值,father1获取var值时,就是20;但是不影响father2的var的值;
father1.var的值为: 20
father2.var的值为: 10
- 类或类的方法中定义的变量,都可以通过类的实例化对象进行修改;
- 一个对象修改了属性的值,不会影响另外一个对象对属性的取值,另外一个对象取到的还是未修改前的值;
- 在非构造函数中定义的属性,如self.test1,因为自定义的方法,不会在运行时自动加载,所以未运行test()方法前取属性test1的值,会报错;运行过test()方法后,再取属性test1的值,就不会报错;
class Father(object):
var = 10
def __init__(self, name):
self.name = name
self.age = 18
def test(self):
self.test1 = 'test1'
print("self.test1值为:", self.test1)
return "test方法返回字符串"
if __name__ == '__main__':
father = Father('小明')
father.var = 20
father.name = '小红'
father.age = 30
father.test1 = 'test2'
print("father.var的值为:", father.var)
print("father.name的值为:", father.name)
print("father.age的值为:", father.age)
print("father.test1的值为:", father.test1)
father2 = Father('小黄')
print("father2.var的值为:", father2.var)
print("father2.name的值为:", father2.name)
print("father2.age的值为:", father2.age)
print("father2.test1的值为:", father2.test1) # 报错'Father' object has no attribute 'test1'
输出结果:father对象中的属性取值,都是修改后的值;father2对象中的属性取值,还是未修改前的值,即father改变了属性值,father2不会被影响,取到的不是修改后的值;
father.var的值为: 20
father.name的值为: 小红
father.age的值为: 30
father.test1的值为: test2
father2.var的值为: 10
father2.name的值为: 小黄
father2.age的值为: 18
- 子类的对象可以引用父类的属性和方法;
- 但是子类中定义了构造方法后,就不能直接引用父类的构造方法中定义的属性了;
class Father(object):
var = 10
def __init__(self, name):
self.name = name
self.age = 18
def test(self):
self.test1 = 'test1'
print("self.test1值为:", self.test1)
return "test方法返回字符串"
class Son(Father):
def __init__(self):
self.sex = '男'
if __name__ == '__main__':
son = Son()
print("son.sex的值为:", son.sex)
print("son.var的值为:", son.var)
# print("son.name的值为:", son.name) # 'Son' object has no attribute 'name'
# print("son.age的值为:", son.age) # 'Son' object has no attribute 'age'
print(son.test())
print("son.test1的值为:", son.test1)
输出结果:son对象可以引用父类的var属性,不能引用父类的name和age属性;son对象可以引用父类的test()方法,以及方法中定义的属性test1
son.sex的值为: 男
son.var的值为: 10
self.test1值为: test1
test方法返回字符串
son.test1的值为: test1
Python子类执行构造方法的三种情况
- 1. 子类不重写 __init__,实例化子类时,会自动调用父类定义的 __init__。
- 2. 如果重写了__init__ 时,实例化子类,就不会调用父类已经定义的 __init__。
- 3. 如果重写了__init__ 时,要继承父类的构造方法,可以使用 super 关键字。
重写了__init__ 时,要继承父类的构造方法,可以使用 super 关键字:2种写法都可以
super(子类,self).__init__(参数1,参数2,....)
父类名称.__init__(self,参数1,参数2,...)
子类中定义了构造方法,如果还想要能够访问父类中的构造方法,可以有如下几种写法:
super(Son, self).__init__(son_name) # 执行父类的构造方法;传入父类构造函数需要的参数son_name,并且子类的构造函数也要传入son_name
Father.__init__(self, son_name) # 执行父类的构造方法
super(子类,self).__init__(参数1,参数2,....)
class Father(object):
def __init__(self, name):
self.name = name
self.age = 18
class Son(Father):
def __init__(self, son_name):
super(Son, self).__init__(son_name) # 执行父类的构造方法
self.sex = '男'
if __name__ == '__main__':
son = Son("儿子")
print("son.name的值为:", son.name) # 'Son' object has no attribute 'name'
print("son.age的值为:", son.age) # 'Son' object has no attribute 'age'
输出结果:
son.name的值为: 儿子
son.age的值为: 18
父类名称.__init__(self,参数1,参数2,...)
class Father(object):
def __init__(self, name):
self.name = name
self.age = 18
class Son(Father):
def __init__(self, son_name):
Father.__init__(self, son_name) # 执行父类的构造方法
self.sex = '男'
if __name__ == '__main__':
son = Son("儿子")
print("son.name的值为:", son.name) # 'Son' object has no attribute 'name'
print("son.age的值为:", son.age) # 'Son' object has no attribute 'age'
输出结果:
son.name的值为: 儿子
son.age的值为: 18
4、object类
- object 类是所有类的父类,因此所有类都有object类的属性和方法;
- 内置函数dir(),可以查看指定对象所有属性;
- object类的__str__()方法,用于返回一个对象描述,对应于内置函数str(),经常用于print()方法,查看对象的信息,所以__str__()经常会被重写;
# object类
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '我的名字是{0},我的年龄是{1}'.format(self.name, self.age)
stu = Student('张三', '20')
print(dir(stu))
# print(stu) # 重写方法前输出:<__main__.Student object at 0x0000024DBB6B4700>
print(stu) # 重写方法后输出:我的名字是张三,我的年龄是20
print(type(stu))
输出结果:子类中,__str__方法被重写了
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
我的名字是张三,我的年龄是20
<class '__main__.Student'>
5、多态
- 提高程序的可扩展性和可维护性;
- 即具有多种形态,指即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法;

静态语言和动态语言
1)静态语言和动态语言关于多态的区别
静态语言实现多态的三个必要条件:如java
- 明确继承关系
- 方法重写
- 父类引用指向子类对象
动态语言的多态,是鸭子类型,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为;即不用关心Person是谁的子类,只要Person有eat方法就可以了;
# 多态
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('人吃五谷杂粮')
# 定义一个函数,可以传入任意对象
def fun(animal):
animal.eat() # 对象调用eat()方法
# 开始调用函数
fun(Dog())
fun(Cat())
fun(Animal())
fun(Person())
输出结果:
狗要吃肉
猫吃鱼
动物要吃东西
人吃五谷杂粮
6、特殊方法和特殊属性
- 两个_开始和两个_结束的属性和方法;
1)特殊属性
- dir() 查看object类对象的属性和方法
- __dict__查看实例对象的所有实例属性,或查看类对象的所有属性和方法的字典;
- __class__显示对象所属的类型
- __bases__输出类对象的父类的类型,返回元组
- __base__输出与C类最近的一个父类
- __mro__输出类的层次结构,返回元组
- __subclasses__()输出子类列表, 返回列表
dir() 查看object类对象的属性和方法
# 特殊属性
print(dir(object)) # dir() 查看object类对象的属性和方法
输出结果:
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
创建类
class A:
pass
class B:
pass
class C(A, B):
lst = ['hello']
def __init__(self,name, age):
self.name = name
self.age = age
def info(self):
pass
class D(A):
pass
1>> __dict__查看实例对象的所有实例属性,或查看类对象的所有属性和方法的字典
# __dict__查看实例对象的所有实例属性,或查看类对象的所有属性和方法的字典
x = C('jack', 10)
print(x.__dict__) # C类的实例对象c,绑定的所有实例属性,返回字典,{'name': 'jack', 'age': 10}
print(C.__dict__) # C类对象绑定的所有属性和方法,返回字典
输出结果:
{'name': 'jack', 'age': 10}
{'__module__': '__main__', 'lst': ['hello'], '__init__': <function C.__init__ at 0x000001C06F2EA550>, 'info': <function C.info at 0x000001C06F2EA5E0>, '__doc__': None}
2>> __class__显示对象所属的类型
# __class__显示对象所属的类型
print(x.__class__) # __class__显示对象所属的类型,<class '__main__.C'>
print(C.__class__) # <class 'type'>
输出结果:
<class '__main__.C'>
<class 'type'>
3>> __bases__输出类对象的父类的类型,返回元组
# 输出类对象的父类的类型,返回元组
# print(x.__bases__) # 实例对象没有__bases__属性,会报错AttributeError: 'C' object has no attribute '__bases__'
print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)
输出结果:
(<class '__main__.A'>, <class '__main__.B'>)
4>> __base__输出与C类最近的一个父类
# 输出与C类最近的一个父类
print(C.__base__) # class C(A,B) 只返回<class '__main__.A'>
print(C.__base__) # class C(B,A) 只返回<class '__main__.B'>
5>> __mro__输出类的层次结构,返回元组
# __mro__输出类的层次结构,返回元组
print('------输出类的层次结构--------')
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
print(D.__mro__) # (<class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
print(A.__mro__) # (<class '__main__.A'>, <class 'object'>)
print(B.__mro__) # (<class '__main__.B'>, <class 'object'>)
print(object.__mro__) # (<class 'object'>,)
输出结果:
------输出类的层次结构--------
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
(<class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
(<class '__main__.A'>, <class 'object'>)
(<class '__main__.B'>, <class 'object'>)
(<class 'object'>,)
6>> __subclasses__()输出子类列表, 返回列表
# __subclasses__()输出子类列表, 返回列表
print('------输出子类--------')
print(A.__subclasses__()) # [<class '__main__.C'>, <class '__main__.D'>]
print(B.__subclasses__()) # [<class '__main__.C'>]
print(C.__subclasses__()) # []
print(D.__subclasses__()) # []
print('object的子类有:', object.__subclasses__()) # <class '__main__.C'>, <class '__main__.D'>不是object的子类
输出结果:
------输出子类--------
[<class '__main__.C'>, <class '__main__.D'>]
[<class '__main__.C'>]
[]
[]
object的子类有: [<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>, <class 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>, <class 'types.SimpleNamespace'>, <class 'PyCapsule'>, <class 'longrange_iterator'>, <class 'cell'>, <class 'instancemethod'>, <class 'classmethod_descriptor'>, <class 'method_descriptor'>, <class 'callable_iterator'>, <class 'iterator'>, <class 'pickle.PickleBuffer'>, <class 'coroutine'>, <class 'coroutine_wrapper'>, <class 'InterpreterID'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class 'hamt'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'keys'>, <class 'values'>, <class 'items'>, <class 'Context'>, <class 'ContextVar'>, <class 'Token'>, <class 'Token.MISSING'>, <class 'moduledef'>, <class 'module'>, <class 'filter'>, <class 'map'>, <class 'zip'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class 'classmethod'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'nt.ScandirIterator'>, <class 'nt.DirEntry'>, <class 'PyHKEY'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'async_generator'>, <class 'collections.abc.Iterable'>, <class 'bytes_iterator'>, <class 'bytearray_iterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'range_iterator'>, <class 'set_iterator'>, <class 'str_iterator'>, <class 'tuple_iterator'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Callable'>, <class 'os._wrap_close'>, <class 'os._AddedDllDirectory'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>, <class 'MultibyteCodec'>, <class 'MultibyteIncrementalEncoder'>, <class 'MultibyteIncrementalDecoder'>, <class 'MultibyteStreamReader'>, <class 'MultibyteStreamWriter'>, <class '__main__.A'>, <class '__main__.B'>]
2)特殊方法
- __len__() 通过重写__len__()方法,让内置函数len的参数可以是自定义类型;
- __add__() 通过重写__add__() 方法,可使用自定义对象具有"+"功能;
- __new__() 用于创建对象;
- __init__() 对创建的对象进行初始化;
1>> __add__() 通过重写__add__() 方法,可使用自定义对象具有"+"功能;
# 特殊方法__add__()
a = 20
b = 100
c = a + b # 两个整数类型的对象相加运算
d = a.__add__(b) # 两个整数类型的对象相加运算
print(c)
print(d)
# 自定义类型如类的实例对象,让2个对象执行相加操作,要重写__add__()方法
class Student:
def __init__(self, name):
self.name = name
def __add__(self, other): # concatenate str to str
return self.name + other.name
stu1 = Student('jack')
stu2 = Student('lucy')
s = stu1 + stu2 # __add__()方法,实现了2个对象的加法运算
print(s) # 如果Student类没有重写__add__()方法,会报错,TypeError: unsupported operand type(s) for +: 'Student' and 'Student'
print(stu1.__add__(stu2))
输出结果:
120
120
jacklucy
jacklucy
2>> 输出对象的长度,重写__len__()方法
# 特殊方法__len__
lst = [1, 2, 3]
print(len(lst)) # len()内置函数,计算列表的长度
print(lst.__len__()) # 特殊方法__len__,计算列表的长度
# 输出对象的长度,重写__len__()方法
class Student:
def __init__(self, name):
self.name = name
def __len__(self):
return len(self.name)
x = Student('jacky1')
# print(len(x)) # 报错,TypeError: object of type 'Student' has no len()
print(len(x)) # 重写__len__()方法后,不会报错,输出对象name的长度
print(x.__len__()) # 重写__len__()方法后,不会报错,输出对象name的长度
输出结果:
3
3
6
6
3>> __new__() 用于创建对象;
- __init__() 对创建的对象进行初始化;
# 特殊方法__new__和__init__
class Person(object):
# __new__用于创建对象
def __new__(cls, *args, **kwargs):
print('__new__(cls, *args, **kwargs)被调用了,cls是Person类对象,cls的id值为{0}'.format(id(cls))) # Person类对象,2960168107376
obj = super().__new__(cls) # 调用父类object的创建对象,
print('创建的Person类的实例对象id为{0}'.format(id(obj))) # Person类的实例对象,2960206267968
return obj
# __init__给实例对象的属性进行初始化
def __init__(self, name, age):
print('__init__(self, name, age)被调用了,self是实例对象,self的id值为{0}'.format(id(self))) # Person类的实例对象,2960206267968
self.name = name
self.age = age
print('object类对象的id为:{0}'.format(id(object))) # object类对象,140718298803024
print('Person类对象的id为:{0}'.format(id(Person))) # Person类对象,2960168107376
# 创建Person类的实例对象
print('\n-------创建Person类的实例对象前-----------')
p = Person('jack', 20)
print('\n-------创建Person类的实例对象后-----------')
print('Person类实例对象p的id为:{0}'.format(id(p))) # Person类的实例对象,2960206267968
输出结果:
object类对象的id为:140718298803024
Person类对象的id为:2960168107376
-------创建Person类的实例对象前-----------
__new__(cls, *args, **kwargs)被调用了,cls是Person类对象,id值为2960168107376
创建的Person类的实例对象id为2960206267968
__init__(self, name, age)被调用了,self是实例对象,self的id值为2960206267968
-------创建Person类的实例对象后-----------
Person类实例对象p的id为:2960206267968
7、类的浅拷贝与深拷贝
1)变量的赋值操作
- 只是形成两个变量,实际上还是指向同一个对象;
类对象的赋值操作
- 通过CPU类创建了CPU类的实例对象;
- 将实例对象赋值给变量cpu1,cpu2;

# CPU类
class CPU:
pass
# 硬盘类
class Disk:
pass
# CPU和硬盘组装成计算机
class Computer:
def __init__(self, cpu, disk):
self.cpu = cpu
self.disk = disk
# 1、变量的赋值
cpu1 = CPU()
cpu2 = cpu1
cpu3 = CPU()
print(cpu1, id(cpu1)) # <__main__.CPU object at 0x000002660F4C87C0> 2637366593472
print(cpu2, id(cpu2)) # <__main__.CPU object at 0x000002660F4C87C0> 2637366593472
print(cpu3, id(cpu3)) # <__main__.CPU object at 0x000002660F49F820> 2637366425632
输出结果:
<__main__.CPU object at 0x000002660F4C87C0> 2637366593472
<__main__.CPU object at 0x000002660F4C87C0> 2637366593472
<__main__.CPU object at 0x000002660F49F820> 2637366425632
2)浅拷贝
- python拷贝,一般都是浅拷贝(没有特殊说明时);
- 拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象;
-
拷贝时,只拷贝子对象的引用,不拷贝子对象的内容;
import copy
computer2 = copy.copy(computer)

# 类有浅拷贝
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self, cpu, disk):
self.cpu = cpu
self.disk = disk
cpu1 = CPU() # 创建一个CPU类的对象
disk = Disk() # 创建一个硬盘类的对象
computer = Computer(cpu1, disk) # 创建一个计算机类的对象
# 浅拷贝
import copy
computer2 = copy.copy(computer)
# computer和computer2是不同的对象,所包含的子对象cpu和disk,却是相同的对象
print(id(cpu1))
print(id(disk))
print(id(computer), id(computer.cpu), id(computer.disk))
print(id(computer2), id(computer2.cpu), id(computer2.disk))
print(computer is computer2) # False,浅拷贝后,computer2与computer不同
print(computer.cpu is computer2.cpu) # True,浅拷贝后,computer2的子对象cpu与computer的子对象disk相同
print(computer.disk is computer2.disk) # True,浅拷贝后,computer2的子对象disk与computer的子对象disk相同
输出结果
2724301277120
2724301109280
2724301107840 2724301277120 2724301109280
2724301776880 2724301277120 2724301109280
False
True
True
3)深拷贝
- 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象;
- 源对象和拷贝对象所有的子对象也不相同;

# 类有深拷贝
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self, cpu, disk):
self.cpu = cpu
self.disk = disk
cpu1 = CPU() # 创建一个CPU类的对象
disk = Disk() # 创建一个硬盘类的对象
computer = Computer(cpu1, disk) # 创建一个计算机类的对象
# 深拷贝
import copy
computer2 = copy.deepcopy(computer)
# computer和computer2是不同的对象,所包含的子对象cpu和disk,也是不同的对象
print(id(cpu1))
print(id(disk))
print(id(computer), id(computer.cpu), id(computer.disk))
print(id(computer2), id(computer2.cpu), id(computer2.disk))
print(computer is computer2) # False,深拷贝后,computer2与computer不同
print(computer.cpu is computer2.cpu) # False,深拷贝后,computer2的子对象cpu与computer的子对象disk不同
print(computer.disk is computer2.disk) # False,深拷贝后,computer2的子对象disk与computer的子对象disk不同
输出结果:
2724301277120
2724301109280
2724301107840 2724301277120 2724301109280
2724301776880 2724301277916 2724301103924
False
False
False
三、总结

本文详细介绍了Python的面向对象编程,包括面向过程与面向对象的对比、类与对象的概念、类的创建和对象的实例化、类属性、类方法、静态方法、动态绑定属性和方法。同时,深入探讨了面向对象的三大特征:封装、继承和方法重写,并通过实例解析了Python中子类执行构造方法的三种情况、多态性以及特殊方法和特殊属性。此外,还讨论了类的浅拷贝与深拷贝的差异。

8172

被折叠的 条评论
为什么被折叠?



