面向对象
面向对象
与面向过程对比:二狗子准备结婚,需要盖房子
面向过程:数学逻辑的映射,学会做个好员工
面向对象:生活逻辑的映射,学会做个好领导
生活实例
类: 人 手机 电脑
对象: 习大大、黄友 杰哥的T2手机、路飞的iPhone X 杰哥的mac、李森的华硕
官方定义:
类:具有相同特征(属性和行为)事物的抽象
对象:某个类的具象
编程语言:
类:是一种自定义的数据类型
对象:某个类型的变量
类的语法
定义类:
class 类名: 内容
示例:定义一个人的类
# 定义类 class Person: # 行为的体现,通过方法 # 吃饭 def eat(self): print('红烧鸡腿我喜欢吃') # 打篮球 def play(self): print('俺喜欢打篮球')
声明对象
bryant = Person()
调用方法
bryant.eat()
bryant.play()
设置属性:是动态添加的
bryant.name = '科比.布莱恩特'
获取属性
print(bryant.name)
- 语法 - 定义类需要使用关键字:class - 类名:原则上只要符合标识符的命名规范即可,但是我们通常使用大驼峰风格(每个单词首字母大写)命名 - 不要忘记类名后面的冒号':' - 类的内容要进行缩进 - 行为:通过函数体现,与外面定义函数的方式相似,第一个参数默认是self - 属性:通过变量体现,属性是动态添加的,因此在定义时可以不体现 - 成员访问: - 成员属性:对象.属性名 - 成员方法:对象.方法名()- self - 示例: ```python
class Person:
def run(self):
# self表示当前对象:谁调用该方法就代表谁
print('{}每天以2m/s的速度锻炼5km'.format(self.name))
def introduce(self):
# self这个名字可以是任意的,但是通过都是要这个
# 既可以访问成员属性
print('我叫{}'.format(self.name))
# 也可以调用成员方法
self.run()
mugai = Person()
mugai.name = '木盖'
# print(mugai)
mugai.run()
curry = Person()
curry.name = '斯蒂芬.库里'
curry.run()
# 调用方法是第一个参数self不需要
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()
练习:
设计一个数学类,方法有加减乘除,并能展示结果
类属性
说明:定义类时,写在类中,但是方法外的属性,通过放在类的开头位置
示例:
class Person: # 定义类属性 nation = '中国' def __init__(self, name): self.name = name self.nation = 'china' # 通过类名访问类属性 print(Person.nation) p = Person('xiaoming') # 通过对象也可访问类属性,但是不建议 # 当对象有同名的成员属性时,使用的就是成员属性 print(p.nation) # 也可以动态添加 Person.hello = 'hello' print(Person.hello) # 特殊的类属性 # 表示的类名字符串 print(Person.__name__) # 表示父类构成的元组 print(Person.__bases__) # 存储类相关的信息 print(Person.__dict__)
类方法
说明:
定义时使用装饰器:classmethod
通过类名进行调用
作用:
可以创建对象或者简洁的创建对象
对外提供简单易用的接口
示例1:语法:
class Person: def eat(self): print('麻辣是我的最爱') # 使用装饰器 classmethod 修饰的方法 就是类方法 @classmethod def test(cls): print('类方法 test') # cls 表示当前类 print(cls) @classmethod def create(cls): p = cls() # 进行特定的初始化设置 p.age = 1 return p Person.test() # print(Person) # 可以创建或者简洁的创建对象 p = Person.create() print(p)
示例2:设计一个数字类,用于两个属性,能够进行加减乘除运算,要求:计算两个数的平方和
class Number: def __init__(self, num1, num2): self.num1 = num1 self.num2 = num2 def add(self): return self.num1 + self.num2 def sub(self): return self.num1 - self.num2 def mul(self): return self.num1 * self.num2 def div(self): if self.num2 == 0: return None return self.num1 / self.num2 @classmethod def pingfanghe(cls, num1, num2): # 第一个数 n1 = Number(num1, num1) # 求平方 n12 = n1.mul() # 第二个数 n2 = Number(num2, num2) # 求平方 n22 = n2.mul() # 第三个数 n3 = Number(n12, n22) return n3.add() he = Number.pingfanghe(3, 4) print(he)
静态方法
说明:
使用装饰器:staticmethod进行修饰
定义的方法没有第一个表示当前类参数
示例:
class Person: @staticmethod def test(): print('static method test') @staticmethod def create(): # 也可以创建对象 p = Person() return p Person.test() p = Person.create()
与类方法对比:
除了装饰器不同,其他基本一样,做与对象创建无关的任务时可以使用静态方法
所有静态方法能够完成的功能都是使用类方法完成
多态特性
定义:不同的对象,调用相同的方法有不同的响应称为多态
体现:多态性,不同对象接收相同的消息会有不同的响应。
示例:
class Animal: def run(self): pass class Dog(Animal): def run(self): print('狗奔跑的时候一般是s型') class Cat(Animal): def run(self): print('猫平时走猫步,偶尔会突然加速') # 参数必须有run方法 def func(obj): obj.run() func(Dog()) func(Cat())
属性函数
说明:就是将方法当做属性一样
作用:保护特定属性,处理特定属性
示例:
class User: def __init__(self, username, password): self.username = username self.__password = password # 使用property修饰的方法,可以当做属性访问 # 可以保护特定的属性 @property def password(self): print('有人想直接获取密码') # return self.__password return '哈哈,想偷看,没门' # 当设置password属性时,会自动调用该方法 @password.setter def password(self, password): print('注意了,有人想修改密码', password) # 可以对密码进行特定处理,然后保存 self.__password = 'xxx'+ password+'yyy' u = User('xiaoming', '123456') print(u.username) # 很多时候直接访问密码是不需要的,也是不安全的 # 直接访问password属性,自动回调用使用property修饰后的password方法 print(u.password) u.password = '654321'
内置方法- 说明: - 当将对象当做函数一样调用时,系统会自动触发 __ 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)
函数判断
问题:如何判断一个对象是否可以像函数一样调用
示例:
class A: def __call__(self, *args, **kwargs): print('xx') def test(): pass # 不能使用isinstance方法判断一个对象是否是函数 # isinstance(test, function) # 打印时仍然是function类型 # print(type(test)) # 判断一个对象是否可以像函数一样调用 print(callable(test)) a = A() print(callable(a)) # 判断对象是否拥有 call属性 print(hasattr(test, 'call')) print(hasattr(a, 'call')) # 判断是否是函数 from inspect import isfunction print(isfunction(test)) print(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()
- 说明:可以将对象保存到文件中,以便在合适的时候从文件中加载数据