面向对象
面向对象基础
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()
小结:
- 执行对象.方法时,优先去当前对象所关联的类中找,没有的话才去她的父类中查找。
- 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,经典类
面向对象进阶
1.成员
面向对象中的所有成员如下:
- 变量
- 实例变量
- 类变量
- 方法
- 绑定方法
- 类方法
- 静态方法
- 属性
通过面向对象进行编程时,会遇到很多种情况,也会使用不同的成员来实现,接下来我们来逐一介绍成员特性和应用场景。
1.1 变量
- 实例变量,属于对象,每个对象中各自维护自己的数据。
- 类变量,属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。

class Person(object):
country = "中国"
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
# message = "{}-{}-{}".format(Person.country, self.name, self.age)
message = "{}-{}-{}".format(self.country, self.name, self.age)
print(message)
print(Person.country) # 中国
p1 = Person("武沛齐",20)
print(p1.name)
print(p1.age)
print(p1.country) # 中国
p1.show() # 中国-武沛齐-20
提示:当把每个对象中都存在的相同的示例变量时,可以选择把它放在类变量中,这样就可以避免对象中维护多个相同数据。
易错点 & 面试题
第一题:注意读和写的区别。

class Person(object):
country = "中国"
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
message = "{}-{}-{}".format(self.country, self.name, self.age)
print(message)
print(Person.country) # 中国
p1 = Person("武沛齐",20)
print(p1.name) # 武沛齐
print(p1.age) # 20
print(p1.country) # 中国
p1.show() # 中国-武沛齐-20
p1.name = "root" # 在对象p1中讲name重置为root
p1.num = 19 # 在对象p1中新增实例变量 num=19
p1.country = "china" # 在对象p1中新增实例变量 country="china"
print(p1.country) # china
print(Person.country) # 中国
class Person(object):
country = "中国"
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
message = "{}-{}-{}".format(self.country, self.name, self.age)
print(message)
print(Person.country) # 中国
Person.country = "美国"
p1 = Person("武沛齐",20)
print(p1.name) # 武沛齐
print(p1.age) # 20
print(p1.country) # 美国
第二题:继承关系中的读写

class Base(object):
country = "中国"
class Person(Base):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
message = "{}-{}-{}".format(Person.country, self.name, self.age)
# message = "{}-{}-{}".format(self.country, self.name, self.age)
print(message)
# 读
print(Base.country) # 中国
print(Person.country) # 中国
obj = Person("武沛齐",19)
print(obj.country) # 中国
# 写
Base.country = "china"
Person.country = "泰国"
obj.country = "日本"
面试题
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x) # 1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1
Parent.x = 3
print(Parent.x, Child1.x, Child2.x) # 3 2 3
1.2 方法
- 绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】
- 类方法,默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】
- 静态方法,无默认参数,用类和对象都可以调用。【对象&类均可调用】

