面向对象
面向对象
-
与面向过程对比:二狗子准备结婚,需要盖房子
-
面向过程:数学逻辑的映射,学会做个好员工
-
面向对象:生活逻辑的映射,学会做个好领导
-
-
生活实例
-
类: 人 手机 电脑
-
对象: 习大大、黄友 杰哥的T2手机、路飞的iPhone X 杰哥的mac、李森的华硕
-
-
官方定义:
-
类:具有相同特征(属性和行为)事物的抽象
-
对象:某个类的具象
-
-
编程语言:
-
类:是一种自定义的数据类型
-
对象:某个类型的变量
-
类的语法
-
定义类:
class 类名: 内容 -
示例:定义一个人的类
1# 定义类 2class Person: 3 # 行为的体现,通过方法 4 5 # 吃饭 6 def eat(self): 7 print('红烧鸡腿我喜欢吃') 8 9 # 打篮球 10 def play(self): 11 print('俺喜欢打篮球') -
声明对象
bryant = Person()
-
调用方法
bryant.eat()
bryant.play()
-
设置属性:是动态添加的
bryant.name = '科比.布莱恩特'
-
获取属性
print(bryant.name)
1- 语法 - 定义类需要使用关键字:class - 类名:原则上只要符合标识符的命名规范即可,但是我们通常使用大驼峰风格(每个单词首字母大写)命名 - 不要忘记类名后面的冒号':' - 类的内容要进行缩进 - 行为:通过函数体现,与外面定义函数的方式相似,第一个参数默认是self - 属性:通过变量体现,属性是动态添加的,因此在定义时可以不体现 - 成员访问: - 成员属性:对象.属性名 - 成员方法:对象.方法名()- self - 示例: ```python 2 3class Person: 4 def run(self): 5 # self表示当前对象:谁调用该方法就代表谁 6 print('{}每天以2m/s的速度锻炼5km'.format(self.name)) 7 8 def introduce(self): 9 # self这个名字可以是任意的,但是通过都是要这个 10 11 # 既可以访问成员属性 12 print('我叫{}'.format(self.name)) 13 # 也可以调用成员方法 14 self.run() 15 16 mugai = Person() 17 mugai.name = '木盖' 18 19 # print(mugai) 20 mugai.run() 21 22 curry = Person() 23 curry.name = '斯蒂芬.库里' 24 curry.run() 25 # 调用方法是第一个参数self不需要 26 curry.introduce()
-
说明:
-
每个成员方法都有这么一个参数,调用的时候不需要传递
-
名字可以不是self,只不过通常我们都是要self而已
-
self表示当前对象,谁调用该方法就表示谁,哪个对象调用就代表哪个对象
-
通过self可以访问成员属性,也可以调用成员方法
-
-
__ str __方法
-
示例:
class Person: # 使用print函数打印对象时,默认打印对象所属类型及对象地址 # 该函数要求返回一个字符串,当对象作为print参数打印时会打印该字符串 def str(self): # 要求返回一个字符串 return '我叫{},今年{}'.format(self.name, self.age) xiaoming = Person()xiaoming.name = '小明'xiaoming.age = 18
print(xiaoming)
-
- 练习:
- 自定义一个狗类,完成属性的动态添加,方法的调用
- 属性:名字、年龄、颜色
- 方法:跑、吃、游泳、叫
-
构造方法
-
作用:用于对象创建后初始化相关的属性
-
示例:
class Cat: def init(self, name, age): # 创建对象后进行初始化操作,系统会自动调用 # 也叫构造方法 print('init') self.name = name self.age = age self.color = '白色'
创建对象时的参数要与构造方法一致
tom = Cat('Tom', 1) print(tom)
-
-
析构方法
-
作用:当对象即将销毁时,系统会自动调用
-
示例:
class Pig: def del(self): # 当对象释放时系统会自动调用,如果使用del删除对象,则立即释放调用该方法 # 一般在此处做:断开连接、关闭文件、释放资源等 print('大师兄,我不行了') bajie = Pig()
若删除对象,则会立即调用 析构方法
del bajie print('一路走好')
-
-
示例:小明手里有两张牌,左手♥K,右手♠A,问:小明交换两手的牌后,手里分别是什么?
-
思路:
-
先找到对象:小明、左手、♥K、♠A、右手
-
根据对象抽象出来对应的类:人、牌、手
-
写出对应的逻辑,反过来完善抽象出来的类
-
按照题目的要求创建对应的对象,调用相关的方法
-
-
代码:
扑克牌
class Poker: def init(self, color, number): self.color = color self.number = number def str(self): return '{}{}'.format(self.color, self.number)
创建两张牌
p1 = Poker('♥', 'K') p2 = Poker('♠', 'A')
手的类
class Hand: def init(self, poker=None): self.poker = poker def hold_poker(self, poker): self.poker = poker
创建左右两只手的对象
left_hand = Hand(p1) right_hand = Hand(p2)
人的类
class Person: def init(self, name, left_hand, right_hand): self.name = name self.left_hand = left_hand self.right_hand = right_hand # 展示手里的牌 def show(self): print('{}张开手'.format(self.name)) print('左手:{}'.format(self.left_hand.poker)) print('右手:{}'.format(self.right_hand.poker)) # 交换两手的牌 def swap(self): self.left_hand.poker, self.right_hand.poker = self.right_hand.poker, self.left_hand.poker print('{}交换两手的牌'.format(self.name))
创建小明对象
xiaoming = Person('小明', left_hand, right_hand)
展示手里的牌
xiaoming.show()
小明交换牌
xiaoming.swap()
再次展示
xiaoming.show()
-
-
练习:
-
设计一个数学类,方法有加减乘除,并能展示结果
类属性
-
说明:定义类时,写在类中,但是方法外的属性,通过放在类的开头位置
-
示例:
1class Person: 2 # 定义类属性 3 nation = '中国' 4 5 def __init__(self, name): 6 self.name = name 7 self.nation = 'china' 8 9# 通过类名访问类属性 10print(Person.nation) 11 12p = Person('xiaoming') 13# 通过对象也可访问类属性,但是不建议 14# 当对象有同名的成员属性时,使用的就是成员属性 15print(p.nation) 16 17# 也可以动态添加 18Person.hello = 'hello' 19print(Person.hello) 20 21# 特殊的类属性 22# 表示的类名字符串 23print(Person.__name__) 24 25# 表示父类构成的元组 26print(Person.__bases__) 27 28# 存储类相关的信息 29print(Person.__dict__)
类方法
-
说明:
-
定义时使用装饰器:classmethod
-
通过类名进行调用
-
-
作用:
-
可以创建对象或者简洁的创建对象
-
对外提供简单易用的接口
-
-
示例1:语法:
1class Person: 2 def eat(self): 3 print('麻辣是我的最爱') 4 5 # 使用装饰器 classmethod 修饰的方法 就是类方法 6 @classmethod 7 def test(cls): 8 print('类方法 test') 9 # cls 表示当前类 10 print(cls) 11 12 @classmethod 13 def create(cls): 14 p = cls() 15 # 进行特定的初始化设置 16 p.age = 1 17 return p 18 19Person.test() 20# print(Person) 21# 可以创建或者简洁的创建对象 22p = Person.create() 23print(p) -
示例2:设计一个数字类,用于两个属性,能够进行加减乘除运算,要求:计算两个数的平方和
1class Number: 2 def __init__(self, num1, num2): 3 self.num1 = num1 4 self.num2 = num2 5 6 def add(self): 7 return self.num1 + self.num2 8 9 def sub(self): 10 return self.num1 - self.num2 11 12 def mul(self): 13 return self.num1 * self.num2 14 15 def div(self): 16 if self.num2 == 0: 17 return None 18 return self.num1 / self.num2 19 20 @classmethod 21 def pingfanghe(cls, num1, num2): 22 # 第一个数 23 n1 = Number(num1, num1) 24 # 求平方 25 n12 = n1.mul() 26 27 # 第二个数 28 n2 = Number(num2, num2) 29 # 求平方 30 n22 = n2.mul() 31 32 # 第三个数 33 n3 = Number(n12, n22) 34 35 return n3.add() 36 37he = Number.pingfanghe(3, 4) 38print(he)
静态方法
-
说明:
-
使用装饰器:staticmethod进行修饰
-
定义的方法没有第一个表示当前类参数
-
-
示例:
1class Person: 2 @staticmethod 3 def test(): 4 print('static method test') 5 6 @staticmethod 7 def create(): 8 # 也可以创建对象 9 p = Person() 10 return p 11 12 Person.test() 13 14 p = Person.create()与类方法对比:
-
除了装饰器不同,其他基本一样,做与对象创建无关的任务时可以使用静态方法
-
所有静态方法能够完成的功能都是使用类方法完成
-
多态特性
-
定义:不同的对象,调用相同的方法有不同的响应称为多态
-
体现:多态性,不同对象接收相同的消息会有不同的响应。
-
示例:
1class Animal: 2 def run(self): 3 pass 4 5class Dog(Animal): 6 def run(self): 7 print('狗奔跑的时候一般是s型') 8 9class Cat(Animal): 10 def run(self): 11 print('猫平时走猫步,偶尔会突然加速') 12 13 14# 参数必须有run方法 15def func(obj): 16 obj.run() 17 18func(Dog()) 19func(Cat())
属性函数
-
说明:就是将方法当做属性一样
-
作用:保护特定属性,处理特定属性
-
示例:
1class User: 2 def __init__(self, username, password): 3 self.username = username 4 self.__password = password 5 6 # 使用property修饰的方法,可以当做属性访问 7 # 可以保护特定的属性 8 @property 9 def password(self): 10 print('有人想直接获取密码') 11 # return self.__password 12 return '哈哈,想偷看,没门' 13 14 # 当设置password属性时,会自动调用该方法 15 @password.setter 16 def password(self, password): 17 print('注意了,有人想修改密码', password) 18 # 可以对密码进行特定处理,然后保存 19 self.__password = 'xxx'+ password+'yyy' 20 21u = User('xiaoming', '123456') 22print(u.username) 23# 很多时候直接访问密码是不需要的,也是不安全的 24# 直接访问password属性,自动回调用使用property修饰后的password方法 25print(u.password) 26u.password = '654321' 27 28内置方法- 说明: - 当将对象当做函数一样调用时,系统会自动触发 __ call __ 方法 - 若想支持这样的操作,系统在类中提供 __ call __ 方法- 示例: ```python
class Person: # 当对象当做函数一样调用时,系统会自动触发该方法 def call(self, *args, **kwargs): # 如:计算和 return sum(args) p = Person()
将对象当做函数使用,需要提供 call 方法
ret = p(1,2,3, name='xiaoming') print(ret)
函数判断
-
问题:如何判断一个对象是否可以像函数一样调用
-
示例:
1class A: 2 def __call__(self, *args, **kwargs): 3 print('xx') 4 5def test(): 6 pass 7 8# 不能使用isinstance方法判断一个对象是否是函数 9# isinstance(test, function) 10 11# 打印时仍然是function类型 12# print(type(test)) 13 14# 判断一个对象是否可以像函数一样调用 15print(callable(test)) 16a = A() 17print(callable(a)) 18 19# 判断对象是否拥有 call属性 20print(hasattr(test, 'call')) 21print(hasattr(a, 'call')) 22 23# 判断是否是函数 24from inspect import isfunction 25print(isfunction(test)) 26print(isfunction(a))
数据持久化存储
-
方式:普通文件、数据库、序列化
-
示例:
import pickle
class Person: def init(self, name, age): self.name = name self.age = age
存储:对象 => 文件
xiaoming = Person('小明', 18)
fp = open('text.txt', 'wb')
pickle.dump(xiaoming, fp)
print('对象数据已存储完毕')
读取:文件 => 对象
fp = open('text.txt', 'rb') xiaoming = pickle.load(fp)
print(xiaoming.name) print(xiaoming.age)
fp.close()
- 说明:可以将对象保存到文件中,以便在合适的时候从文件中加载数据