第三模块 面向对象&网络&并发编程
从今天开始,我们将进入系列课程第3个模块的的学习,此模块包含如下三大部分知识:
-
面向对象,Python中支持两种编程方式来写代码,分别是:
函数式编程
、面向对象式编程
。-
函数式
# 定义函数,在函数中实现功能 def func(): print("一个NB的功能") # 执行函数 func()
-
面向对象
# 定义类 class Foo(object): # 在类中定义方法 def func(self): print("一个NB的功能") # 实例化类的对象 obj = Foo() # 执行类中的方法 obj.func()
Python支持两种编程方式(其他很多语言只支持一种),所以初学者在刚开始学习往往不知道应如何选择,并且行业内对于 函数式编程 vs 面向对象编程 之间谁更好的讨论也是难分胜负,其实在开发中无论要实现什么样的功能,两种编程模式都能实现,那种让我们能更好实现就选择谁?不必非纠结于那种方式更好,编程语言只是工具,最重要的是把功能实现。
初学者在选择编程方式时候,可以遵循如下规则:
-
函数式,推荐初学者使用。理由:上手快且逻辑简单清晰。
-
面向对象,推荐有一些代码经验后使用。理由:面向对象的思想需要有一定的项目积累之后(写多了&看的多)才能真正理解其精髓,基于面向对象可以编写出扩展性更强的代码(在一定程序上也可以简化代码)。
现阶段,大家在学习面向对象时更重要的是:掌握相关知识点 & 读懂源码 & 编写简单的基于面向对象的程序。
-
-
网络编程,学习网络知识后,可以让我们的程序通过网络来进行数据交互和传输 并 掌握其本质。
-
并发编程,一个程序想要执行的速度更快是必须要掌握并发编程的相关知识。
例如:下载10个抖音视频,每个需要2分钟。 - 按照以前的思路,逐一下载就需要20分钟。 - 按照并发的思路,创建10个线程/进程来实现,大概需要2分钟就可以完成。
day17 面向对象基础
课程目标:了解面向对象并可以根据面向对象知识进行编写代码。
课程概要:
- 初识面向对象
- 三大特性(面向对象)
- 封装
- 继承
- 多态
- 再看数据类型
1. 初识面向对象
想要通过面向对象去实现某个或某些功能时需要2步:
-
定义类,在类中定义方法,在方法中去实现具体的功能。
-
实例化类并的个一个对象,通过对象去调用并执行方法。
class Message:
def send_email(self, email, content):
data = "给{}发邮件,内容是:{}".format(email,content)
print(data)
msg_object = Message() # 实例化一个对象 msg_object,创建了一个一块区域。
msg_object.send_email("wupeiqi@live.com","注册成功")
注意:1.类名称首字母大写&驼峰式命名;2.py3之后默认类都继承object;3.在类中编写的函数称为方法;4.每个方法的第一个参数是self。
类中可以定义多个方法,例如:
class Message:
def send_email(self, email, content):
data = "给{}发邮件,内容是:{}".format(email, content)
print(data)
def send_wechat(self, vid, content):
data = "给{}发微信,内容是:{}".format(vid, content)
print(data)
msg_object = Message()
msg_object.send_email("wupeiqi@live.com", "注册成功")
msg_object.send_wechat("武沛齐", "注册成功")
你会发现,用面向对象编程写的类有点像归类的意思:将某些相似的函数划分到一个类中。
但,这种编写方式让人感觉有些鸡肋,直接用 函数 写多好呀。对吧?
别着急,记者往下看。
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参数传递进去。 往区域中(data="注册成功")
msg_object = Message("注册成功")
msg_object.send_email("wupeiqi@live.com") # 给wupeiqi@live.com发邮件,内容是:注册成功
msg_object.send_wechat("武沛齐") # 给武沛齐发微信,内容是:注册成功
通过上述的示例,你会发现:
- 对象,让我们可以在它的内部先封装一部分数据,以后想要使用时,再去里面获取。
- 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("注册成功")
msg_object.send_email("wupeiqi@live.com") # 给wupeiqi@live.com发邮件,内容是:注册成功
msg_object.send_wechat("武沛齐")
login_object = Message("登录成功")
login_object.send_email("wupeiqi@live.com") # 给wupeiqi@live.com发邮件,内容是:登录成功
login_object.send_wechat("武沛齐")
面向对象的思想:将一些数据封装到对象中,在执行方法时,再去对象中获取。
函数式的思想:函数内部需要的数据均通过参数的形式传递。
- self,本质上就是一个参数。这个参数是Python内部会提供,其实本质上就是调用当前方法的那个对象。
- 对象,基于类实例化出来”一块内存“,默认里面没有数据;经过类的
__init__
方法,可以在内存中初始化一些数据。
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)
def all_message(self):
msg = "我是{}人,我叫{},今年{}岁。".format(Person.country, self.name, self.age)
print(msg)
def total_message(self):
msg = "我是{}人,我叫{},今年{}岁。".format(self.country, self.name, self.age)
print(msg)
# 执行绑定方法
p1 = Person("武沛齐",20)
p1.show()
# 或
# p1 = Person("武沛齐",20)
# Person.show(p1)
# 初始化,实例化了Person类的对象叫p1
p1 = Person("武沛齐",20)
1.3 应用示例
-
将数据封装到一个对象,便于以后使用。
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对象中有:name/password user_object = UserInfo(user, pwd,19) # user_dict = {"name":user,"password":pwd} user_object_list.append(user_object) # user_object_list.append(user_dict) # 展示用户信息 for obj in user_object_list: print(obj.name, obj.password) 总结: - 数据封装到对象,以后再去获取。 - 规范数据(约束)
注意:用字典也可以实现做封装,只不过字典在操作值时还需要自己写key,面向对象只需要
.
即可获取对象中封装的数据。 -
将数据分装到对象中,在方法中对原始数据进行加工处理。
user_list = ["用户-{}".format(i) for i in range(1,3000)] # 分页显示,每页显示10条 while True: page = int(input("请输入页码:")) start_index = (page - 1) * 10 end_index = page * 10 page_data_list = user_list[start_index:end_index] for item in page_data_list: print(item)
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, 20) page_data_list = user_list[ pg_object.start() : pg_object.end() ] for item in page_data_list: print(item)
还有这个示例:将数据封装到一个对象中,然后再方法中对已封装的数据进行操作。
import os import requests class DouYin: def __init__(self, folder_path): self.folder_path = folder_path if not os.path.exists(folder_path): os.makedirs(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)
-
根据类创建多个对象,在方法中对对象中的数据进行修改。
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): """ 投炸弹,炸掉恐怖分子 """ for terrorist in terrorist_list: terrorist.blood -= 200 terrorist.show_status() """ p1 = Police("武沛齐","队员") p1.show_status() p1.bomb(["alex","李杰"]) p2 = Police("日天","队长") p2.show_status() p2.bomb(["alex","李杰"]) """ class Terrorist: """ 恐怖分子 """ def __init__(self, name, blood=300): self.name = name self.blood = blood def shoot(self, police_object): """ 开枪射击某个警察 """ 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) """ t1 = Terrorist('alex') t2 = Terrorist('李杰',200) """ def run(): # 1.创建3个警察 p1 = Police("武沛齐", "队员") p2 = Police("苑昊", "队员") p3 = Police("于超", "队长") # 2.创建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()
总结:
- 仅做数据封装。
- 封装数据 + 方法再对数据进行加工处理。
- 创建同一类的数据且同类数据可以具有相同的功能(方法)。
2. 三大特性
面向对象编程在很多语言中都存在,这种编程方式有三大特性:封装、继承、多态。
2.1 封装
封装主要体现在两个方面:
- 将同一类方法封装到了一个类中,例如上述示例中:匪徒的相关方法都写在Terrorist类中;警察的相关方法都写在Police类中。
- 将数据封装到了对象中,在实例化一个对象时,可以通过
__init__
初始化方法在对象中封装一些数据,便于以后使用。
2.2 继承
传统的理念中有:儿子可以继承父亲的财产。
在面向对象中也有这样的理念,即:子类可以继承父类中的方法和类变量(不是拷贝一份,父类的还是属于父类,子类可以继承而已)。
父类
子类
基类
派生类
class Base:
def func(self):
print("Base.func")
class Son(Base):
def show(self):
print("Son.show")
s1 = Son()
s1.show()
s1.func() # 优先在自己的类中找,自己没有才去父类。
s2 = Base()
s2.func()
class Base:
def f1(self):
pass
class Foo(Base):
def f2(self):
pass
class Bar(Base):
def f3(self):
pass
o1 = Foo()
o1.f2()
o1.f1()
练习题
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f1()
obj.f2()
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() # obj,Foo类创建出来的对象。 obj.f1
print('foo.f2')
def f1(self):
print('foo.f1')
obj = Foo()
obj.f1() # obj对象到底是谁?优先就会先去谁里面找。
obj.f2()
>>> 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() # 优先去Foo类中找f1,因为调用f1的那个对象是Foo类创建出来的。
>>> 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):
pass
class TCPServer(BaseServer):
pass
class ThreadingMixIn:
def process_request(self, request, client_address):
pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
obj = ThreadingTCPServer()
obj.serve_forever()
小结:
- 执行对象.方法时,优先去当前对象所关联的类中找,没有的话才去她的父类中查找。
- Python支持多继承:先继承左边、再继承右边的。
- self到底是谁?去self对应的那个类中去获取成员,没有就按照继承关系向上查找 。
2.3 多态
多态,按字面翻译其实就是多种形态。
- 其他编程语言多态
- 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)
}
public static void show(Cat a) {
a.eat()
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
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)
}
public static void show(Animal a) {
a.eat()
}
}
在java或其他语言中的多态是基于:接口 或 抽象类和抽象方法来实现,让数据可以以多种形态存在。
在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)
在程序设计中,鸭子类型(duck typing)是动态类型的一种风格。在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型,例如:一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子。
小结:
-
封装,将方法封装到类中 或 将数据封装到对象中,便于以后使用。
-
继承,将类中的公共的方法提取到基类中去实现。
-
多态,Python默认支持多态(这种方式称之为鸭子类型),最简单的基础下面的这段代码即可。
def func(arg): v1 = arg.copy() # 浅拷贝 print(v1) func("武沛齐") func([11,22,33,44])
3. 扩展:再看数据类型
在初步了解面向对象之后,再来看看我们之前学习的:str、list、dict等数据类型,他们其实都一个类,根据类可以创建不同类的对象。
# 实例化一个str类的对象v1
v1 = str("武沛齐")
# 通过对象执行str类中的upper方法。
data = v1.upper()
print(data)
总结
-
类和对象的关系。
-
面向对象编程中常见的成员:
- 绑定方法
- 实例变量
-
self到底是什么?
-
面向对象的三大特性。
-
面向对象的应用场景
- 数据封装。
- 封装数据 + 方法再对数据进行加工处理。
- 创建同一类的数据且同类数据可以具有相同的功能(方法)。
-
补充:在Python3中编写类时,默认都会继承object(即使不写也会自动继承)。
class Foo: pass class Foo(object): pass
这一点在Python2是不同的:
- 继承object,新式类
- 不继承object,经典类
作业
-
简述面向对象三大特性?
# 封装, 将数据存在类的一个内存区域中,用的时候到类里面取 # 继承, 公共/相同的属性可以放到同一个类中,子类可以继承父类中的属性。类默认都是继承object类的属性。 # 多态, python 类中的参数默认支持多种数据类型
-
将以下函数改成类的方式并调用 :
def func(a1): print(a1)
class info: def __init__(self, a1): self.a1 = a1 func = info('wahaha') print(func.a1)
-
面向对象中的self指的是什么?
一块内存空间,谁调用这个class 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.fo 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 user_info: def __init__(self, name, password, email): self.name = name self.password = password self.email = email # zhuqian, 123, zhuqian@123.com # wanwan, 456, wanwan@456.com # chunying, 789, chunying@789.com user_list = [] while True: user = input("请输入用户名:") if not user: print('输入错误,重新输入!') continue if user.upper() == 'Q': break pwd = input("请输入密码:") email = re.findall('^\w+@\w+.\w+$', input("请输入邮箱:"), re.ASCII) if not email: print('邮箱格式错误,请重新输入。') continue user = user_info(user, pwd, email) user_list.append(user) for item in user_list: print(item.name, item.email)
-
补充代码:实现 户注册和登录。
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()
py27
面向对象
初识面向对象
什么是类? 一系列具有相同属性和相似方法的事物的抽象
什么是对象? 一个带有具体属性值的类的实例
什么是实例化? 通过类创造对象的过程
面向对象语法
class Person: # Person是类
def __init__(self,name,hp,ad,sex,job):
self.username = name
self.hp = hp
self.ad = ad
self.sex = sex
self.job = job
alex = Person('alex',100,5,'不详','乞丐') # alex是对象 这是实例化的过程
class Person:
def __init__(self,name,hp,ad,sex,job):
self.username = name
self.hp = hp
self.ad = ad
self.sex = sex
self.job = job
class Dog:
def __init__(self,name,kind,hp,ad): # 初始化方法
self.name = name
self.kind = kind
self.hp = hp
self.ad = ad
def bite(self,person):
person.hp -= self.ad
print('%s咬了%s,%s掉了%s点血'%(self.name,person.username,person.username,self.ad))
# 谁在类的外部调用了这个方法,方法中的第一个self参数就是谁
alex = Person('alex',100,5,'不详','乞丐')
旺财 = Dog('旺财','teddy',2000,300)
二饼 = Dog('二饼','哈士奇',10000,500)
二饼.bite(alex) # Dog.bite(二饼,alex)
print(alex.hp)
# 人狗大战
# 人-角色
# 名称 等级 血量 攻击力 性别 职业
def Person(name, hp, ad, sex, job, level=1): # 角色的模板
person_dic = {'name': name, 'level': level, 'hp': hp, 'ad': ad, 'sex': sex, 'job': job}
def attack(dog):
dog['hp'] -= person_dic['ad']
print('%s攻击了%s,%s掉了%s点血' % (person_dic['name'], dog['name'], dog['name'], person_dic['ad']))
person_dic['attack'] = attack
return person_dic
alex = Person('alex', 100, 5, '不详', '乞丐') # 角色
wusir = Person('wusir', 200, 6, '女', '嫂子')
print(alex)
print(wusir)
# 狗-角色
def Dog(name, kind, hp, ad):
dog_dic = {'name': name, 'kind': kind, 'hp': hp, 'ad': ad}
def bite(person):
person['hp'] -= dog_dic['ad']
print('%s咬了%s,%s掉了%s点血' % (dog_dic['name'], person['name'], person['name'], dog_dic['ad']))
dog_dic['bite'] = bite
return dog_dic
dog1 = Dog('旺财', 'teddy', 2000, 150)
print(dog1)
dog2 = Dog('二饼', '哈士奇', 10000, 300)
print(dog2)
dog1['bite'](wusir)
alex['attack'](dog1)
# 程序中有多少个角色
# 每个角色有什么技能 有什么属性
# 所有的角色都是由一个模板创建的
# 我们甚至不关心程序的结果是什么
# 所有的属性 和 技能都 待在自己的角色模板中
# 能够一眼就看出程序的结构 -- 可读性好
# 能够更加方便的为角色添加技能或者属性 -- 可扩展性高
# 抽象
# 类 -- 角色模板 抽象的
# 通过类创建 对象 -- 角色 具体的
# 具体表现在所有的属性都具有了具体的值
# class 类
# def psersonType
class Person:
def __init__(self, name, hp, ad, sex, job):
self.username = name
self.hp = hp
self.ad = ad
self.sex = sex
self.job = job
alex = Person('alex', 100, 5, '不详', '乞丐') # 实例化
wusir = Person('wusir', 200, 6, '女', '嫂子')
print('-->', alex)
print(alex.username, wusir.username)
print(alex.ad)
print(alex.sex)
print(alex.job)
# class后面跟类名创造一个类
# 类名() -->对象
class Dog:
def __init__(self, name, kind, hp, ad): # 初始化方法
self.name = name
self.kind = kind
self.hp = hp
self.ad = ad
旺财 = Dog('旺财', 'teddy', 2000, 300)
class Person:
def __init__(self, name, hp, ad, sex, job):
self.username = name
self.hp = hp
self.ad = ad
self.sex = sex
self.job = job
def attack(self, dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.username, dog.name, dog.name, self.ad))
class Dog:
def __init__(self, name, kind, hp, ad): # 初始化方法
self.name = name
self.kind = kind
self.hp = hp
self.ad = ad
def bite(self, person):
person.hp -= self.ad
print('%s咬了%s,%s掉了%s点血' % (
self.name, person.username, person.username, self.ad)) # 谁在类的外部调用了这个方法,方法中的第一个self参数就是谁
alex = Person('alex', 100, 5, '不详', '乞丐') # 实例化,参数传对象,实例化就是创建对象
旺财 = Dog('旺财', 'teddy', 2000, 300)
二饼 = Dog('二饼', '哈士奇', 10000, 500)
二饼.bite(alex) # Dog.bite(二饼,alex)
print(alex.hp)
# 旺财.bite() # Dog.bite(旺财)
alex.attack(旺财)
print(旺财.hp)
# 类和对象的内存解析
类名一共有三个作用:
- 可以调用类中的变量 Fruits.discount
- 实例化创建一个对象 Fruits(‘苹果’,5)
- 调用一个方法(现在不常用):类名.方法名()
对象名
- 查看对象的属性 对象名.属性
- 调用对象的方法 对象名.方法名()
类和对象和实例和实例化
- 什么是类 ? Dog Person Fruits
- 什么是对象 ? alex 二饼 旺财 苹果 李子
- 什么是实例 ? 对象就是实例
- 实例化 是一个动词 类创造实例的过程叫做实例化: 对象 = 类名() 实例化
class Fruits:
discount = 0.8 # 折扣 # 类变量 静态变量
def __init__(self, name, price): # 实例方法 初始化方法
self.name = name # 实例变量 属性
self.pri = price
self.price = Fruits.discount * self.pri
def attack(self): pass # 自定义实例方法
def bite(self): pass # 自定义实例方法
apple = Fruits('苹果', 5)
banana = Fruits('香蕉', 7)
栗子 = Fruits('栗子', 4)
李子 = Fruits('李子', 10)
pear = Fruits('梨', 2)
print(apple.price)
print(李子.price)
print(apple.pri * Fruits.discount)
print(pear.pri * Fruits.discount)
# 类名一共有三个作用:
# 可以调用类中的变量 Fruits.discount
# 实例化创建一个对象 Fruits('苹果',5)
# 调用一个方法(现在不常用):类名.方法名()
# 对象名
# 查看对象的属性 对象名.属性
# 调用对象的方法 对象名.方法名()
# 类和对象和实例和实例化
# 什么是类 ? Dog Person Fruits
# 什么是对象 ? alex 二饼 旺财 苹果 李子
# 什么是实例 ? 对象就是实例
# 实例化 是一个动词 类创造实例的过程叫做实例化
# 对象 = 类名() 实例化
# 圆形类
# 属性 :半径
# 内部提供两个方法
# 计算周长 2πr
# 计算面积 πr**2
from math import pi
class Circle:
def __init__(self, r):
self.r = r
def area(self):
return self.r ** 2 * pi
def perimeter(self):
return 2 * self.r * pi
c1 = Circle(10)
c2 = Circle(20)
# print(c1.area())
# c1.r = 20
# print(c1.area())
# print(c2.area() - c1.area())
# 在哪里计算周长和面积?
# 返回值还是print?
类和对象的命名空间
class A:
静态变量 = '值'
def __init__(self, 属性):
self.属性名 = 属性
def show(self):
print('展示一下所有的属性')
a = A('参数') # 对象a\
print(a.静态变量) # 对象可以引用类的命名空间中的内容 包括方法和静态变量
# 类的命名空间中
# 静态变量
# 方法
# 对象的命名空间中
# 对象指针
# 实例变量 / 对象的属性
class Person:
sum = 0 # 全家人的工资总和为0
def __init__(self):
self.salary = 1000
# 一家人
father = Person()
mother = Person()
mother.age = 18
print(mother.age)
# print(mother.sum)
# print(mother.salary)
Person.sum += mother.salary # 用对象修改静态变量只要用到赋值,相当于在自己的空间中新建
print('-->', mother.sum)
print('person -->', Person.sum)
Person.sum += father.salary
print('-->', father.sum)
print('-->', mother.sum)
print('person -->', Person.sum)
# 例题:
# 写一个类, 统计一共实例化了多少个变量?
class Person:
count = 0
def __init__(self):
Person.count += 1
alex = Person()
print(alex.count, Person.count)
wusir = Person()
print(alex.count)
print(wusir.count)
print(Person.count) # 2
class A:
num = 0
def __init__(self):
self.num += 1
a1 = A()
a2 = A()
a3 = A()
print(A.num) # 0
print(a1.num, a2.num, a3.num) # 1
class A:
lst = []
def __init__(self):
self.lst.append(1)
a1 = A()
a2 = A()
a3 = A()
print(A.lst)
print(a1.lst)
print(a2.lst)
print(a3.lst)
class A:
lst = []
def __init__(self):
self.lst = [1]
a1 = A()
a2 = A()
a3 = A()
print(A.lst)
print(a1.lst)
print(a2.lst)
print(a3.lst)
class A:
lst = [0]
def __init__(self):
self.lst[0] += 1
a1 = A() # [1]
print(A.lst)
a2 = A() # [2]
print(A.lst)
a3 = A() # [3]
print(A.lst)
print(a1.lst)
print(a2.lst)
print(a3.lst)
# 操作静态变量的时候
# 如果是查看用类或者对象都可以
# 如果是修改
# 只用类名进行修改
# 不要在对象的空间中创建一个和类变量同名的实例变量
class Student:
'''
这是一个学生类,描述了学生的选课和查看分数的行为
'''
def __init__(self, id, name, sex, phone):
self.id = id
self.name = name
self.sex = sex
self.phone = phone
self.course_lst = []
def choose_course(self):
print('选择课程')
def show_score(self):
print('查看分数')
print(Student.__dict__) # __dict__ 内置的属性 可以查看类或者对象的命名空间中存储了什么
老王 = Student(1, '老王', 'male', '110119120999')
print(老王.__dict__)
到底什么是对象
在python中 一切皆对象
内置的类 不需要我们定义就可以直接使用的
class Student:
pass
s1 = Student()
# Student 是类型
# s1是对象
# s1是学生类的
# alex是人类的
# 二饼是狗类的
# 列表是什么? 类 L是什么?对象
l = [1,2,3]
d = {'a':'b'}
# 在python中 一切皆对象
int bool str list tuple dict set
# 内置的类 不需要我们定义就可以直接使用的
l = list([1,2,3]) # l = [1,2,3]
print(l)
组合
# 学生 : 姓名 性别 年龄 所学习的课程
class Student:
def __init__(self,name,sex,age,course):
self.name = name
self.sex = sex
self.age = age
self.course = course
class Course:
def __init__(self,cname,period,price):
self.name = cname
self.period = period
self.price = price
php = Course('php','5 months',18000)
python = Course('python','6 months',19800)
go = Course('go','5 months',8999)
tang = Student('汤青松','不详',80,python)
print(python.price)
print(tang.course.price)
wang = Student('老王','不详',80,'php')
tang.course = python
wang.course = python
print(tang.course.price)
print(wang.course.price)
python.price = 21800
print(tang.course.price)
print(wang.course.price)
###################################################################################
class Student:
def __init__(self,name,sex,age,course_price,course_period,course_name):
self.name = name
self.sex = sex
self.age = age
self.course_price = course_price
self.course_period = course_period
self.course_name = course_name
tang = Student('汤青松','不详',80,19800,'5 months','python')
wang = Student('老王','不详',80,19800,'5 months','python')
print(tang.course_name)
print(wang.course_name)
wang.course_price = 21800
tang.course_price = 21800
class A:
def __init__(self,name):
self.name = name
a = A('alex Li')
a是对象,是A的对象
a.name # 是对象a的属性
a.name是个字符串'alex Li'
'alex Li'是str的对象
'alex Li'.split(' ')
a.name.split(' ')
继承
class Animal:
def __init__(self, hp, ad, name):
self.hp = hp
self.ad = ad
self.name = name
def eat(self):
print('%s执行我啦' % self.name)
self.hp += 5
class Person(Animal):
def __init__(self, name, hp, ad, sex, job):
self.sex = sex # 人特有的
self.job = job # 人特有的
Animal.__init__(self, hp, ad, name)
def attack(self, dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.name, dog.name, dog.name, self.ad))
class Dog(Animal):
def __init__(self, name, kind, hp, ad): # 初始化方法
Animal.__init__(self, hp, ad, name)
self.kind = kind # kind是狗特有的
def bite(self, person):
person.hp -= self.ad
print('%s咬了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad))
二饼 = Dog('二饼', '哈士奇', 3000, 150)
print(二饼.__dict__)
alex = Person('alex', 100, 5, '不详', '乞丐')
print(alex.__dict__)
# A和B类都需要调用相同的方法
# 创建父类C,把相同的方法放到C类中
# A和B继承C A(C) B(C)
# A的对象和B的对象就可以直接调用C中的方法了
# A和B中有相同的方法,一部分功能相同,还有不同的部分
# 创建父类C, 把相同的部分放到C类的方法中
# 在A\B中保留不同的部分,
# 然后分别在A\B中调用C类的方法即可
class Course:
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price
class Student:
def __init__(self, name):
self.name = name
self.courses = []
def show_course(self):
for item in course_lst:
print(item)
class Manager:
def __init__(self, name):
self.name = name
def show_course(self):
for item in course_lst:
print(item.name, item.period, item.price)
course_lst = []
python = Course('python', '6months', 19800)
linux = Course('linux', '5months', 17800)
course_lst = [python, linux]
zhuqian = Student('zhuqian')
m = Manager('jinjin')
m.show_course()
super
class Course:
course_lst = []
def __init__(self,name,period,price):
self.name = name
self.period = period
self.price = price
class Role:
def __init__(self,name):
self.name = name
def show_course(self):
for item in Course.course_lst:
print(item.name,item.period,item.price)
class Student(Role):
def __init__(self,name):
# Role.__init__(self,name)
# super(Student, self).__init__(name)
super().__init__(name) # super也可以帮助我们找到父类
self.courses = []
class Manager(Role):pass
python = Course('python','6 months',19800)
linux = Course('linux','5 months',17800)
Course.course_lst = [python,linux] # 所有的可选课程
m = Student('alex')
print(m.name)
m.show_course()
- 在单继承中 super的作用就是找父类
- 在多继承中 super是找mro顺序的下一个类
总结
序列化
# json
# json类型 : '{"key":[1,2,3]}'
# 所有语言通用的\支持的数据类型有限
# 序列化的结果是字符串 : 可视化
# json不支持多次dump
# pickle
# python自己用\支持python中几乎所有的数据类型
# 结果是二进制 :看不懂的
# pickle天生支持多次dump和load
面向对象
# 类 class 类型
# 类变量
# 实例方法 __init__ attack bite
# 类指针 - 指向父类
# 对象
# 对象指针
# 实例变量 self.name slef.age
# 组合
# 一个对象作为一个属性
# self.course = python
# 继承
# class Foo:pass
# class Son(Foo):pass
# Son是子类\派生类 Foo是父类\超类\基类
# 继承的特点:
# 如果多个类都用到了相同的方法\属性
# 我们应该把这些共用的方法抽象到他们的父类中去
# 减少代码的冗余
# 先写子类的功能,发现重复才创建父类
# 子类自己没有某一个方法或者属性的时候用父类的
# 如果自己有 还像用父类的 在子类中直接调用父类的方法就可以了
object
- 有很多__xxx__方法
- init方法也在object类中
object类
在python3.x的所有类都是object的子类
所以对于一些内置的方法会写在object类中
如果子类不定义,在调用的时候最终会调用object类中的方法
就不会让程序出现不必要的错误了
__init__方法就是其中的一个例子
所有继承了object类的类 ---- 新式类
在python2中 不继承object类的都是 经典类
class A(object):
pass # 新式类
class A:
pass # 经典类 :在多继承中遵循深度优先
经典类中没有super和mro方法
把面向对象的基础知识掌握之后才来深入的了解复杂的继承关系
所有的py3中 的类都继承object 是新式类
在继承中 遵循 广度优先的 C3算法
也可以使用mro来查看继承顺序
super这个方法 可以帮助我们查找到mro顺序中的下一个类
三大特定 : 继承 封装 多态
封装
人狗大战
规范的创建对象
创建的所有人的属性名都能一致
把所有的方法装进一个角色中
广义上的封装 : 把方法和变量都封装在类中
在类的外部就不能直接调用了
狭义上的封装 : 在类的外部干脆不能调用了
class Student:
def __init__(self,name):
self.__name = name # 把name这个属性私有化了
def get_name(self):
return self.__name
def set_name(self,value):
if type(value) is str:
self.__name = value
老王 = Student('老王')
print(老王.get_name())
老王.set_name(1010101010100010)
print(老王.get_name())
print(老王.__name)
class Person:
def __init__(self,username,password):
self.username = username
self.__password = password
p = Person('alex','alex3714')
print(p.username)
class A:
__val = []
def __init__(self):
print(A.__val)
A()
print(A.__val)
class A:
def func(self):
self.__aaa()
def __aaa(self):
print('aaa')
a = A()
a.func()
# 在类的内部 ,实例变量(对象属性)可以变成私有的,类变量可以变成私有的,实例方法也可以变成私有的
# 一旦变成私有的就只能在类的内部使用,而不能在类的外部使用了
# 私有化到底是怎么做到的 :只是在类内部使用的时候对名字进行了包装 变成了_类名xxxx
class B:
__abc = 123 # _类名xxxx
print(__abc) # 使用 都会由这个类进行一个变形 _类名xxxx
print(B.__dict__)
print(B.__abc)
# 私有的变量不能被继承
class A:
def __func(self): # _A__func
print('in A')
class B(A):
def wahaha(self):
self.__func() # _B__func
b = B()
b.wahaha()
# 毕业练习题
class A:
def __init__(self):
self.__func() # self._A__func
def __func(self): # _A__func
print('in A')
class B(A):
def __func(self): # _B__func
print('in B')
b = B()
# 在哪个类中调用方法,就在这个私有方法之前加上这个类中的变形
# 和self本身是谁的对象都没有关系
多态
在python中处处是多态
def func(int a,int b,int c):
pass
# java是比较严谨的,所有在传递参数的时候必须指定参数的类型才可以
class User:pass
class Student(User):pass
class Manager(User):pass
def change_pwd(person):
pass
# 希望指定的类型 既能够保证 学生对象能传进来 管理员也能传进来
print(type('123'))
alex = Manager()
print(type(alex))
周老板 = Student()
print(type(周老板))
# User这个类可以表现出多种状态 :学生的状态 管理员的状态
三个装饰器方法
# class Student:
# def __init__(self,name,birth):
# self.name = name
# self.birth = birth
#
# @property # 将一个方法伪装成属性
# def age(self):
# import time
# return time.localtime().tm_year - self.birth
# alex = Student('alex',1930)
# print(alex.age) # 名词
class Circle:
def __init__(self,r):
self.r = r
@property
def area(self):
return 3.14*self.r**2
@property
def perimeter(self):
return 2*3.14*self.r
c = Circle(10)
print(c.area)
print(c.perimeter)
################################### classmethod and staticmethod #######################
class Student:
def __init__(self,name):
self.name = name
@staticmethod # 生命login方法是一个静态方法 ,不必传任何默认的参数
def login(flag):
print('登录程序',flag)
username = input('>>>')
stu = Student(username)
return stu
# 要想调用login 必须现有对象
# 要想创建对象 必须用户先输入名字
# 得调用登录之后才开始input
# 不必实例化就可以调用的login方法 不需要传递对象作为参数,就定义这个方法为静态方法
obj = Student.login(flag = True) # 用类名可以直接调用这个方法了
print(obj.__dict__)
class Manager:
def __init__(self,name):
self.name = name
@classmethod # 装饰当前这个方法为一个类方法,默认传参数cls,表示当前所在的类名
def login(cls):
username = input('>>>')
stu = cls(username)
return stu
obj = Manager.login() # 用类名可以直接调用这个方法了
print(obj.__dict__)
class A:
def func(self): pass # 实例方法 self作为默认参数,需要用对象来调用
@classmethod
def func1(cls): pass # 类方法 cls作为默认参数,可以用类名来调用
@staticmethod
def func1(): pass # 静态方法方法 没有默认参数,可以用用类名来调用
内置方法和单例模式
# 凡是数据类型 都会或多或少带有一些 双下方法
# __xxxx__ 魔术方法 内置方法
# 调用的时候总是不好好调用
# 'abc'.split('b') # 正经调用str类型的split方法
# ret = 'abc'.__add__('efg')
# print(ret)
# print('abc' + 'edf')
# __str__
class Course:
course_lst = []
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price
def __str__(self):
return '%s,%s,%s' % (self.name, self.period, self.price)
python = Course('python','6 months',19800)
linux = Course('linux','5 months',17800)
Course.course_lst = [python,linux]
for course in Course.course_lst:
print(course) # 打印一个对象总是打印内存地址,这个数据对我们来说没有用
# 打印这个对象的时候查看这个对象的相关信息
# print(obj) 打印一个对象 总是调用obj.__str__(),打印的是这个方法的返回值
__new__
class A(object):
def __new__(cls, *args, **kwargs): # 构造方法 开辟空间 构造对象的方法
obj = object.__new__(cls)
return obj
def __init__(self): # 初始化方法
print('init : ',self)
self.name = 'alex'
# 1.创建一块空间 : __new__
# 2.调用init
# A()
# 算法导论 - 微观
# 23个设计模式 - 宏观
# java语言
# 单例模式 - 只创建一个实例
# class A:
# pass
# a1 = A()
# a2 = A()
# print(a1)
# print(a2)
class Singleton:
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance
def __init__(self, name):
self.name = name
obj1 = Singleton('alex')
obj2 = Singleton('wusir')
print(obj1.name, obj2.name)
# 什么是单例模式?
#在多次实例化过程中只会产生一个实例。
# 怎么实现?
#使用 __new__ 方法实现, __new__ 方法是用来创建/开辟空间的,在 __init__ 之前执行。
# 用new实现
# new做什么用 在什么时候执行
反射
# 什么是反射
# 如果有一个变量名 是字符串数据类型的 你能获取到这个变量的值么?
class Student:
def __init__(self):
self.name = 'alex'
self.age = 80
self.gender = 'male'
def show_info(self):
print('%s,%s'%(self.name,self.age))
stu = Student()
content = input('>>>')
if hasattr(stu,content):
name = getattr(stu,content) # stu.show_info name=showinfo的地址
if callable(name):
name()
else:
print(name)
if content == 'name':
print(stu.name)
elif content == 'age':
print(stu.age)
elif content == 'gender':
print(stu.gender)
# 对象的反射
hasattr(对象,'属性名') 判断对象是否有这个属性,有返回True
getattr(对象,'属性名') 返回对象中属性名对应的值
# 反射属性
val = getattr(对象,'属性名')
val就是属性的值
# 反射方法
val = getattr('对象','方法名')
val就是方法的地址
val() ==> 调用方法
# 类的反射
class A:
role = 'China'
print(getattr(A,'role')) # 用类获取类的变量
# 模块的反射
import time
print(time.time())
print(getattr(time,'time')())
# 反射
a.b ===== getattr(a,'b')
name = 'alex'
age = 84
def func(*args):
print('wahaha')
class Student:pass
import sys
print(getattr(sys.modules[__name__],'name'))
print(getattr(sys.modules[__name__],'age'))
getattr(sys.modules[__name__],'func')(1,2,3)
print(getattr(sys.modules[__name__],'Student'))
反射的应用
class Studnet:
opt_lst = [('查看可选课程', 'show_courses'),
('选择课程', 'choose_course'), ('查看已选课程', 'show_selected_course')
, ('退出', 'quit')]
def __init__(self,name):
self.name = name
self.courses = []
def show_courses(self):
print('查看一共有多少门课程')
def choose_course(self):
print('选择课程')
def show_selected_course(self):
print('查看已经选择的课程')
def quit(self):
print('退出')
stu = Studnet('alex')
for index,opt in enumerate(Studnet.opt_lst,1):
print(index,opt[0])
num = int(input('请输入您要选择的操作序号:'))
if hasattr(stu,Studnet.opt_lst[num-1][1]):
getattr(stu,Studnet.opt_lst[num-1][1])()
# 选课系统
# 改进 反射
# classmethod/staticmethod装饰器
class Studnet:
opt_lst = [
('查看可选课程', 'show_courses'),
('选择课程', 'choose_course'),
('查看已选课程', 'show_selected_course'),
('退出', 'quit')]
def __init__(self, name):
self.name = name
self.courses = []
def show_courses(self):
print('查看一共有多少门课程')
def choose_course(self):
print('选择课程')
def show_selected_course(self):
print('查看已经选择的课程')
def quit(self):
print('退出')
stu = Studnet('alex')
for index, opt in enumerate(Studnet.opt_lst, 1):
print('{}.{}'.format(index, opt[0]))
while True:
num = input('请输入选择项目的序号:').strip()
if not num:
continue
if num.upper() == 'Q':
break
if num.isdecimal():
num = int(num)
if hasattr(stu, Studnet.opt_lst[num -1][1]):
getattr(stu, Studnet.opt_lst[num -1][1])()
常用模块:https://www.cnblogs.com/Eva-J/articles/7228075.html
日志:https://www.cnblogs.com/Eva-J/articles/11266790.html#_label14