class Foo(object):
def __init__(self, name,age):
self.name = name
self.age = age
def f1(self):
print("绑定方法", self.name)
@classmethod
def f2(cls):
print("类方法", cls)
@staticmethod
def f3():
print("静态方法")
# 绑定方法(对象)
obj = Foo("武沛齐",20)
obj.f1() # Foo.f1(obj)
# 类方法
Foo.f2() # cls就是当前调用这个方法的类。(类)
obj.f2() # cls就是当前调用这个方法的对象的类。
# 静态方法
Foo.f3() # 类执行执行方法(类)
obj.f3() # 对象执行执行方法
在Python中比较灵活,方法都可以通过对象和类进行调用;而在java、c#等语言中,绑定方法只能由对象调用;类方法或静态方法只能由类调用。
import os
import requests
class Download(object):
def __init__(self, folder_path):
self.folder_path = folder_path
@staticmethod
def download_dou_yin():
# 下载抖音
res = requests.get('.....')
with open("xxx.mp4", mode='wb') as f:
f.write(res.content)
def download_dou_yin_2(self):
# 下载抖音
res = requests.get('.....')
path = os.path.join(self.folder_path, 'xxx.mp4')
with open(path, mode='wb') as f:
f.write(res.content)
obj = Download("video")
obj.download_dou_yin()
面试题:
在类中 @classmethod 和 @staticmethod 的作用?
1.3 属性
属性其实是由绑定方法 + 特殊装饰器 组合创造出来的,让我们以后在调用方法时可以不加括号,例如:
class Foo(object):
def __init__(self, name):
self.name = name
def f1(self):
return 123
@property
def f2(self):
return 123
obj = Foo("武沛齐")
v1 = obj.f1()
print(v1)
v2 = obj.f2
print(v2)
示例:以之前开发的分页的功能。
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)
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
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
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("请输入页码:")
pg_object = Pagination(page, 20)
page_data_list = user_list[ pg_object.start : pg_object.end ]
for item in page_data_list:
print(item)
其实,除了咱们写的示例意外,在很多模块和框架的源码中也有porperty的身影,例如:requests模块。
import requests
# 内部下载视频,并将下载好的数据分装到Response对象中。
res = requests.get(
url="https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg",
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"
}
)
# 去对象中获取text,其实需要读取原始文本字节并转换为字符串
res.text
关于属性的编写有两种方式:
-
方式一,基于装饰器
class C(object): @property def x(self): pass @x.setter def x(self, value): pass @x.deleter def x(self): pass obj = C() obj.x obj.x = 123 del obj.x -
方式二,基于定义变量
class C(object): def getx(self): pass def setx(self, value): pass def delx(self): pass x = property(getx, setx, delx, "I'm the 'x' property.") obj = C() obj.x obj.x = 123 del obj.x
Django源码一撇:
class WSGIRequest(HttpRequest):
def __init__(self, environ):
script_name = get_script_name(environ)
# If PATH_INFO is empty (e.g. accessing the SCRIPT_NAME URL without a
# trailing slash), operate as if '/' was requested.
path_info = get_path_info(environ) or '/'
self.environ = environ
self.path_info = path_info
# be careful to only replace the first slash in the path because of
# http://test/something and http://test//something being different as
# stated in https://www.ietf.org/rfc/rfc2396.txt
self.path = '%s/%s' % (script_name.rstrip('/'),
path_info.replace('/', '', 1))
self.META = environ
self.META['PATH_INFO'] = path_info
self.META['SCRIPT_NAME'] = script_name
self.method = environ['REQUEST_METHOD'].upper()
# Set content_type, content_params, and encoding.
self._set_content_type_params(environ)
try:
content_length = int(environ.get('CONTENT_LENGTH'))
except (ValueError, TypeError):
content_length = 0
self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
self._read_started = False
self.resolver_match = None
def _get_scheme(self):
return self.environ.get('wsgi.url_scheme')
def _get_post(self):
if not hasattr(self, '_post'):
self._load_post_and_files()
return self._post
def _set_post(self, post):
self._post = post
@property
def FILES(self):
if not hasattr(self, '_files'):
self._load_post_and_files()
return self._files
POST = property(_get_post, _set_post)
写在最后,对属性进行一个补充:
由于属性和实例变量的调用方式相同,所以在编写时需要注意:属性名称 不要 实例变量 重名。
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
@property
def func(self):
return 123
obj = Foo("武沛齐", 123)
print(obj.name)
print(obj.func)
一旦重名,可能就会有报错。
class Foo(object):
def __init__(self, name, age):
self.name = name # 报错,错认为你想要调用 @name.setter 装饰的方法。
self.age = age
@property
def name(self):
return "{}-{}".format(self.name, self.age)
obj = Foo("武沛齐", 123)
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
@property
def name(self):
return "{}-{}".format(self.name, self.age) # 报错,循环调用自己(直到层级太深报错)
@name.setter
def name(self, value):
print(value)
obj = Foo("武沛齐", 123)
print(obj.name)
如果真的想要在名称上创建一些关系,可以让实例变量加上一个下划线。
class Foo(object):
def __init__(self, name, age):
self._name = name
self.age = age
@property
def name(self):
return "{}-{}".format(self._name, self.age)
obj = Foo("武沛齐", 123)
print(obj._name)
print(obj.name)
2.成员修饰符
Python中成员的修饰符就是指的是:公有、私有。
- 公有,在任何地方都可以调用这个成员。
- 私有,只有在类的内部才可以调用改成员(成员是以两个下划线开头,则表示该成员为私有)。
示例一:
class Foo(object):
def __init__(self, name, age):
self.__name = name
self.age = age
def get_data(self):
return self.__name
def get_age(self):
return self.age
obj = Foo("武沛齐", 123)
# 公有成员
print(obj.age)
v1 = self.get_age()
print(v1)
# 私有成员
# print(obj.__name) # 错误,由于是私有成员,只能在类中进行使用。
v2 = obj.get_data()
print(v2)
示例2:
class Foo(object):
def get_age(self):
print("公有的get_age")
def __get_data(self):
print("私有的__get_data方法")
def proxy(self):
print("公有的proxy")
self.__get_data()
obj = Foo()
obj.get_age()
obj.proxy()
示例3:
class Foo(object):
@property
def __name(self):
print("公有的get_age")
@property
def proxy(self):
print("公有的proxy")
self.__name
return 1
obj = Foo()
v1 = obj.proxy
print(v1)
特别提醒:父类中的私有成员,子类无法继承。
class Base(object):
def __data(self):
print("base.__data")
def num(self):
print("base.num")
class Foo(Base):
def func(self):
self.num()
self.__data() # # 不允许执行父类中的私有方法
obj = Foo()
obj.func()
class Base(object):
def __data(self):
print("base.__data")
def num(self):
print("base.num")
self.__data() # 不允许执行父类中的私有方法
class Foo(Base):
def func(self):
self.num()
obj = Foo()
obj.func()
写在最后,按理说私有成员是无法被外部调用,但如果用一些特殊的语法也可以(Flask源码中有这种写法,大家写代码不推荐这样写)。
class Foo(object):
def __init__(self):
self.__num = 123
self.age = 19
def __msg(self):
print(1234)
obj = Foo()
print(obj.age)
print(obj._Foo__num)
obj._Foo__msg()
成员是否可以作为独立的功能暴露给外部,让外部调用并使用。
- 可以,公有。
- 不可以,内部其他放的一个辅助,私有。
3.对象嵌套
在基于面向对象进行编程时,对象之间可以存在各种各样的关系,例如:组合、关联、依赖等(Java中的称呼),用大白话来说就是各种嵌套。
下面我们就用示例来学习常见的嵌套的情景:
情景一:
class Student(object):
""" 学生类 """
def __init__(self, name, age):
self.name = name
self.age = age
def message(self):
data = "我是一名学生,我叫:{},我今年{}岁".format(self.name, self.age)
print(data)
s1 = Student("武沛齐", 19)
s2 = Student("Alex", 19)
s3 = Student("日天", 19)
class Classes(object):
""" 班级类 """
def __init__(self, title):
self.title = title
self.student_list = []
def add_student(self, stu_object):
self.student_list.append(stu_object)
def add_students(self, stu_object_list):
for stu in stu_object_list:
self.add_student(stu)
def show_members(self):
for item in self.student_list:
# print(item)
item.message()
c1 = Classes("三年二班")
c1.add_student(s1)
c1.add_students([s2, s3])
print(c1.title)
print(c1.student_list)
情景二:
class Student(object):
""" 学生类 """
def __init__(self, name, age, class_object):
self.name = name
self.age = age
self.class_object = class_object
def message(self):
data = "我是一名{}班的学生,我叫:{},我今年{}岁".format(self.class_object.title, self.name, self.age)
print(data)
class Classes(object):
""" 班级类 """
def __init__(self, title):
self.title = title
c1 = Classes("Python全栈")
c2 = Classes("Linux云计算")
user_object_list = [
Student("武沛齐", 19, c1),
Student("Alex", 19, c1),
Student("日天", 19, c2)
]
for obj in user_object_list:
print(obj.name,obj.age, obj.class_object.title)

