第三模块包含的知识内容:
-
面向对象,Python中支持两种编程方式来编写代码,分别是:
函数式编程
、面向对象式编程
。-
函数式
# 定义函数,在函数中实现功能 def func(): print("一个NB的功能") # 执行函数 func()
-
面向对象
# 定义类 class Foo(object): # 在类中定义方法 def func(self): print("一个NB的功能") # 实例化类的对象 obj = Foo() # 执行类中的方法 obj.func()
行业内对于函数式编程 vs 面向对象编程之间谁更好的讨论也是难分胜负,其实在开发中无论要实现什么样的功能,两种编程模式都能实现,那种让我们能更好实现就选择谁?不必非纠结于那种方式更好,编程语言支持工具,最重要的是把功能实现。
-
函数式编程:推荐初学者使用。
理由:上手快且逻辑简单清晰。
-
面向对象编程:推荐有一些代码经验后使用。
理由:面向对象的思想需要有一定的项目积累之后(写多了&看的多)才能真正理解其精髓,基于面向对象可以编写出扩展性更强的代码(在一定程序上也可以简化代码)。
现阶段,大家在学习面向对象时更重要的是:掌握相关知识点 & 读懂源码 & 编写简单的基于面向对象的程序。
-
-
网络编程,学习网络知识后,可以让我们的程序通过网络来进行数据交互和传输并掌握其本质。
-
并发编程,一个程序想要执行的速度更快是必须要掌握并发编程的相关知识。
例如:下载10个视频,每个需要2分钟。
- 按照以前的思路,逐一下载就需要20分钟。
- 按照并发的思路,创建10个线程/进程来实现,大概需要2分钟就可以完成。
课程目标:了解面向对象并可以根据面向对象知识进行编写代码。
课程概要:
- 初识面向对象
- 三大特性(面向对象)
- 封装
- 继承
- 多态
- 再看数据类型
想要通过面向对象去实现某个或某些功能时需要2步:
-
定义类,在类中定义方法,在方法中去实现具体的功能。
-
实例化类并得到一个对象,通过对象去调用并执行方法。
class Message:
def send_email(self, email, content):
data = "给{}发邮件,内容是:{}".format(email,content)
print(data)
# 实例化一个msg_object对象,相当于在python内部创建了一个区域:
msg_object = Message()
msg_object.send_email("xuanxiaomo@live.com","注册成功")
注意:
1.类名称首字母大写&驼峰式命名
2.py3之后默认类都继承object
3.在类中编写的函数称为方法
4.每个方法的第一个参数是self
1.1 对象和self在每个类中都可以定义一个特殊的方法:__init__ 初始化
,会在实例化类创建对象(即对象=类()
)时自动执行,。
class Message:
def __init__(self, content):
self.data = content
def send_email(self, email):
data = "给{}发邮件,内容是:{}".format(email, self.data)
print(data)
def send_wechat(self, vid):
data = "给{}发微信,内容是:{}".format(vid, self.data)
print(data)
# 对象 = 类名() # 自动执行类中的 __init__ 方法。
# 1. 根据类创建一个对象,相当于在内存的创建一块区域 。
# 2. 执行__init__方法,会将创建的对象的那块区域的内存地址当成self参数传递进去。
msg_object = Message("注册成功")
# 给xuanxiaomo@live.com发邮件,内容是:注册成功
msg_object.send_email("xuanxiaomo@live.com")
# 给轩小陌发微信,内容是:注册成功
msg_object.send_wechat("轩小陌")
通过上述的示例,你会发现:
-
对象,可以让我们在它的内部先封装一部分数据,以后需要使用时,再从里面去获取。
对象是基于类实例化出来
一块内存
,默认里面没有数据,经过类的__init__
方法,可以在内存中初始化一些数据。 -
self,类中的方法需要由这个类的对象来触发并执行( 对象.方法名 ),且在执行时会自动将对象当做参数传递给 self ,以供方法中获取对象中已封装的数据。
self 本质上就是一个参数,代指调用当前方法的那个对象。
-
除了默认参数 self 外,方法中的参数的定义和执行与函数相同。
当然,根据类也可以创建多个对象并执行其中的方法,例如:
class Message:
def __init__(self, content):
self.data = content
def send_email(self, email):
data = "给{}发邮件,内容是:{}".format(email, self.data)
print(data)
def send_wechat(self, vid):
data = "给{}发微信,内容是:{}".format(vid, self.data)
print(data)
msg_object = Message("注册成功")
# 给xuanxiaomo@live.com发邮件,内容是:注册成功
msg_object.send_email("xuanxiaomo@live.com")
login_object = Message("登录成功")
# 给轩小陌@live.com发邮件,内容是:登录成功
login_object.send_email("xuanxiaomo@live.com")
1.2 常见成员
在编写面向对象相关代码时,最常见成员有:
- 实例变量,不属于类,属于对象,只能通过对象调用。
- 绑定方法,属于类,通过对象调用或通过类调用。
注意:还有很多其他的成员,后续再来介绍。
class Person:
def __init__(self, n1, n2):
# 实例变量
self.name = n1
self.age = n2
# 绑定方法
def show(self):
msg = "我叫{},今年{}岁。
"
.format(self.name, self.age)
print(msg)
# 执行绑定方法
p1 = Person("轩小陌",20)
p1.show()
p1 = Person("轩小陌",20)
Person.show(p1)
1.3 应用示例
1.3.1 将数据封装到一个对象,便于以后使用。
class UserInfo:
def __init__(self, name, pwd, age):
self.name = name
self.password = pwd
self.age = age
def run():
user_object_list = []
# 用户注册
while True:
user = input("用户名:")
if user.upper() == "Q":
break
pwd = input("密码")
user_object = UserInfo(user, pwd, 19)
user_object_list.append(user_object)
# 展示用户信息
for obj in user_object_list:
print(obj.name, obj.password)
注意:用字典也可以实现做封装,只不过字典在 *** 作值时还需要自己写key,面向对象只需要 .
即可获取对象中封装的数据。
示例1:
class Pagination:
def __init__(self, current_page, per_page_num=10):
self.per_page_num = per_page_num
if not current_page.isdecimal():
self.current_page = 1
return
current_page = int(current_page)
if current_page < 1:
self.current_page = 1
return
self.current_page = current_page
def start(self):
return (self.current_page - 1) * self.per_page_num
def end(self):
return self.current_page * self.per_page_num
user_list = ["用户-{}".format(i) for i in range(1, 3000)]
# 分页显示,每页显示10条
while True:
page = input("请输入页码:")
# page,当前访问的页码
# 10,每页显示10条数据
# 内部执行Pagination类的init方法。
pg_object = Pagination(page, 10)
page_data_list = user_list[ pg_object.start() : pg_object.end() ]
for item in page_data_list:
print(item)
示例2:
import os
import requests
class DouYin:
def __init__(self, folder_path):
if not os.path.exists(folder_path):
os.makedirs(folder_path)
self.folder_path = folder_path
# 定义下载视频的函数:
def download(self, file_name, url):
res = requests.get(
url=url,
headers={
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS"
}
)
file_path = os.path.join(self.folder_path, file_name)
with open(file_path, mode='wb') as f:
f.write(res.content)
f.flush()
# 定义一个批量下载视频的函数:
def multi_download(self, video_list):
for item in video_list:
self.download(item[0], item[1])
if __name__ == '__main__':
douyin_object = DouYin("videos")
douyin_object.download(
"罗斯.mp4",
"https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg"
)
video_list = [
("a1.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300fc20000bvi413nedtlt5abaa8tg"),
("a2.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0d00fb60000bvi0ba63vni5gqts0uag"),
("a3.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg")
]
douyin_object.multi_download(video_list)
1.3.3 根据类创建多个对象,在方法中对对象中的数据进行修改。
# 定义警察类:
class Police:
"""警察"""
def __init__(self, name, role):
self.name = name
self.role = role
if role == "队员":
self.hit_points = 200
else:
self.hit_points = 500
def show_status(self):
""" 查看警察状态 """
message = "警察{}的生命值为:{}".format(self.name, self.hit_points)
print(message)
def bomb(self, terrorist_list):
""" 投炸d,炸掉恐怖分子 """
for terrorist in terrorist_list:
terrorist.blood -= 200
terrorist.show_status()
# 定义恐怖分子类:
class Terrorist:
""" 恐怖分子 """
def __init__(self, name, blood=300):
self.name = name
self.blood = blood
def shoot(self, police_object):
""" 开q射击某个警察 """
police_object.hit_points -= 5
police_object.show_status()
self.blood -= 2
def strafe(self, police_object_list):
""" 扫射某些警察 """
for police_object in police_object_list:
police_object.hit_points -= 8
police_object.show_status()
def show_status(self):
""" 查看恐怖分子状态 """
message = "恐怖分子{}的血量值为:{}".format(self.name, self.blood)
print(message)
# 定义执行函数:
def run():
# 创建3个警察
p1 = Police("轩小陌", "队员")
p2 = Police("苑昊", "队员")
p3 = Police("于超", "队长")
# 创建2个匪徒
t1 = Terrorist("alex")
t2 = Terrorist("eric")
# alex匪徒射击于超警察
t1.shoot(p3)
# alex扫射
t1.strafe([p1, p2, p3])
# eric射击苑昊
t2.shoot(p2)
# 轩小陌炸了那群匪徒王八蛋
p1.bomb([t1, t2])
# 轩小陌又炸了一次alex
p1.bomb([t1])
if __name__ == '__main__':
run()
面向对象用途小结:
- 仅做数据封装。
- 封装数据,同时在方法中对数据进行加工处理。
- 创建同一类的多个对象,每个对象可以具有相同的功能(方法)。
面向对象编程在很多语言中都存在,这种编程方式有三大特性:封装、继承、多态。
封装主要体现在两个方面:
- 将同一类方法封装到了一个类中,例如上述示例中:恐怖分子的相关方法都写在Terrorist类中;警察的相关方法都写在Police类中。
- 将数据封装到了对象中,在实例化一个对象时,可以通过
__init__
初始化方法在对象中封装一些数据,便于以后使用。
在面向对象中也有这样的特性,即:子类可以继承父类中的方法和类变量,或者说派生类可以继承基类中的方法和类变量(不是拷贝一份,父类的还是属于父类,子类可以继承而已)。
class Base:
def func(self):
print("Base.func")
class Son(Base):
def show(self):
print("Son.show")
s1 = Son()
s1.show()
s1.func() # 优先在自己的类中找,否则从父类中找。
练习题
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
print('before')
self.f1() # 调用了f1方法 obj.f1()
print('foo.f2')
obj = Foo()
obj.f2()
>>输出结果:
before
base.f1
foo.f2
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
print("before")
self.f1()
print('foo.f2')
def f1(self):
print('foo.f1')
obj = Foo()
obj.f1()
obj.f2()
>>输出结果:
foo.f1
before
foo.f1
foo.f2
class Base:
def f1(self):
print('before')
self.f2() # slef是obj对象(Foo类创建的对象) obj.f2
print('base.f1')
def f2(self):
print('base.f2')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f1()
>>输出结果:
before
foo.f2
base.f1
b1 = Base()
b1.f1()
>>输出结果:
before
base.f2
base.f1
class TCPServer:
def f1(self):
print("TCPServer")
class ThreadingMixIn:
def f1(self):
print("ThreadingMixIn")
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
def run(self):
print('before')
self.f1()
print('after')
obj = ThreadingTCPServer()
obj.run()
>>输出结果:
before
ThreadingMixIn
after
class BaseServer:
def serve_forever(self, poll_interval=0.5):
self._handle_request_noblock()
def _handle_request_noblock(self):
self.process_request(request, client_address)
def process_request(self, request, client_address):
print('456')
class TCPServer(BaseServer):
pass
class ThreadingMixIn:
def process_request(self, request, client_address):
print('123')
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
obj = ThreadingTCPServer()
obj.serve_forever()
>>输出结果:
123
小结:
- 执行对象.方法时,优先去当前对象所关联的类中找,没有则去父类中找。
- Python支持多继承:优先继承左边、再继承右边。
- 优先去 self 对应的那个类中去获取成员,没有就按照继承关系向上查找。
多态,按字面翻译其实就是多种形态。
- 其他编程语言中的多态
- Python中的多态
在java或其他语言中的多态是基于接口
或抽象类和抽象方法
来实现,让数据可以以多种形态存在。
class Cat{
public void eat() {
System.out.println("吃鱼");
}
}
class Dog {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
public class Test {
public static void main(String[] args) {
obj1 = Cat()
obj2 = Cat()
show(obj1)
show(obj2)
obj3 = Dog()
show(obj3) # 报错
}
# show中只能传入Cat对象的参数
public static void show(Cat a) {
a.eat()
}
}
# 创建一个抽象类和抽象方法
abstract class Animal {
abstract void eat();
}
# 创建Cat类时继承抽象类
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
# 创建Dog类时继承抽象类
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
public class Test {
public static void main(String[] args) {
obj1 = Cat()
show(obj1)
obj2 = Dog()
show(obj2)
}
# show中支持抽象类对象的参数,因为Cat和Dog都继承了抽象类,所以都能作为参数传入
public static void show(Animal a) {
a.eat()
}
}
2.3.2 Python中的多态
在Python中则不一样,由于Python对数据类型没有任何限制,所以天生支持多态。
def func(arg):
v1 = arg.copy()
print(v1)
func("轩小陌")
func([11,22,33,44])
class Email(object):
def send(self):
print("发邮件")
class Message(object):
def send(self):
print("发短信")
def func(arg):
v1 = arg.send()
print(v1)
v1 = Email()
func(v1)
v2 = Message()
func(v2)
在 python 多态下的数据的类型的也通常成为鸭子类型(duck typing),是动态类型的一种风格。
在鸭子类型中,关注点在于对象的行为,是否符合函数内部对于该数据类型的调用规则;而不是关注对象所属的类型。
例如:一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子。
-
封装,将方法封装到类中或将数据封装到对象中,便于以后使用。
-
继承,将类中的公共的方法提取到基类中去实现。
-
多态,Python默认支持多态(这种方式下的数据类型也称为鸭子类型)。
在初步了解面向对象之后,再来看看我们之前学习的:str、list、dict等数据类型,他们其实都一个类,根据类可以创建不同类的对象。
# 实例化一个str类的对象v1:
v1 = str("轩小陌")
# 通过对象执行str类中的各种方法:
data1 = v1.upper()
data2 = v1.strip()
data3 = v1.split(',')
...
今日总结
-
类和对象的关系。
-
面向对象编程中常见的成员:
- 绑定方法
- 实例变量
-
self 到底是什么?
-
面向对象的三大特性。
-
面向对象的应用场景
- 数据封装。
- 封装数据 + 在方法中再对数据进行加工处理。
- 创建同一类的对象且同类对象可以具有相同的功能(方法)。
- 数据封装。
-
补充:在Python3中编写类时,默认都会继承object(即使不写也会自动继承)。
这一点在Python2是不同的:
- 继承object,新式类
- 不继承object,经典类
-
简述面向对象三大特性?
1、封装:将数据封装到类对象中,方便后续需要的时候再使用。
2、继承:子类可以继承父类的方法,python还支持多继承,多继承时优先继承左边,再继承右边。
3、多态:python中的数据默认支持多态,不对数据的类型做限制,只要该类型符合的函数内部相关的调用规则即可。
-
将以下函数改成类的方式并调用 :
def func(a1): print(a1) # 补充代码: class Func: def func(self,a1): print(a1) obj = Func() obj.func(a1)
-
面向对象中的 self 指的是什么?
self是一个参数,在通过对象.方法的方式去执行方法的时候,self会将对象作为值传入。
-
以下代码体现面向对象的什么特性?
class Person(object): def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender obj = Person('轩小陌', 18, '男') >>体系了面向对象的封装数据的特性
-
以下代码体现面向对象的什么特性?
class Message(object): def email(self): """ 发送邮件 :return: """ pass def msg(self): """ 发送短信 :return: """ pass def wechat(self): """ 发送微信 :return: """ pass >>体系了面向对象的封装方法的特性
-
看代码写结果
class Foo: def func(self): print('foo.func') obj = Foo() result = obj.func() print(result) >>输出结果: foo.func None
-
看代码写结果
class Base1: def f1(self): print('base1.f1') def f2(self): print('base1.f2') def f3(self): print('base1.f3') self.f1() class Base2: def f1(self): print('base2.f1') class Foo(Base1, Base2): def f0(self): print('foo.f0') self.f3() obj = Foo() obj.f0() >>输出结果: foo.f0 base1.f3 base1.f1
-
看代码写结果:
class Base: def f1(self): print('base.f1') def f3(self): self.f1() print('base.f3') class Foo(Base): def f1(self): print('foo.f1') def f2(self): print('foo.f2') self.f3() obj = Foo() obj.f2() >>输出结果: foo.f2 foo.f1 base.f3
-
补充代码实现
user_list = [] while True: user = input("请输入用户名:") pwd = input("请输入密码:") email = input("请输入邮箱:") """ # 需求 1. while循环提示用户输入:用户名、密码、邮箱(正则满足邮箱格式) 2. 为每个用户创建一个对象,并添加到user_list中。
3. 当列表中添加了3个对象后,跳出循环并以此循环打印所有用户的姓名和邮箱 """
# 补充代码: import re class Message: def __init__(self,user,pwd,email): self.user = user self.pwd = pwd self.email = email def run(): user_list = [] while True: user = input("请输入用户名:") pwd = input("请输入密码:") email = input("请输入邮箱:") email_list = re.findall('\w+@\w+\.\w+', email, re.ASCII) if not email_list: print('邮箱格式有误,请重新输入') continue email = email_list[0] obj = Message(user, pwd, email) user_list.append(obj) if len(user_list) == 3: break for user in user_list: print(user.user, user.email) if __name__ == '__main__': run() -
补充代码实现用户注册和登录。
class User: def __init__(self, name, pwd): self.name = name self.pwd = pwd class Account: def __init__(self): # 用户列表,数据格式:[user对象,user对象,user对象] self.user_list = [] def login(self): """ 用户登录,输入用户名和密码然后去self.user_list中校验用户合法性 :return: """ pass def register(self): """ 用户注册,每注册一个用户就创建一个user对象,然后添加到self.user_list中,表示注册成功。
:return: """
pass def run(self): """ 主程序 :return: """ pass if __name__ == '__main__': obj = Account() obj.run()class User: def __init__(self, name, pwd): self.name = name self.pwd = pwd class Account: def __init__(self): # 用户列表,数据格式:[user对象,user对象,user对象] self.user_list = [] def login(self): while True: name = input('请输入用户名(Q/q退出):') if name.upper() == 'Q': return pwd = input('请输入密码:') for user_obj in self.user_list: if name == user_obj.name and pwd == user_obj.pwd: print('登录成功') return print('用户名或密码错误,请重新输入') continue def register(self): while True: name = input('请输入用户名(Q/q退出):') if name.upper() == 'Q': return pwd = input('请输入密码:') user_obj = User(name, pwd) self.user_list.append(user_obj) print('注册成功') return def run(self): while True: message = input('请选择登录/注册:') if message.upper() == 'Q': break if message == '登录': self.login() elif message == '注册': self.register() else: print('输入有误,请重新输入') continue if __name__ == '__main__': obj = Account() obj.run()
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)