part1
1.封装
概述
如果写代码时,函数比较多比较乱:
- 可以将函数归类并放到同一个类中。(方法封装到类中)
- 函数如果有一个反复使用的公共值,则可以放到对象中。(相同的参数封装到对象中)
对比面向过程和面向对象:
-
面向过程
将多个def函数分别归类到不同的文件夹、py文件中,在main函数需要使用的时候通过from … import …的方式进行调用
-
面向对象
使用class进行封装:将同一类的函数(方法)封装到一个类中。
class Goods:
def goods(self):
pass
def func2(self):
pass
一般习惯:类名首字母大写(函数名:除第一个单词外首字母大写)
应用场景:遇到很多函数,需要给函数进行归类和划分。【封装】
基本格式
# 函数
def func():
pass
# 调用
from src import account
account.login()
account.logout()
# 定义一个类(类名:Account)
class Account:
# 方法
def login(self):
print("登录")
def logout(self,name):
print(name+"注销")
return 12
# 调用
# 首先要创建一个类的对象(或者称为实例化)
x = Account()
# 使用对象调用类中的方法
x.login()
num = x.logout("wany")
print(num)
【练习】 假设有n个功能函数,进行封装
class Db:
#数据库操作
def db_add(self):
pass
def db_del(self):
pass
def db_change(self):
pass
def db_query(self):
pass
class File:
#文件操作
def file_add(self):
pass
def file_del(self):
pass
def file_change(self):
pass
def file_query(self):
pass
实例化对象的作用和练习
存储一些值,以后方便自己使用。
class File:
def read(self):
with open(self.x , mode='r',encoding='utf-8') as f:
data = f.read()
return data
def write(self , content):
with open(self.x , mode='a',encoding='utf-8') as f:
f.write(content)
# 实例化一个对象
obj1 = File()
obj1.x = "test.log"
# 通过对象调用类中的read方法(此时的self就是obj1)
obj1.write("1")
obj1.read()
# 实例化一个对象
obj2 = File()
obj2.x = "info.txt"
# 通过对象调用类中的read方法(此时的self就是obj1)
obj2.write("2")
obj2.read()
# 简单示例:
class Person:
def show(self):
print(f"我是{self.name} 年龄{self.age} 性别{self.sex}")
p1 = Person()
p1.name = "wany"
p1.age = 100
p1.sex = "男"
p1.show()
以下为一般写法(上述帮助理解)
class Person:
def __init__(self):
self.name = "wany"
self.age = 100
self.sex = "男"
def show(self):
print(f"我是{self.name} 年龄{self.age} 性别{self.sex}")、
p1 = Person() # 类() => 实例化对象,只要实例化直接自动执行此类中的__init__方法。
p1.show()
此时出现新的问题:
# 如果此时新实例化一个p2
p2 = Person()
p2.show()
# 此时得到的结果与p1一致
解决方案?使用 参数传递。
class Person:
def __init__(self , name , age ,sex): # 初始化方法
self.name = name
self.age = age
self.sex = sex
def show(self):
print(f"我是{self.name} 年龄{self.age} 性别{self.sex}")
p1 = Person("wany",20,"男")
p1.show()
p2 = Person("cxwxy",25,"女")
p2.show()
【练习】循环让用户输入:用户名/密码,输入 yes 后进行数据打印
# 面向过程的写法:
users_list = []
while True:
user = input("请输入用户名:")
pwd = input("请输入密码:")
temp = {'user':user,'pwd':pwd}
users_list.append(temp)
check = input("是否完成?yes or no?")
if check == "yes":
break
for e in users_list:
temp = f"用户名:{e['user']},密码:{e['pwd']}"
print(temp)
# 面向对象的写法:
class Person:
def __init__(self,user,pwd):
self.user = user
self.pwd =pwd
def resultprint(self):
print(f"用户名:{self.user},密码:{self.pwd}")
users_list = []
while True:
user = input("请输入用户名:")
pwd = input("请输入密码:")
temp = Person(user,pwd)
users_list.append(temp)
check = input("是否完成?yes or no?")
if check == "yes":
break
for e in users_list:
e.resultprint()
示例
class Police:
def __init__(self,name):
self.name = name
self.hp = 100
def attack(self,other):
msg = f"{self.name}攻击了{other.nickname}"
self.hp -= 10
other.hp -= 20
print(msg)
class Bandit:
def __init__(self,nickname):
self.nickname = nickname
self.hp = 100
zs = Police("张三")
ls = Bandit("李四")
zs.attack(ls)
2.继承
概述
# 父类 (基类)
class Father:
def func1(self):
print("父类功能1")
# 子类 (派生类)
class Son(Father): # 表示继承
def func2(self):
print("子类功能2")
class Son2(Father): # 表示继承
def func3(self):
print("子类2功能3")
# 创建一个子类对象
exp = Son()
# 执行对象方法时,优先在自己的类中找,如果没有再去父类中找
exp.func2()
exp.func1()
# 创建一个父类对象
exp2 = Father()
# exp2.func2() => 会报错
应用场景
多个类中如果有公共的方法,可以放到基类中避免重复编写。
重点
继承关系中的查找方法顺序:
#示例一
class Base:
def f1(self):
print("base.f1")
class Foo(Base):
def f2(self):
print("foo.f2")
obj = Foo()
obj.f1()
obj.f2()
# 结果:
# base.f1
# foo.f2
#示例二
class Base:
def f1(self):
print("base.f1")
class Foo(Base):
def f2(self):
self.f1()
print("foo.f2")
obj = Foo()
obj.f2()
# 结果:
# base.f1
# foo.f2
# 示例三
class Base:
def f1(self):
print("base.f1")
class Foo(Base):
def f2(self):
self.f1()
print("foo.f2")
def f1(self):
print("foo.f1")
obj = Foo()
obj.f2()
# 结果:
# foo.f1
# foo.f2
# 示例四
class Base:
def f1(self):
self.f2()
print("base.f1")
def f2(self):
print("base.f2")
class Foo(Base):
def f2(self):
print("foo.f2")
obj = Foo()
obj.f1()
# 结果:
# foo.f2
# base.f1
注意事项:
- self 到底是谁?
- self是哪个类创建的,就从此类开始找
- 自己没有则去父类寻找
- 如果继承了多个父类,从左往右找(不推荐使用多继承,只有python,C++语法上支持多继承)
3.多态
多态:多种形态/多种类型(鸭子模型)
# python天生自带多态
def func(arg):
temp = arg[1]
print(temp)
# arg可以传 字符串、元组、列表、字典等等具有索引功能的数据类型
# java
def func(str arg):
temp = arg[-1]
print(temp)
面试时,什么是鸭子模型?
对于一个函数而言,python对于参数的类型不会限制,那么传入的参数就可以是各种类型。如果函数中有例如arg.send方法,那么就是对传入类型的一个限制(类型必须有send方法)。这就是鸭子模型,类似于上述的函数。(通俗来讲,只要是呱呱叫的,就认为是鸭子)
4.作业题
import sys
class User:
def __init__(self,name,pwd):
self.name = name
self.pwd = pwd
class Account:
def __init__(self):
self.user_list = []
def register(self):
# 注册:没注册一个用户就创建一个user对象,然后添加到self.user_list中,表示注册成功。
# 最多存放三个
while len(self.user_list) < 3:
user = input("请输入用户名(输入N退出):")
if user.upper() == "N":
return
pwd = input("请输入密码:")
temp_obj = User(user,pwd)
self.user_list.append(temp_obj)
print("注册成功")
print("存放到达上限")
def login(self):
times = 0
while times < 2:
user = input("请输入用户名:")
pwd = input("请输入密码:")
flag = False
for item in self.user_list:
# 每个item是一个User对象
if item.name == user and item.pwd == pwd:
flag = True
break
if flag:
print("登陆成功")
sys.exit(0)
else:
print("用户名或者密码错误")
times = times + 1
print("试错以达上限")
sys.exit(1)
def run(self):
print("1.注册;2.登录;3.退出")
while True:
choice = input("输入选择:")
if choice == "1":
self.register()
elif choice == "2":
self.login()
elif choice == "3":
print("退出")
return
else:
print("输入有误")
return
if __name__ == '__main__':
# 开辟了一块内存给obj(实例化对象),内存中存储了 user_list = []
obj = Account()
obj.run()