情景三:
class Student(object):
""" 学生类 """
def __init__(self, name, age, class_object):
self.name = name
self.age = age
self.class_object = class_object
def message(self):
data = "我是一名{}班的学生,我叫:{},我今年{}岁".format(self.class_object.title, self.name, self.age)
print(data)
class Classes(object):
""" 班级类 """
def __init__(self, title, school_object):
self.title = title
self.school_object = school_object
class School(object):
""" 学校类 """
def __init__(self, name):
self.name = name
s1 = School("北京校区")
s2 = School("上海校区")
c1 = Classes("Python全栈", s1)
c2 = Classes("Linux云计算", s2)
user_object_list = [
Student("武沛齐", 19, c1),
Student("Alex", 19, c1),
Student("日天", 19, c2)
]
for obj in user_object_list:
print(obj.name, obj.class_object.title , obj.class_object.school_object.name)

4.特殊成员
在Python的类中存在一些特殊的方法,这些方法都是 __方法__ 格式,这种方法在内部均有特殊的含义,接下来我们来讲一些常见的特殊成员:
-
__init__,初始化方法class Foo(object): def __init__(self, name): self.name = name obj = Foo("武沛齐") -
__new__,构造方法class Foo(object): def __init__(self, name): print("第二步:初始化对象,在空对象中创建数据") self.name = name def __new__(cls, *args, **kwargs): print("第一步:先创建空对象并返回") return object.__new__(cls) obj = Foo("武沛齐") -
__call__class Foo(object): def __call__(self, *args, **kwargs): print("执行call方法") obj = Foo() obj() -
__str__class Foo(object): def __str__(self): return "哈哈哈哈" obj = Foo() data = str(obj) print(data) -
__dict__class Foo(object): def __init__(self, name, age): self.name = name self.age = age obj = Foo("武沛齐",19) print(obj.__dict__) -
__getitem__、__setitem__、__delitem__class Foo(object): def __getitem__(self, item): pass def __setitem__(self, key, value): pass def __delitem__(self, key): pass obj = Foo("武沛齐", 19) obj["x1"] # 自动触发__getitem__ obj['x2'] = 123 # 自动触发__setitem__ del obj['x3'] # 自动触发__delitem__ -
__enter__、__exit__class Foo(object): def __enter__(self): print("进入了") return 666 def __exit__(self, exc_type, exc_val, exc_tb): print("出去了") obj = Foo() with obj as data: print(data)超前知识:数据连接,每次对远程的数据进行操作时候都必须经历。 1.连接 = 连接数据库 2.操作数据库 3.关闭连接class SqlHelper(object): def __enter__(self): self.连接 = 连接数据库 return 连接 def __exit__(self, exc_type, exc_val, exc_tb): self.连接.关闭 with SqlHelper() as 连接: 连接.操作.. with SqlHelper() as 连接: 连接.操作...# 面试题(补充代码,实现如下功能) class Context: def do_something(self): print('内部执行') with Context() as ctx: print('内部执行') ctx.do_something()上下文管理的语法。
-
__add__等。class Foo(object): def __init__(self, name): self.name = name def __add__(self, other): return "{}-{}".format(self.name, other.name) v1 = Foo("alex") v2 = Foo("sb") # 对象+值,内部会去执行 对象.__add__方法,并将+后面的值当做参数传递过去。 v3 = v1 + v2 print(v3) -
__iter__-
迭代器
# 迭代器类型的定义: 1.当类中定义了 __iter__ 和 __next__ 两个方法。 2.__iter__ 方法需要返回对象本身,即:self 3. __next__ 方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。 官方文档:https://docs.python.org/3/library/stdtypes.html#iterator-types # 创建 迭代器类型 : class IT(object): def __init__(self): self.counter = 0 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter # 根据类实例化创建一个迭代器对象: obj1 = IT() # v1 = obj1.__next__() # v2 = obj1.__next__() # v3 = obj1.__next__() # 抛出异常 v1 = next(obj1) # obj1.__next__() print(v1) v2 = next(obj1) print(v2) v3 = next(obj1) print(v3) obj2 = IT() for item in obj2: # 首先会执行迭代器对象的__iter__方法并获取返回值,一直去反复的执行 next(对象) print(item) 迭代器对象支持通过next取值,如果取值结束则自动抛出StopIteration。 for循环内部在循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的next取值(有异常StopIteration则终止循环)。 -
生成器
# 创建生成器函数 def func(): yield 1 yield 2 # 创建生成器对象(内部是根据生成器类generator创建的对象),生成器类的内部也声明了:__iter__、__next__ 方法。 obj1 = func() v1 = next(obj1) print(v1) v2 = next(obj1) print(v2) v3 = next(obj1) print(v3) obj2 = func() for item in obj2: print(item) 如果按照迭代器的规定来看,其实生成器类也是一种特殊的迭代器类(生成器也是一个中特殊的迭代器)。 -
可迭代对象
# 如果一个类中有__iter__方法且返回一个迭代器对象 ;则我们称以这个类创建的对象为可迭代对象。 class Foo(object): def __iter__(self): return 迭代器对象(生成器对象) obj = Foo() # obj是 可迭代对象。 # 可迭代对象是可以使用for来进行循环,在循环的内部其实是先执行 __iter__ 方法,获取其迭代器对象,然后再在内部执行这个迭代器对象的next功能,逐步取值。 for item in obj: passclass IT(object): def __init__(self): self.counter = 0 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter class Foo(object): def __iter__(self): return IT() obj = Foo() # 可迭代对象 for item in obj: # 循环可迭代对象时,内部先执行obj.__iter__并获取迭代器对象;不断地执行迭代器对象的next方法。 print(item)# 基于可迭代对象&迭代器实现:自定义range class IterRange(object): def __init__(self, num): self.num = num self.counter = -1 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == self.num: raise StopIteration() return self.counter class Xrange(object): def __init__(self, max_num): self.max_num = max_num def __iter__(self): return IterRange(self.max_num) obj = Xrange(100) for item in obj: print(item)class Foo(object): def __iter__(self): yield 1 yield 2 obj = Foo() for item in obj: print(item)# 基于可迭代对象&生成器 实现:自定义range class Xrange(object): def __init__(self, max_num): self.max_num = max_num def __iter__(self): counter = 0 while counter < self.max_num: yield counter counter += 1 obj = Xrange(100) for item in obj: print(item)常见的数据类型:
v1 = list([11,22,33,44]) v1是一个可迭代对象,因为在列表中声明了一个 __iter__ 方法并且返回一个迭代器对象。from collections.abc import Iterator, Iterable v1 = [11, 22, 33] print( isinstance(v1, Iterator) ) # false,判断是否是迭代器;判断依据是__iter__ 和 __next__。 v2 = v1.__iter__() print( isinstance(v2, Iterator) ) # True v1 = [11, 22, 33] print( isinstance(v1, Iterable) ) # True,判断依据是是否有 __iter__且返回迭代器对象。 v2 = v1.__iter__() print( isinstance(v2, Iterable) ) # True,判断依据是是否有 __iter__且返回迭代器对象。
-

浙公网安备 33010602011771号