前言
前几天更新面向对象,学了很长时间,也是断断续续更新了很多内容,总算是有所收获了,今天终于是把面向对象的只是学完了,还有一点是网络编程,到时候学了分享出来。这个是把所有的面向对象相关的都总结在一起了,方便查看。
2.1 初识面向对象
def send_email(to_email):
msg = "给{}发送了一封邮件。".format(to_email)
print(msg)
send_email("45646@qq.com")
如果要基于面向对象实现上述过程:
-
定义类和方法
# 类名:首字母大写 大驼峰写法 class MessageInfo: # 在类找中定义方法 def send_email(self, to_email): msg = "给{}发送了一封邮件。".format(to_email) print(msg)
-
调用类中的方法
-
根据类名实例化一个对象 类名()
obj = MessageInfo()
-
调用方法时 -- 使用对象.方法名() 注意,其中第一个
self
参数不需要自己传递值 --self
是调用它的这个对象obj.send_email("123156456@qq.com")
- 意思是:self实在python内部传递的,默认会将调用此方法的对象传递进去,比如说,
obj.send_email("123156456@qq.com")
,那self
这个参数所传递过去的值为obj
这个对象。
- 意思是:self实在python内部传递的,默认会将调用此方法的对象传递进去,比如说,
-
代码再复杂一点
class Message: def send_email(self, to_email): msg = "给{}发送了一封邮件。".format(to_email) print(msg) def send_dingding(self, to_email): msg = "给{}发送了一封钉钉消息。".format(to_email) print(msg) def send_wechat(self, to_email): msg = "给{}发送了一封微信消息。".format(to_email) print(msg) # 实例化Message类的对象 # 1. 与其他的类关联 # 2. 一块内存,可以存放数据 obj = Message() obj.send_email("xxxx") obj.send_dingding("xx") obj.send_wechat("qqq")
-
2.2 什么是对象
示例一:
class Message:
def send_email(self, to_email):
msg = "给{}发送了一封邮件。".format(to_email)
print(msg)
def send_dingding(self, to_email):
msg = "给{}发送了一封钉钉消息。".format(to_email)
print(msg)
def send_wechat(self, to_email):
msg = "给{}发送了一封微信消息。".format(to_email)
print(msg)
# 实例化Message类的对象
# 1. 与其他的类关联
# 2. 一块内存,可以存放数据
obj = Message()
obj.send_email("xxxx")
obj.send_dingding("xx")
obj.send_wechat("qqq")
示例二:
class Message:
def send_email(self, to_email):
msg = "给{}发送了一封邮件。".format(to_email)
print(msg)
def send_dingding(self, to_email):
msg = "给{}发送了一封钉钉消息。".format(to)
print(msg)
def send_wechat(self, to_email):
msg = "给{}发送了一封微信消息。".format(to)
print(msg)
obj = Message()
obj.company = "这是个公司名"
obj.number = 100000
示例三:
class Message:
def send_email(self, to):
msg = "给{}的{}发送了一封邮件。".format(self.company, to)
print(msg)
def send_dingding(self, to_email):
msg = "给{}发送了一封钉钉消息。".format(to)
print(msg)
def send_wechat(self, to_email):
msg = "给{}发送了一封微信消息。".format(to)
print(msg)
obj = Message()
obj.company = "这是个公司名"
obj.number = 100000
obj.send_email("123@qq.com")
示例四:
class Message:
def send_email(self, to):
msg = "给{}的{}发送了一封邮件。".format(self.company, to)
print(msg)
def send_dingding(self, to_email):
msg = "给{}的{}发送了一封钉钉消息。".format(self.company, to)
print(msg)
def send_wechat(self, to_email):
msg = "给{}的{}发送了一封微信消息。".format(self.company, to)
print(msg)
# 根据类实例化对象
obj = Message()
obj.company = "这是个公司名"
obj.number = 100000
obj.send_email("123@qq.com")
# 只要根据类实例化对象,就创建一块内存
# 根据类实例化对象
new = Message()
obj.company = "这是个公司名1"
obj.number = 1000000
new.send_email("456@qq.com")
示例五:
class Message:
# 非常特殊的方法 不用自己调用 在内部实例化对象的时候调用
def __init__(self, city):
self.company = "这是一个公司名2"
# 等价于: obj1.company = "这是一个公司名2"
self.city = city
def send_email(self, to):
msg = "给 {} 的 {} 发送了一封邮件。".format(self.city, to)
print(msg)
def send_dingding(self, to_email):
msg = "给 {} 的 {} 发送了一封钉钉消息。".format(self.company, to)
print(msg)
def send_wechat(self, to_email):
msg = "给 {} 的 {} 发送了一封微信消息。".format(self.company, to)
print(msg)
# 1. 创建空对象 并且 空对象和类关联起来
# 2. 自动执行 __init__(self)方法 -- obj1.__init__()
obj1 = Message("哈哈")
obj2 = Message("嘻嘻")
obj1.send_email("A") # 给 哈哈 的 A 发送了一封邮件
obj1.send_email("B") # 给 哈哈 的 B 发送了一封邮件
obj1.send_email("C") # 给 这是一个公司名2 的 C 发送了一封邮件
obj1.send_email("D") # 给 这是一个公司名2 的 D 发送了一封邮件
小结:
-
在面向对象中,
self
是什么?- 我的答案:
self
是一个特殊的参数,当一个实例化的对象被初始化后,self
就被赋值成为这个被初始化的对象。 - 老师的答案:
self
本质上是一个参数,这个参数的值是由python内部传递【特殊】- 对象.方法(
self
),self
等于什么? -- 当前方法是由哪个对象调用的,self
就等于哪个对象
- 我的答案:
-
在面向对象中,
__init__()
方法__init__(self) 一般称为初始化方法,当 `类名()` 即: 根据类名实例化对象时,自动调用
-
一般情况下,把函数放在类中 +
self
作为参数 -- 就将其称为方法# 函数 def func(): ... class 类名(注意首字母大写): # 方法 def func(): ...
-
对象的作用是
将很多的数据封装到一个对象中,再通过这个对象可以再进行调用里面的数据.
案例:用户注册
"""
{
{"username": "computer", "password":"132456"},
{"username": "computer", "password":"132456"},
{"username": "computer", "password":"132456"}
}
"""
user_list = []
while True:
user = input("用户名")
if user.upper() == "Q":
break
password = input("用户密码")
info = {"username": user, "password": password}
user_list.append(info)
for item in user_list:
msg = "{} < == > {}".format(item["username"], item["password"])
print(msg)
调整--使用面向对象
class UserInfo:
def __init__(self, a1, a2):
self.username = a1
self.password = a2
# [对象(), 对象(), 对象()]
user_list = []
while True:
user = input("用户名")
if user.upper() == "Q":
break
password = input("用户密码")
obj = UserInfo(user, password)
user_list.append(obj)
for item in user_list:
print(item.username)
print(item.password)
msg = "{} < == > {}".format(item.username, item.password)
print(msg)
回忆一下: 在对象(包裹)中封装一些值.
回忆:
class Foo:
def f1(self):
pass
def f2(self):
pass
def f3(self, a1, a2):
return a1 + a2
obj = Foo()
obj.f1()
obj.f2()
res = obj.f3(1, 2)
print(res)
v1 = list()
v1.append(123)
# 按住键盘上的Ctrl键,点击v1 = list()的哪个list,pycharm中会弹出一些源码
[!Caution]
我们以前学习的数据类型,本质上还是 对象 + 类
案例:警匪游戏
class Police:
"""警察类."""
def __init__(self, name, age, hit_point):
self.name = name
self.age = age
self.hit_point = hit_points
def catch(self):
"""抓小偷"""
self.hit_point += 100
def smoking(self):
"""抽烟"""
self.hit_point -= 50
def shoot(self, user):
"""开枪"""
user.hit_points -= 100
self.hit_point -= 10
# (name="computer", age=19, hit_points=1100)
p1 = Police("computer", 19, 1100)
print(p1.hit_point) # 1100
p1.catch()
print(p1.hit_point) # 1200
p2 = Police("science", 23, 1200)
print(p2.hit_point) # 1200
p2.smoking()
print(p2.hit_point) # 1150
p3 = Police("technology", 24, 1300)
print(p3.hit_point) # 1300
p3.catch()
p3.smoking()
print(p3.hit_point) # 1350
class Police:
"""警察类."""
def __init__(self, name, age, hit_point):
self.name = name
self.age = age
self.hit_point = hit_points
def catch(self):
"""抓小偷"""
self.hit_point += 100
def smoking(self):
"""抽烟"""
self.hit_point -= 50
def shoot(self, user):
"""开枪"""
user.hit_points -= 100
self.hit_point -= 10
# (name="computer", age=19, hit_points=1100)
p1 = Police("computer", 19, 1100)
p2 = Police("science", 23, 1200)
p3 = Police("technology", 24, 1300)
p1.shoot(p3)
print(p1.hit_point) # 1090
print(p3.hit_point) # 1200
p3.shoot(p1)
print(p1.hit_point) # 990
print(p3.hit_point) # 1190
class Police:
"""警察类."""
def __init__(self, name, age, hit_points):
self.name = name
self.age = age
self.hit_points = hit_points
def catch(self):
"""抓小偷"""
self.hit_points += 100
def smoking(self):
"""抽烟"""
self.hit_points -= 50
def shoot(self, user):
"""开枪"""
user.hit_points -= 100
self.hit_points -= 10
class Terriorist:
"""恐怖分子类。"""
def __init__(self, name, hit_points):
self.name = name
self.hit_points = hit_points
def shoot(self, user):
"""射击"""
user.hit_points -= 200
def strafe(self, user_list):
"""扫射"""
for user in user_list:
user.hit_points -= 200
def bomb(self, user_list):
"""炸"""
for user in user_list:
user.hit_points -= 300
self.hit_points -= 100
p1 = Police("computer", 19, 1100)
p2 = Police("science", 23, 1200)
p3 = Police("technology", 24, 1300)
t1 = Terriorist("恐怖分子1", 42, 800)
t1 = Terriorist("恐怖分子2", 46, 1000)
p3.shoot(t2) # Police.shoot()方法
t2.bomb([p3, p1]) # Terriorist.bomb()方法
t2.bomb([t1]) # Terriorist.bomb()方法
t1.strafe([t2, t2])
2.3 面向对象三大特性
2.3.1 封装
- 一种定义:将数据打包放到对象中。
class UserInfo:
def __init__(self):
self.name = name
self.age = age
self.email = email
obj1 = UserInof(“computer”, 22, "xxx@qq.ocm")
obj2 = UserInof(“computer”, 22, "xxx@qq.ocm")
obj3 = UserInof(“computer”, 22, "xxx@qq.ocm")
- 另一种定义 -- 归类:将同一类型的函数,汇总到一类中.
class Message:
def email(self):
pass
def wechat(self):
pass
...
class FileHandler:
def txt(self):
pass
def txt(self):
pass
...
2.3.2 继承
子承父业 -- 为什么要有继承,继承存在的意义
class Foo:
pass
class Son(Foo):
pass
class F1:
def show(self):
print(123)
def do(self):
pass
class F2:
def show(self):
print(123)
def exec(self):
pass
我们发现上述代码中show
函数在类F1
和F2
中都有为了代码的可重用性,我们可以按照下面这样写:
class Base:
def show(self):
print(123)
class F1(Base):
def do(self):
pass
class F2(Base):
def exec(self):
pass
2.3.2.1 示例一
class Base:
def show(self):
print("123")
class Son(Base):
def do(self):
print("do")
s1 = Son()
# 当前对象是由哪个类创建出来的,找方法的时候,优先去创建它的这个类里面去找.
s1.方法()
s1.do() # do
s1.show() # 传的self参数是:s1对象,依然是调用这个方法的对象
b1 = Base()
b1.show() # "123"
b1.do() # 报错
2.3.2.2 示例二
class Base:
def show(self):
print("123")
def do(self):
print("Base do")
class Son(Base):
def do(self):
print("do")
s1 = Son()
# 当前对象是由哪个类创建出来的,找方法的时候,优先去创建它的这个类里面去找.
s1.do()
s1.show()
b1 = Base()
b1.show()
b1.do()
[!Note]
要点:
self本质是什么: - 本质上是一个参数 - 由哪个对象调用这个方法,self就是哪个对象.
2.3.2.3 示例三
class Base:
def show(self):
print("123")
def do(self):
print("Base do")
class Son(Base):
def do(self):
print("do")
def show(self):
print("show")
self.do()
s1 = Son()
s1.show() #
"""
show
do
"""
[!Important]
self
本质上是一个参数,哪个对象调用了方法,self
就是哪个对象。对象.方法()时,优先去创建这个对象的类中找方法,找不到再去根据继承关系向上寻找。
2.3.2.4 实例四
class Base:
def show(self):
print("show")
self.do()
def do(self):
print("Base do")
class Son(Base):
def do(self):
print("do")
s1 = Son()
s1.show()
"""
show
Base do
"""
2.3.2.5 示例五
class Base:
def show(self):
print("show")
self.do()
def do(self):
print("Base do")
class Son(Base):
def do(self):
print("do")
b1 = Base()
b1.show()
"""
show
Base do
"""
2.3.2.6 示例六
class F1:
...
class F2:
...
class Foo(F1, F2):
...
# 多继承 -- 寻找成员时,优先去自己的类中找,如果没有,那就先去左边的类里面找
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("afters")
obj = ThreadingTCPServer()
obj.run()
>>> before
>>> ThreadingMixIn
>>> after
2.3.2.7 实例七
class BaseServer:
def run(self):
print("RUN")
self.f1()
class TCPServer(BaseServer):
def f1(self):
print("TCPServer")
class ThreadingMixIn:
def f1(self):
print("ThreadingMixIn")
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
obj = ThreadingTCPServer()
obj.run()
>>> RUN
>>> ThreadingMixIn
>>>
2.3.3 多态
Java
等编程语言中,多态是比较重要的,在python
中默认支持多态。
多态 -- 多种形态,多种类型。
# arg参数可以使多种形态 多种类型。多类型 各种各样的类型
def func(arg):
arg.send()
# 对于这个func函数,arg可以传递各种类型的对象 + 只要有对应的方法就行了(在这个函数中是send方法)
class F1:
def send(self):
pass
class F2:
def send(self):
pass
obj1 = F1()
obj2 = F2()
func(obj1)
func(obj2)
在Java
中:
pubic void func(String v1){
}
func("aaa") // √
func(12345) // ×
// 要想实现可以传递多种形态和多种类型的参数,需要使用多态来实现
面向对象三大特性:封装、继承、多态
3 面向对象补充
[!Tip]
这部分是观看另外的一个视频所记的笔记
内容概要:
-
函数式编程和面向对象的对比
-
面向对象如何编程
-
面向对象三大特性:
3.1 封装
3.2 继承
3.3 多态
-
成员
-
组合(建模、耦合等)
3.1 函数式编程和面向对象的对比
开发一个消息提醒的功能(发邮件 短信 微信的提醒)
函数式编程的优点:调用简单、定义简单
面向对象的缺点:调用复杂、定义复杂 优点:可归类,将一堆类似的功能放到一起
class F1:
def __init__(self): # 这个函数:只要 类名() 就会自动调用这个方法 -- 构造方法
pass
通过构造方法,可以将数据打包,以后需要使用的时候直接去拿就可以了。
3.2 面向对象的应用
如果遇到很多函数都要用到同一个参数的时候,可以使用面向对象的方式编程
- 将数据封装到对象中,以供自己在方法中调用
- 将数据封装到对象中,以供其它函数调用
class FileHandler:
def read_first(self, file_path):
pass
def read_second(self, file_path):
pass
def read_last(self, file_path):
pass
上述程序,我们可以看出来,实现这些方法都需要一个文件路径来打开文件再进行操作,所以可以这样写:
class FileHandler:
def __init__(self, file_path):
self.file_path = file_path
def read_first(self):
with open(self.file_path, "r", encoding="utf-8") as fp:
...
def read_second(self):
with open(self.file_path, "r", encoding="utf-8") as fp:
...
def read_last(self):
with open(self.file_path, "r", encoding="utf-8") as fp:
...
还可以进行优化:我们发现上述代码,如果我们要先读第一行read_first
,再读第二行read_second
最后读最后一行read_last
,那么我们需要像下面这样写:
F = FileHandler("./db.txt")
F.read_first()
F.read_second()
F.read_last()
但是如果这样写,就会导致一个文件打开三次 -- 于是可以再进行优化,优化如下:
class FileHandler:
def __init__(self, file_path):
self.file_path = file_path
self.f = open(file_path, "r")
def read_first(self):
self.f.read()
pass
def read_second(self):
self.f.read()
pass
def read_last(self):
self.f.read()
pass
F = FileHandler("./db.txt")
F.read_first()
F.read_second()
F.read_last()
F.obj.close() # 打开文件记得关闭
# 下面这种打包的思想
def func(*args, **kwargs):
print(args)
print(kwargs["k1"])
func(1, 2, 3, k1=1, k2=3)
# 也可以使用面向对象的思想来实现
def new_func(arg):
arg.k1
arg.k2
arg.k6
class Foo:
def __init__(self, k1, k2, k6):
self.k1 = k1
self.k2 = k2
self.k6 = k6
obj = Foo(111, 222, 333)
new_func(obj)
练习:信息管理系统
- 用户登录
- 显示当前用户信息
- 查看当前用户所有的账单
- 购买了姑娘形状的抱枕
class Account:
def __init__(self):
self.name = None
def info(self):
"""
打印用户信息
Returns:
"""
print("用户名:", self.name)
def account(self):
"""
打印用户账单
Returns:
"""
pass
def buy_pillow(self):
"""
购买抱枕
Returns:
"""
pass
def login(self):
user = input("请输入用户名:")
password = input("请输入密码:")
if password == "123456":
self.name = user
while True:
print("1 查看用户信息 2 查看用户啊账单 3 购买抱枕")
num_choose = int(input("""请输入选项:"""))
if num_choose == 1:
self.info()
elif num_choose == 2:
self.account()
elif num_choose == 3:
self.buy_pillow()
else:
print("输入错误,请重新输入!")
break
print("登录成功!")
else:
print("登录失败!")
obj = Account()
obj.login()
3.3 如何编写面向对象程序
3.3.1 什么时候写、如何写
-
方式一:归类 + 提取公共值 -- 反推
def file_read(file_path): pass def file_update(file_path): pass def file_delete(file_path): pass def file_add(file_path): pass def excel_read(file_path): pass def excel_update(file_path): pass def excel_delete(file_path): pass def excel_add(file_path): pass
--> 归类:仁者见仁 智者见智
class File: def file_read(file_path): pass def file_update(file_path): pass def file_delete(file_path): pass def file_add(file_path): pass class ExcelFile: def excel_read(file_path): pass def excel_update(file_path): pass def excel_delete(file_path): pass def excel_add(file_path): pass
提取公共值:
class File: def __init__(self, file_path): self.file_path = file_path def file_read(file_path): pass def file_update(file_path): pass def file_delete(file_path): pass def file_add(file_path): pass class ExcelFile: def __init__(self, file_path): self.file_path = file_path def excel_read(file_path): pass def excel_update(file_path): pass def excel_delete(file_path): pass def excel_add(file_path): pass
-
方式二:正向编写
[!IMPORTANT]
在指定类中编写和当前类相关的所有代码
class Message: def email(self): pass def wechat(self): pass class Person: def __init__(self, gender, age, name): self.gender = gender self.age = age self.name = name def sing(self): pass def dancing(self): pass def rap(self): pass def basketball(self): pass obj = Person("男", 18, "computer") ...
3.4 三大特性
3.4.1 封装
将相关功能打包(封装)到一个类中
将数据打包(封装)到一个对象中
3.4.2 继承
自己(子类/派生类)有就用自己的,没有就用父亲(基类)的。
子类和父类是相对而言的。
为什么要有继承 -- 为了复用,提高代码重用性。
3.4.3 多态
鸭子模型:只要可以嘎嘎叫,那就是鸭子。
python
原生支持多态- 崇尚鸭子模型
- 传参时无需指定类型
3.5 成员
-
类的成员
class Foo: def __init__(self, name): self.name = name # 实例变量/对象变量/字段 -- 作用是对对象初始化 def func(self): pass # obj = Foo("haha") # Foo类的实例/对象
-
成员共分为三类:
-
变量/字段
-
实例变量(字段)
-
公有实例变量
class Foo: def __init__(self, name): self.name = name # 公有实例变量 self.age = 123 # 公有实例变量 def func(self): # 公有变量 在内部调用 print(self.name) obj = Foo("computer") # 公有变量在外部调用 print(obj.name) print(obj.age)
-
私有实例变量
class Foo: def __init__(self, name): self.__name = name # 私有实例变量 self.age = 123 # 公有实例变量 def func(self): print(self.__name) # 类内部调用私有实例变量 -- 间接访问 obj = Foo("computer") # 公有变量在外部调用 print(obj.age) # 类外部调用私有变量 print(__name) # 报错,显示“没有__name这个属性” obj.func() # 可以访问
-
-
类变量(静态字段) -- 可以直接通过类进行访问
class Foo: country = "中国" # 类变量(静态字段) -- 在内存中,这个变量是放在类那个空间里面 -- 如果每个对象里面都需要设置一个相同的值,并且要改都改,要删都删,那就可以将其提取为类变量。 def __init__(self, name): self.name = name # 实例变量/对象变量/字段 -- 作用是对对象初始化 def func(self): pass obj = Foo("computer") obj1 = Foo("science") print(obj.country) # 中国 print(obj1.country) # 中国
obj.country = "美国" # 只改的是自己对象所在内存区域的country变量,和Foo类里面的country没有关系 print(obj.country) # 美国 print(obj1.country) # 中国
Foo.country = "美国" print(obj.country) # 美国 print(obj1.country) # 美国
-
公有类变量
class Foo: country = "中国" def __init__(self): pass def func(self): # 内部调用 print(self.country) print(Foo.country) # 外部调用 print(Foo.country) obj = Foo() print(obj.country) print(Foo.country)
-
私有类限量
class Foo: __country = "中国" def __init__(self): pass def func(self): # 内部调用 print(self.__country) print(Foo.__country) # 外部直接调用 print(Foo.__country) # 无法调用 obj = Foo() print(obj.__country) # 无法调用 print(Foo.__country) # 无法调用 obj.func() # 外部间接调用,可以调用
-
如果非要访问,也不是不行
class Foo: def __init__(self, name): self.__name = name obj = Foo("hahaha") obj.__name # 无法访问 print(obj._Foo__name) # 可以访问但不推荐
-
-
准则:以后
- 对于实例变量/字段,访问时使用对象访问,
obj.xxx
- 对于类变量/静态字段,访问时,使用类来访问,如果实在不方便时,使用对象访问。
- 对于实例变量/字段,访问时使用对象访问,
思考题:私有变量,不仅外部无法访问,其子类也无法访问。那问题来了,如何验证?
class Base(object): #python 3+ 所有、任何类都会继承object类,不管写不写object __private = "私有" class Foo(Base): def func(self): print(self.__private) print(Foo.__private) Foo().func() # 无法调用
class Base(object): #python 3+ 所有、任何类都会继承object类,不管写不写object __private = "私有" def tell(self): print(Base.__private) class Foo(Base): def func(self): print(self.__private) print(Foo.__private) Foo().tell() # 可以调用
-
-
方法
-
方法(实例方法) -- 当实例方法里面如果需要调用到构造方法里面的值的时候才需要用到实例方法
class Foo(object): def __init__(self, name): self.name = name def func(self): # 实例方法 print("实例方法") print(self.name) obj = Foo("computer") obj.func()
-
静态方法 -- 如果方法中无需使用构造方法中封装的数据、对象中封装的方法时,那就写静态方法
class Foo(object): def __init__(self, name): self.name = name def func(self): # 实例方法 print(self, "实例方法") print(self.name) @staticmethod def display(): # 静态方法 print(123) @classmethod def show(cls, a, b): """类方法""" print(999) obj = Foo("computer") obj.func() obj.show(1, 2) # cls传递的是当前类
-
类方法 -- 可以帮我们自动识别当前类 -- 如果在方法中会使用到当前类那么就可以使用类方法。
class Foo(object): def __init__(self, name): self.name = name def func(self): # 实例方法 print(self, "实例方法") print(self.name) @staticmethod def display(): # 静态方法 print(123) @classmethod def show(cls, a, b): """类方法""" print(999) obj = Foo("computer") obj.func() obj.show(1, 2) # cls传递的是当前类
-
公有方法
-
私有方法
class Foo(object): def __init__(self): # 这是特殊方法 self.name = "computer" def __display(self, arg): # 私有实例方法 print("私有方法") print(arg) def func(self): self.__display(233) obj = Foo() obj.__display("hello") # 无法访问 obj.func() # 可以访问
class Foo(object): def __init__(self): # 这是特殊方法 self.name = "computer" @staticmethod def __display(arg): # 私有静态方法 print("私有静态方法") print(arg) def func(self): self.__display(233) obj = Foo() obj.__display("hello") # 无法访问 obj.func() # 可以访问 Foo.func() # 可以访问
# 私有类方法 一样的
-
-
属性(特性) -- 通过方法改造出来的 -- 当一个方法不需要传递参数(只有一个
self
),并且return
一个东西时 -- 属性也有公有和私有之分 改造之前:class Foo(object): def __init__(self): pass def start(self): # 私有方法方法 return 1 def end(self): return 10 obj = Foo() obj.start() obj.end()
改造之后:
class Foo(object): def __init__(self): pass @property def start(self): # 私有方法方法 return 1 @property def end(self): return 10 obj = Foo() print(obj.start) print(obj.end)
[!Caution]
当将方法变成属性时,不能传参数。
-
3.5.1 面试题
[!Important]
面试题:静态方法/实例方法/类方法的区别:
- 如果在方法中不使用关于对象的方法,那么就使用静态方法;
- 如果我们需要使用对象中封装的数据,那么就使用实例方法;
- 如果我们需要在方法中使用当前类,那么就使用类方法
3.5.2 练习题:分页
- 面向过程:
data_list = []
for i in range(1, 301):
data_list.append("alex-%s" % i)
page_size = 10
print("请输入要查看的页码,输入q/Q退出。")
while True:
page_num_str = input(">>> ")
if page_num_str.upper() == "Q":
break
page_num = int(page_num_str)
page_start_index = (page_num - 1) * page_size + 1
page_end_index = page_num * page_size
for item in range(page_start_index - 1, page_end_index):
print(data_list[item], end=" ")
print()
- 面向对象
# 我的:
class Pagination(object):
"""
处理分页类
"""
def __init__(self, current_page_num):
"""
初始化分页类
Args:
total_page_num (): 总页数
"""
self.current_page_num = current_page_num
self.page_size = 2
def get_start_index(self):
"""
获取开始索引
Returns:
"""
page_start_index = (self.current_page_num - 1) * self.page_size + 1
return page_start_index
def get_end_index(self):
"""
获取结束索引
Returns:
"""
page_end_index = self.current_page_num * self.page_size
return page_end_index
# 老师的:
class Pagination(object):
"""
处理分页类
"""
def __init__(self, current_page_num, page_size=10, ):
"""
初始化分页类
Args:
current_page_num (int): 当前页数
page_size (int): 一页有多少条数据
"""
self.current_page_num = current_page_num
self.page_size = page_size
def start(self):
"""
获取开始索引
Returns:
"""
return (self.current_page_num - 1) * self.page_size + 1
def end(self):
"""
获取结束索引
Returns:
"""
return self.current_page_num * self.page_size
def main() -> int:
data_list = []
for i in range(1, 301):
data_list.append("alex-%s" % i)
print("请输入要查看的页码,输入q/Q退出。")
while True:
page_num_str = input(">>> ")
if page_num_str.upper() == "Q":
break
page_num = int(page_num_str)
pagination_obj = Pagination(page_num, 20)
page_start_index = pagination_obj.start()
page_end_index = pagination_obj.end()
for item in range(page_start_index - 1, page_end_index):
print(data_list[item], end=" ")
print()
return 0
if __name__ == '__main__':
main()
优化一下:
# 老师的:
class Pagination(object):
"""
处理分页类
"""
def __init__(self, current_page_num, page_size=10, ):
"""
初始化分页类
Args:
current_page_num (int): 当前页数
page_size (int): 一页有多少条数据
"""
self.current_page_num = current_page_num
self.page_size = page_size
@property
def start(self):
"""
获取开始索引
Returns:
"""
return (self.current_page_num - 1) * self.page_size + 1
@property
def end(self):
"""
获取结束索引
Returns:
"""
return self.current_page_num * self.page_size
def main() -> int:
data_list = []
for i in range(1, 301):
data_list.append("alex-%s" % i)
print("请输入要查看的页码,输入q/Q退出。")
while True:
page_num_str = input(">>> ")
if page_num_str.upper() == "Q":
break
page_num = int(page_num_str)
pagination_obj = Pagination(page_num, 20)
page_start_index = pagination_obj.start
page_end_index = pagination_obj.end
for item in range(page_start_index - 1, page_end_index):
print(data_list[item], end=" ")
print()
return 0
if __name__ == '__main__':
main()
另外一种分类方式:
class Pagination(object):
"""
处理分页类
"""
def __init__(self, current_page_num, page_size=10, ):
"""
初始化分页类
Args:
current_page_num (int): 当前页数
page_size (int): 一页有多少条数据
"""
self.current_page_num = current_page_num
self.page_size = page_size
@property
def start(self):
"""
获取开始索引
Returns:
"""
return (self.current_page_num - 1) * self.page_size
@property
def end(self):
"""
获取结束索引
Returns:
"""
return self.current_page_num * self.page_size
def show(self, data_list):
"""
打印分页的那一页的数据
Returns:
"""
page_start_index = self.start
page_end_index = self.end
print(data_list[page_start_index:page_end_index])
def main() -> int:
data_list = []
for i in range(1, 301):
data_list.append("alex-%s" % i)
print("请输入要查看的页码,输入q/Q退出。")
while True:
page_num_str = input(">>> ")
if page_num_str.upper() == "Q":
break
page_num = int(page_num_str)
pagination_obj = Pagination(page_num, page_size=10)
pagination_obj.show(data_list)
return 0
if __name__ == '__main__':
main()
3.6 组合(嵌套)
对象和对象之间可以进行嵌套。
class School(object):
def __init__(self, name, address):
self.name = name
self.address = address
def speech(self):
print("讲课")
pass
obj1 = School("computer", "address-a")
obj2 = School("science", "address-b")
obj3 = School("technology", "address-c")
class Teacher(object):
def __init__(self, name, age, __salary):
self.name = name
self.age = age
self.__salary = __salary
self.school = None
T1 = Teacher("a", 40, 15000)
T2 = Teacher("b", 64, 25000)
T3 = Teacher("c", 67, 35000)
T1.school = obj1
T2.school = obj1
T3.school = obj2
# 查看T1这个老师的学校的信息
print(T1.school.name)
print(T1.school.address)
# 查看老师的信息
print(T1.name)
print(T1.age)
T1.school.speech()
3.6.1 组合(嵌套)的补充
-
类/对象能否做字典的key? -- 可以的
class Foo(object): pass userinfo = {Foo: 1, Foo(): 2} print(userinfo)
-
对象中到底有什么? -- 此处要十分注意打印出的那个
None
class Foo(object): def __init__(self, age): self.age = age def display(self): print("age is:", self.age) data_list = [Foo(8), Foo(9)] for item in data_list: print("年龄是:", item.age, ) print(item.display())
-
封装 -- 注意,虽然子类没有
__init__
方法,但是继承了父类的__init__
方法,于是有了下面的输出。class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) class RoleConfig(StartConfig): def change_list(self, request): print(666) config_obj_list = [StartConfig(1), StartConfig(2), RoleConfig(3)] for item in config_obj_list: print(item.num)
-
函数的执行 -- 注意,还是前面讲的,去自己跌对象空间里面找,找不到再去父类找
class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) class RoleConfig(StartConfig): pass config_obj_list = [StartConfig(1), StartConfig(2), RoleConfig(3)] for item in config_obj_list: print(item.change_list(168))
-
还有
class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) class RoleConfig(StartConfig): def change_list(self, request): print(666) config_obj_list = [StartConfig(1), StartConfig(2), RoleConfig(3)] for item in config_obj_list: print(item.change_list(168))
class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) class RoleConfig(StartConfig): def change_list(self, request): print(666, self.num) config_obj_list = [StartConfig(1), StartConfig(2), RoleConfig(3)] for item in config_obj_list: print(item.change_list(168))
-
还有
class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) def run(self): print(self.change_list(999)) class RoleConfig(StartConfig): def change_list(self, request): print(666, self.num) config_obj_list = [StartConfig(1), StartConfig(2), RoleConfig(3)] for item in config_obj_list: item.run()
-
还有
class AdminSite(object): def __init__(self): self._registry = dict() def register(self, k, v): self._registry[k] = v site = AdminSite() print(len(site._registry)) site.register("a", 666) site.register("b", 123) print(len(site._registry))
class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) def run(self): self.change_list(999) class RoleConfig(StartConfig): def change_list(self, request): print(666, self.num) class AdminSite(object): def __init__(self): self._registry = dict() def register(self, k, v): self._registry[k] = v site = AdminSite() site.register("c", StartConfig(1999)) site.register("d", StartConfig(20)) site.register("e", RoleConfig(333)) print(len(site._registry)) # 3 for k, row in site._registry.items(): print(k, row, row.change_list(5))
-
还有
class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) def run(self): self.change_list(999) class RoleConfig(StartConfig): def change_list(self, request): print(666, self.num)
-
最后一个
class UserInfo(object): pass class Department(object): pass class StartConfig(object): def __init__(self, num): self.num = num def change_list(self, request): print(self.num, request) def run(self): self.change_list(999) class RoleConfig(StartConfig): def change_list(self, request): print(666, self.num) class AdminSite(object): def __init__(self): self._registry = dict() def register(self, k, v): self._registry[k] = v(k) # config_obj_list = [StartConfig(1), StartConfig(2), RoleConfig(3)] # for item in config_obj_list: # item.run() site = AdminSite() site.register(UserInfo, StartConfig) site.register(Department, StartConfig) for k, row in site._registry.items(): # {UserInfo: StartConfig(UserInfo), Department: StartConfig(Department)} row.run()
3.7 主动调用其他类的成员
# 如果有下面的程序:
class Base(object):
def f1(self):
print("Base.f1, 实现三个功能")
# 注意这个地方,如果我们要用类名调用函数,需要手动传参
obj = Base()
Base.f1(obj)
# 但是我们一般情况下不像上面那样写,因为上面的代码Base调用f1的时候Python内部不会自动帮我们传self参数,
# 所以要手动传参,所以我们要使用下面的方式
# 上面那种方式和下面这种方式是一样的
obj = Base()
obj.f1()
class Base(object):
def f1(self):
print("Base.f1, 实现三个功能")
class Foo(object):
def f1(self):
print("Foo.f1, 实现五个功能")
Base.f1(self) # 主动调用 方式一
# 如果要执行八个功能 如上
obj = Foo()
obj.f1()
但是上述代码和继承没有半毛钱关系!!! 因为两个类没有继承关系!!!
# 主动调用 方式二
class Base(object):
def f1(self):
print("Base.f1, 实现三个功能")
class Foo(Base):
def f1(self):
print("Foo.f1, 实现五个功能")
super().f1() # 按照类的继承顺序去找
# 如果要执行八个功能 如上
obj = Foo()
obj.f1()
class Base(object):
def f1(self):
print("Base.f1, 实现三个功能")
class Foo(object):
def f1(self):
super().f1() # 按照类的继承顺序去找 找下一个!!! 是找下一个!!!
print("Foo.f1, 实现五个功能")
class Bar(object):
def f1(self):
print("Base.f1, 实现六个功能!")
class Info(Foo, Bar):
pass
# 如果要执行八个功能 如上
obj = Info()
obj.f1()
[!Important]
下面这个很重要,多看!!!
class Base(object):
def f1(self):
print("Base.f1, 实现三个功能")
class Foo(object):
def f1(self):
super().f1() # self传进来的是哪个对象 就按照哪个对象的继承顺序去找下一个 找下一个!!! 是找下一个!!!
print("Foo.f1, 实现五个功能")
class Bar(object):
def f1(self):
print("Base.f1, 实现六个功能!")
class Info(Foo, Bar):
pass
# 如果要执行八个功能 如上
obj = Foo()
obj.f1()
3.8 特殊成员
[!Note]
注意:谁创建对象,谁就是构造方法!!!在
python
中一般认为是__new__
方法 -- 因为其创建了空的对象,只是在__init__
方法中进行
3.8.1 一些特殊方法
class Foo(object):
def __new__(cls, *args, **kwargs):
"""
创建一个空的对象,然后返回这个对象,在__init__方法中进行初始化
必须设置返回值,否则执行完__new__后不会自动执行__init__方法 并且,返回值必须是object.__new__(cls)
Args:
*args ():
**kwargs ():
"""
# 那么问题来了,这个v1和obj = Foo(1, 2) 是不是同一个对象?
# 答案是:内存地址是一样的,但是里面的值是不一样的,因为object.__new__(cls)是空的 但是v1是真正有值的对象 -- 内存地址是一样的
return object.__new__(cls) # python内部创建一个当前类的对象(初始时内部是空的) 在__init__里面才进行初始化,使变得不空
def __init__(self, a1, a2):
"""
为空对象进行数据初始化。
Args:
a1 ():
a2 ():
"""
self.a1 = a1
self.a2 = a2
def __call__(self, *args, **kwargs):
"""
Args:
*args ():
**kwargs ():
Returns:
"""
print(1111, args, kwargs)
return 123
def __getitem__(self, item):
"""
Args:
item ():
Returns:
"""
print(item)
return 8
def __setitem__(self, key, value):
"""
这种的是没有返回值的。
Args:
key ():
value ():
Returns:
"""
print(key, value, 123)
def __delitem__(self, key):
"""
这种的是没有返回值的。
Args:
key ():
Returns:
"""
print(key)
def __add__(self, other):
"""
Args:
other ():
Returns:
"""
return self.a1 + other.a1
def __enter__(self):
"""
Returns:
"""
print(111)
return 132456
def __exit__(self, exc_type, exc_val, exc_tb):
"""
Args:
exc_type ():
exc_val ():
exc_tb ():
Returns:
"""
print(222)
# 类名() 自动执行__init__方法
obj = Foo(1, 2)
# 对象() 自动执行__call__方法
res = obj(1, 2, 3, k1=1, k2=2)
print(res)
# 对象[] 自动执行__getitem__方法
res = obj['yu']
print(res)
# 对象[xxxx] = xxx 自动执行__setitem__方法
obj["computer"] = "science"
# del 对象[xxx] 自动执行__delitem__方法
del obj["xxx"]
# 还有很多的方法 自己查看源码
# 对象 + 对象 自动执行__add__方法
obj1 = Foo(1, 2)
obj2 = Foo(3, 4)
res = obj1 + obj2 # 这里会报错 因为没有实现__add__方法
print(res)
# with 对象.方法 自动执行__enter__方法
with obj as f:
print("内部的代码!")
print(f) # 这个f就是__enter__方法的返回值
# 真正的构造方法 __new__ 在实例化对象的时候,先执行__new__方法 再执行__init__方法
# print(对象) 自动执行__str__方法
# 对象 * 对象 自动执行__mul__方法
# 对象 in 对象 自动执行__contains__方法
# 对象 == 对象 自动执行__eq__方法
# 对象 != 对象 自动执行__ne__方法
# 对象 < 对象 自动执行__lt__方法
# 对象 <= 对象 自动执行__le__方法
# 对象 > 对象 自动执行__gt__方法
# 对象 >= 对象 自动执行__ge__方法
# 对象 | 对象 自动执行__or__方法
# 对象 & 对象 自动执行__and__方法
# 对象 ^ 对象 自动执行__xor__方法
# 对象 << 对象 自动执行__lshift__方法
# 对象 >> 对象 自动执行__rshift__方法
# 对象 ** 对象 自动执行__pow__方法
# 对象 // 对象 自动执行__floordiv__方法
# 对象 / 对象 自动执行__truediv__方法
# 对象 % 对象 自动执行__mod__方法
# 对象() 自动执行__call__方法
# 对象[xxx] 自动执行__getitem__方法
# 对象[xxx] = xxx 自动执行__setitem__方法
# del 对象[xxx] 自动执行__delitem__方法
# 对象 += 对象 自动执行__iadd__方法
# 对象 *= 对象 自动执行__imul__方法
# 对象 |= 对象 自动执行__ior__方法
# 对象 &= 对象 自动执行__iand__方法
# 对象 ^= 对象 自动执行__ixor__方法
# ...
3.8.2 重点
- 组合练习题
******
- 主动调用其他类的成员
***
- 特殊成员
***
isinstance/issubclass/type
***
3.9 练习题
- 第一题:
class StarkConfig(object):
list_display = []
def __init__(self):
pass
def get_list_display(self):
self.list_display.insert(0, 3)
return self.list_display
class RoleConfig(object):
list_display = [11, 22]
def __init__(self):
pass
s1 = StarkConfig()
res1 = s1.get_list_display()
print(res1) # [3]
res2 = s1.get_list_display()
print(res2) # [3, 3]
- 第二题:
class StarkConfig(object):
list_display = []
def __init__(self):
pass
def get_list_display(self):
self.list_display.insert(0, 3)
return self.list_display
class RoleConfig(StarkConfig):
list_display = [11, 22]
def __init__(self):
pass
s1 = StarkConfig()
s2 = StarkConfig()
res1 = s1.get_list_display()
print(res1) # [3]
res2 = s2.get_list_display()
print(res2) # [3]
- 第三题:
class StarkConfig(object):
list_display = []
def __init__(self):
pass
def get_list_display(self):
self.list_display.insert(0, 3)
return self.list_display
class RoleConfig(StarkConfig):
list_display = [11, 22]
def __init__(self):
pass
s1 = StarkConfig()
s2 = RoleConfig()
res1 = s1.get_list_display()
print(res1) # [3]
res2 = s2.get_list_display()
print(res2) # [3, 11, 22]
- 第四题:
class StarkConfig(object):
list_display = []
def __init__(self):
pass
def get_list_display(self):
self.list_display.insert(0, 3)
return self.list_display
class RoleConfig(StarkConfig):
list_display = [11, 22]
def __init__(self):
pass
s1 = RoleConfig()
s2 = RoleConfig()
res1 = s1.get_list_display()
print(res1) # [3, 11, 22]
res2 = s2.get_list_display()
print(res2) # [3, 3, 11, 22]
3.10 面向对象相关
isinstance/issubclass/type
- 方法和函数
- 反射
3.10.1 issubclass
[!Caution]
注意,这个子类和父类,求得是子子孙孙的关系,并不只是两个层级的关系,而是跨越多个和继承层级的。
class Base(object):
pass
class Foo(Base):
pass
class Bar(Foo):
pass
# 检查第一个参数是否是第二个参数的子类
print(issubclass(Foo, Base)) # True
print(issubclass(Base, Foo)) # False
print(issubclass(Bar, Base)) # True
3.10.2 type
class Foo(object):
pass
class Bar(object):
pass
obj = Foo()
print(obj, type(obj)) # 获取当前对象是由哪个类创建。
v = type(obj) is Foo
print(v)
obj1 = Foo()
obj2 = Foo()
obj3 = Bar()
def func(*args):
foo_count = 0
bar_count = 0
for item in args:
if type(item) is Foo:
foo_count += 1
if type(item) is Bar:
bar_count += 1
return foo_count, bar_count
print(func(obj1, obj2, obj3))
3.10.3 isinstance
判断,是谁创建这个对象,往上找,只要往上找,能找到就返回True
-- 相比较于type
,找的范围更大
class Base(object):
pass
class Foo(Base):
pass
class Bar(object):
pass
obj = Foo()
print(obj, isinstance(obj, Foo)) # True 检查第一个参数是否是第二个参数(类或者父类)的实例 第一个参数一般是对象 第二个参数一般是类
print(obj, isinstance(obj, Bar)) # False
print(obj, isinstance(obj, Base)) # True
注意:给你一个参数,判断对象是不是某一个指定类 -- type
给你一个参数,判断对象是不是某一个指定类(或其父类) -- ininstance
3.10.4 方法和函数的区分
def func():
pass
class Foo(object):
def func(self):
pass
@staticmethod
def xxx():
pass
print(func) # 函数 <function func at 0x0000019B8BA5E0C0>
print(Foo().func) # 方法 <bound method Foo.func of <__main__.Foo object at 0x0000019B8BC016D0>>
print(Foo().xxx) # 函数 <function Foo.xxx at 0x00000294E219E700>
print(Foo.xxx) # 函数 <function Foo.xxx at 0x00000294E219E700>
class Foo(object):
def f1(self):
pass
def f2(self):
pass
def f3(self):
pass
list_display = [f1, f2]
# def get_list_display(self):
# self.list_display.append(self.f3)
# return self.list_display
def __init__(self):
pass
obj = Foo()
for item in Foo.list_display:
print(item) # 都是函数
# item(132)
# 这里有一点,是否是函数还是方法,不是通过是否写在类里面判断的,而是通过调用这个函数的对象来判断的
# 如果是通过类名来调用的,那么就是函数--就需要自己传递那个对象 如果是通过对象来调用的,那么就是方法--方法是自动传值的
class Foo(object):
def f1(self):
pass
def f2(self):
pass
def f3(self):
pass
list_display = [f1, f2]
# def get_list_display(self):
# self.list_display.append(self.f3)
# return self.list_display
def __init__(self):
pass
obj = Foo()
Foo.list_display.append(obj.f3)
for item in Foo.list_display:
print(item)
# 这里有一点,是否是函数还是方法,不是通过是否写在类里面判断的,而是通过调用这个函数的对象来判断的
# 如果是通过类名来调用的,那么就是函数--就需要自己传递那个对象 如果是通过对象来调用的,那么就是方法--方法是自动传值的
3.11 反射
[!Tip]
问题:我们有十个功能,每个功能对应一个函数,我希望在用户选择的时候能够快速的选择出来需要的功能你会用什么方法?
- 一大堆if else
- 反射
以字符串为参数,去模块中寻找与之同名的函数 -- 反射
3.11.1 重点
# handler.py
def f1():
print("f1")
def f2():
print("f2")
def f3():
print("f3")
def f4():
print("f4")
def f5():
print("f5")
# reflect.py
# -*- coding: utf-8 -*-
# @CreateTime : 2024/4/27 027 18:32
# @Author : 瑾瑜@20866
# @IDE : PyCharm
# @File : studyProject/reflect.py
# @Description :
# @Interpreter : python 3.10
# @Motto : You must take your place in the circle of life!
# @Site : https://github.com/wephiles or https://gitee.com/wephiles
import handler
from types import FunctionType
# handler.f1()
# handler.f2()
# handler.f3()
# handler.f4()
# handler.f5()
print("""系统支持的函数有:
1: f1
2: f2
3: f3
4: f4
5: f5
""", end=" ")
while True:
print("请输入要执行的函数. eg: \n>>>f1 \n ===================================")
val = input(">>> ")
# handler.val() # 错误的写法 -- 因为这样会去handler里面找val函数!但是handler里面没有这个函数,
# 此外,如果有这个函数的话,可能造成巨大的问题!
# # 下面这样写是正确的,但是不够优雅!!!
# if var == "f1":
# handler.f1()
# elif var == "f2":
# handler.f2()
# elif var == "f3":
# handler.f3()
# elif var == "f4":
# handler.f4()
# elif var == "f5":
# handler.f5()
# else:
# print("输入错误, 请重新输入.")
# # 怎么办? -- 使用反射!
# # 反射:通过字符串调用函数,而不是直接调用函数。
# func = getattr(handler, "f1") # 直接去handler模块里面找f1函数(通过字符串的形式) -- 返回一个function对象
# func()
# # 这个函数的作用是通过字符串调用函数,而不是直接调用函数。
# # 第一个参数是模块名,第二个参数是函数名(字符串类型)。
# # 它会返回一个函数对象,然后就可以调用这个函数对象了。
if hasattr(handler, val):
func_or_val = getattr(handler, val)
if isinstance(func_or_val, FunctionType):
func_or_val()
else:
print(func_or_val)
else:
print("输入错误, 请重新输入.")
break
# 这样就可以通过字符串调用函数了!
# --END--
# 上述表述不够精准,还需修改:
class Foo(object):
country = "中国"
def func(self):
pass
# v = getattr(Foo, "country") # 根据字符串,从类实例中寻找
# print(v) # 中国
# v = getattr(Foo, "func") # # 根据字符串,从类中寻找
# print(v) # <function Foo.func at 0x0000027D372D8C20>
# obj = Foo()
#
# v = getattr(obj, "func") # 根据字符串,从对象中寻找
# print(v) # <bound method Foo.func of <__main__.Foo object at 0x000001EEE8031550>>
[!Important]
准确的说,
getattr
--> 根据字符串为参数,去对象中寻找与之同名的成员
class Account(object):
function_list = ['login', 'register', 'logout']
def login(self):
"""
登录
Returns:
"""
print("login")
def register(self):
"""
注册
Returns:
"""
print("register")
def logout(self):
"""
注销
Returns:
"""
print('logout')
def run(self):
"""
运行 主代码
Returns:
"""
print("请输入要执行的功能:1、登录 2、注册 3、注销 4、退出")
choice = int(input(">>> "))
func_name = Account.function_list[choice-1]
# func = getattr(Account, func_name) # 函数
# func(self)
func = getattr(self, func_name) # 函数
func()
pass
obj = Account()
obj.run()
obj1 = Account()
obj1.run()
-
关于
attr
家族:getattr
-- 根据字符串形式,去对象中找成员hasattr
-- 根据字符串形式,判断对象中是否有成员setattr
-- 根据字符串形式,去动态地设置成员(内存)delsttr
-- 根据字符串形式,去动态地删除成员(内存)
# demo3.py x1 = 123 def f1(arg): print(arg, 666)
# practice.py import demo3 v1 = (demo3, "x1") v2 = getattr(demo3, "f1") # # getattr # print(v1) # (<module 'demo3' from 'F:\\CSProjects\\PycharmProjects\\studyProject\\OOP\\demo3.py'>, 'x1') # print(v2) # <function f1 at 0x000002CCD1998C20> # v2("computer") # computer 666 # hasattr v3 = hasattr(demo3, "x1") v4 = hasattr(demo3, "f1") v5 = hasattr(demo3, "f111") print(v3, v4) # True True print(v5) # False # setattr setattr(demo3, 'x2', 999) # 设置了 但demo3.py中没有x2 -- 在内存中 但是没有写入文件 print(getattr(demo3, 'x2')) # 999 setattr(demo3, 'f2', lambda x: x + 1) # 设置了 但demo3.py中没有x2 -- 在内存中 但是没有写入文件 print(getattr(demo3, 'f2')) # <function <lambda> at 0x000001F6DCCBE0C0> # delattr delattr(demo3, "x1") v9 = getattr(demo3, "x1") # 报错
class Foo(object): def __init__(self, a1): self.a1 = a1 obj = Foo(1) v1 = getattr(obj, "a1") print(v1) # # !!!注意!:不推荐使用setattr # setattr(obj, "a2", 2) # v2 = getattr(obj, "a2") # print(v2)
3.11.2 补充
什么后面可以加()? -- 只要可以加括号,就是可被执行/可被调用
- 类()
- 对象()
- 函数()
- 方法()
def func():
pass
class Foo(object):
pass
def func(self):
pass
class Bar(object):
def __call__(self, *args, **kwargs):
pass
data = 123
obj = Foo()
obj1 = Bar()
print(callable(func)) # True
print(callable(Foo)) # True
print(callable(obj)) # False
print(callable(obj.func)) # True
print(callable(obj1)) # True
print(callable(data)) # False
接下来要讲:
- 约束
***
- 自定义异常
***
hashlib
*****
- 日志
logging
****
3.12 类的约束
3.12.1 约束的概念
什么是约束:约束其派生类,保证派生类中必须要编写某一个方法。
如果是约束,这个类必须抛出 NotImplementedError
class BaseMessage(object):
"""
潜规则,以后根据这个基类写的代码都必须要重新send方法,否则会抛出异常
"""
def send(self):
"""
必须要继承BaseMessage的send方法,来完成相关的业务逻辑。
Returns:
"""
raise NotImplementedError(".send()方法必须被重写。") # 如果是约束,这个类必须抛出 NotImplementedError
class Email(BaseMessage):
def send(self):
pass
def f1(self):
pass
def f2(self):
pass
class Wechat(BaseMessage):
def send(self):
pass
def f1(self):
pass
def f2(self):
pass
class Msg(BaseMessage):
def send(self):
pass
def f1(self):
pass
def f2(self):
pass
def func(arg):
"""
报警通知功能
Args:
arg ():
Returns:
"""
arg.send()
obj = Msg()
看源码:
from rest_framework.authentication import SessionAuthentication
from rest_framework.authentication import RemoteUserAuthentication
from rest_framework.authentication import TokenAuthentication
上述三个类其实都继承了BaseAuthentication
类。看下面这张图片方框框出的内容,这就是约束。
[!Caution]
建议使用:
def func(arg): """ 报警通知功能 Args: arg (): Returns: """ arg.send() class BaseMessage(object): """ 潜规则,以后根据这个基类写的代码都必须要重新send方法,否则会抛出异常 """ def send(self, x1): """ 必须要继承BaseMessage的send方法,来完成相关的业务逻辑。 Returns: """ raise NotImplementedError(".send()方法必须被重写!") class Wechat(BaseMessage): def send(self): pass def f1(self): pass def f2(self): pass class Msg(BaseMessage): def send(self): pass def f1(self): pass def f2(self): pass class Email(BaseMessage): pass def send(self, x1): pass obj = Email() obj.send(123)
3.12.2 补充
python
:
-
类
class Foo: pass
-
类
-
抽象类 -- 这个基本没人用 -- 常用人为抛出异常
from abc import ABCMeta, abstractmethod class Base(metaclass=ABCMeta): # 定义了抽象类 """ 抽象类,语法就是这样,记住就行了。 """ def f1(self): """ 普通方法 Returns: """ pass @abstractmethod def f2(self): """ 抽象方法 Returns: """ pass class Foo(Base): pass obj = Foo() obj.f1() obj.f2()
-
java、C#
:专业的叫实现一个接口。 -- 可以简单理解为继承
-
接口:接口中不允许在方法内部写代码 -- 只能约束实现(继承)他的类必须**实现(implement)**接口中实现的所有方法
接口关键字为interface
java
允许实现(继承)多个接口。 -
类
类关键字为class
-
类
-
抽象类 -- 里面可以有抽象方法 -- 约束继承他的派生类必须实现他其中的抽象方法。 -- 抽象方法里面不能写代码
关键字为 abstract class 类名 关键字为 abstract 方法名
-
3.13 自定义异常
程序设计的时候,要处理程序中的问题,有以下几种方式:
3.13.1 第一种方式:
import os
def func(path, prev):
"""
去path路径的文件中找前缀为prev的数据,并返回
1000 成功
1001 文件不存在
1002 关键字为空
1003 未知错误
...
Args:
path ():
prev ():
Returns:
"""
response = {"code": 1000, "data": None}
try:
if not os.path.exists(path):
response["code"] = 1001
response["data"] = "文件不存在"
return response
if not prev:
response["code"] = 1002
response["data"] = "关键字为空"
return response
pass
except Exception as e:
response["code"] = 1003
response["data"] = "未知错误"
return response
def show():
return 8
def run():
v1 = func()
v2 = show()
3.13.2 第二种方式: -- 着重关注下面代码中的new_func()
函数
import os
class FileExistException(Exception):
pass
class KeyInvalidError(Exception):
pass
def func(path, prev):
"""
去path路径的文件中找前缀为prev的数据,并返回
1000 成功
1001 文件不存在
1002 关键字为空
1003 未知错误
...
Args:
path ():
prev ():
Returns:
"""
response = {"code": 1000, "data": None}
try:
if not os.path.exists(path):
response["code"] = 1001
response["data"] = "文件不存在"
return response
if not prev:
response["code"] = 1002
response["data"] = "关键字为空"
return response
pass
except Exception as e:
response["code"] = 1003
response["data"] = "未知错误"
return response
def new_func(path, prev):
"""
去path路径的文件中找前缀为prev的数据,并返回
1000 成功
1001 文件不存在
1002 关键字为空
1003 未知错误
...
Args:
path ():
prev ():
Returns:
"""
response = {"code": 1000, "data": None}
try:
if not os.path.exists(path):
raise FileExistException()
if not prev:
raise KeyInvalidError()
pass
except FileExistException as e:
response["code"] = 1001
response["data"] = "文件不存在"
except KeyInvalidError as e:
response["code"] = 1002
response["data"] = "关键字为空"
except Exception as e:
response["code"] = 1003
response["data"] = "未知错误"
return response
def show():
return 8
def run():
v1 = func()
v2 = show()
3.13.3 自定义异常类
class MyException(Exception):
"""
自定义异常类。
"""
def __init__(self, code, message):
self.code = code
self.message = message
try:
raise MyException(1000, "自定义异常啦")
except MyException as e: # 捕获异常 这个e是一个对象
print(e.code, e.message)
class MyException(Exception):
"""
自定义异常类。
"""
def __init__(self, code, message):
self.code = code
self.message = message
try:
raise MyException(1000, "自定义异常啦")
except MyException as e: # 捕获异常 这个e是一个对象
print(e.code, e.message)
except Exception as e: # 捕获异常 这个e是一个对象
print(e)
3.14 hashlib
import hashlib
SALT = b"daojdjuioaejhwdejas98dfjoiwejf9pweqj9iJCOPIEJWFUOHREIUOFHJ9ERHJGUIEHGUHJDIS9UPHFGOISAJR8T9FHUEWSOUIGHOLIDFSUAH"
obj = hashlib.md5() # 先实例化一个对象
obj.update("admin".encode("utf-8")) # 想对谁加密,就把参数传进去 在python3.5中,这个参数必须是字节
v = obj.hexdigest() # 获取密文
print(v) # 21232f297a57a5a743894a0e4a801fc3
obj1 = hashlib.md5(SALT) # 先实例化一个对象 这波加盐 防止撞库被发现密码 传一个盐进去 这个盐必须是字节码
obj1.update("admin".encode("utf-8")) # 想对谁加密,就把参数传进去 在python3.5中,这个参数必须是字节码
v = obj1.hexdigest() # 获取密文
print(v) # 21232f297a57a5a743894a0e4a801fc3
3.15 日志 logging
为什么要有日志 -- 给开发人员看,用于排查错误
# 日志级别
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
import logging
logging.basicConfig(
filename="log.log",
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
# asctime 什么时候出的错
# name 模块名
datefmt="%Y-%m-%d %H:%M:%S %p",
level=10 # 日志级别 大于等于的时候10
)
logging.debug("debug") # 测试时候的日志
logging.info("info") # 正常的信息
logging.warning("warning") # 警告 能用
logging.error("error") # 报错
logging.critical("critical") # 非常严重错误
logging.log(10, "loggg")
import logging
logging.basicConfig(
filename="log.log",
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
# asctime 什么时候出的错
# name 模块名
datefmt="%Y-%m-%d %H:%M:%S %p",
level=10 # 日志级别 大于等于的时候10
)
# logging.debug("debug") # 测试时候的日志
# logging.info("info") # 正常的信息
# logging.warning("warning") # 警告 能用
# logging.error("error") # 报错
# logging.critical("critical") # 非常严重错误
# logging.log(10, "loggg")
def func():
try:
a = a + 1
except Exception as e:
logging.error(str(e))
func()
牛逼的来啦:
import logging
import traceback
logging.basicConfig(
filename="log.log",
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
# asctime 什么时候出的错
# name 模块名
datefmt="%Y-%m-%d %H:%M:%S %p",
level=10 # 日志级别 大于等于的时候10
)
# logging.debug("debug") # 测试时候的日志
# logging.info("info") # 正常的信息
# logging.warning("warning") # 警告 能用
# logging.error("error") # 报错
# logging.critical("critical") # 非常严重错误
# logging.log(10, "loggg")
def func():
try:
a = a + 1
except Exception as e:
# 获取当前错误的堆栈信息
msg = traceback.format_exc()
logging.error(msg)
func()
关于日志的个数:只能有一个 -- 利用logging.basicConfig
的时候。
如果要写多个日志:自定义日志
import logging
file_handler_obj = logging.FileHandler("log1.log", 'a', encoding='utf-8')
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s")
file_handler_obj.setFormatter(fmt)
logger1 = logging.Logger("s1", level=logging.ERROR)
logger1.addHandler(file_handler_obj)
logger1.error("logger1 error")
file_handler_obj = logging.FileHandler("log2.log", 'a', encoding='utf-8')
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s")
file_handler_obj.setFormatter(fmt)
logger2 = logging.Logger("s1", level=logging.WARNING)
logger2.addHandler(file_handler_obj)
logger2.warning("logger2 warning")
下面要讲解:
- 面向对象多继承
- 网络基础
- 网络相关的程序
3.16 面向对象多继承之c3
算法
3.16.1 c3
算法
- 先找左边,再找右边
-
经典类和新式类:
-
区别:查找顺序不一样
-
python 2.2+
:- 经典类: 一条道走到黑(深度优先搜索) -- 先找左边,再找右边
- 新式类:如果自己活着自己的前辈只要有人继承
object
,那就是新式类。 并不是广度优先. 通过C3
算法找.
-
python 3
:全部都是新式类 -- 和python2
的新式类一样class A(object): pass class B(A): pass class C(B): pass class D(object): pass class E(D, C): pass class F(object): pass class G(F): pass class H(C, G): pass class Foo(E, H): pass obj = Foo() print(E.__mro__) print(H.__mro__) print(Foo.__mro__) """ L(Foo + L(E) + L(H)) L(E) = (D, object) + (C, B, A, object) E 找出 并取出第一个元组的表头(D)和后面的元组 **除了表头** (C)以外的类名做比较, 如果D!=B、A、object中的任意一个,那么就将这第一个元组的表头拿出来 得到 E D L(E) = (object) + (C, B, A, object) 再去取第一个表的表头(object),发现在后面的表(除了表头以外的其他所有表)中能找到,于是就放着. 这时候去取下一个表的表头(C),找除这个表头所在表以外的所有表,没找到,所以把C取出来. 得到 E D C 再从第一个表里面开始找(每次都是从最开始的第一个表里面去找) 是object,其他表里面有,不管他,从下一个表里面找, B A 依次按照上述方式寻找 得到 E D C B A 于是最后只剩下object,拿出来 得到 E D C B A object ==> 所以E的继承关系为: E D C B A object 同理,H的继承关系为: ==> H C B A G F object 于是Foo的继承关系为: L(E D C B A object) + L(H C B A G F object) ==> Foo E D H C B A G F object 如果第一个表头的元素 在 其他的表里(除了表头以外)能够找到,那么就先跳过第一个表的这个表头元素转去判断下一个表的表头元素是否能够 在其他的表中找到(不判断表头元素.) """
-
一般情况下不会出现很复杂的继承关系,一旦出现较为复杂的继承关系,也能够使用C3
算法找出来继承关系.
总结:c3
算法
Foo + (B, C, D, E, G) + (I, G, D, G, W) + (I, G, D, G, W)
Foo,
(先找自己)- 拿第一个表的表头,和其他表的除了表头以外的元素(表尾)做比较
- 不存在: 直接拿出来,写在继承顺序的后面,表明这是一个已经寻找出来的继承关系
- 存在: 放弃他,不管了,从第二个表的表头再次和其他表的表尾进行对比
- 拿第一个表的表头,和其他表的除了表头以外的元素(表尾)做比较
注意每次都是从第一个表开始寻找.
-- c3
算法的更详细信息从python
官方文档里面找到: python 2.3
更新时写上了.
3.16.2 简单的继承关系
简单的继承关系
3.16.3 补充
[!Caution]
super
是遵循了__mro__
执行顺序 -- 只有python
中有