Python面向对象编程
# ###### 定义类 ######
class 类名:
def 方法名(self,name):
print(name)
return 123
def 方法名(self,name):
print(name)
return 123
def 方法名(self,name):
print(name)
return 123
class 类名:
def 函数(self):
函数体
#
# ###### 调用类中的方法 ######
# 1.创建该类的对象
obj = 类名()
# 2.通过对象调用方法
result = obj.方法名('alex')
print(result)
应用场景:遇到很多函数,需要给函数进行归类和划分。 【封装】
练习题:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Db:
def db_read(self):
pass
def db_write(self):
pass
def db_delete(self):
pass
def db_update(self):
pass
class File:
def file_read(self):
pass
def file_write(self):
pass
def file_delete(self):
pass
def file_update(self):
pass
class Redis:
def redis_read(self):
pass
def redis_write(self):
pass
def redis_delete(self):
pass
def redis_update(self):
pass
几个使用:代码从上到下执行
1) print('你好') def func(): pass func() -------------结果: 你好
2) class Foo: X = 1 def func(self): pass Foo.X ---------结果:
3) class Foo: print('你好') #类里面第一层的成员在创建类的时候会执行 def func(self): pass ------------结果: 你好
4) class Foo: print('你') x = 1 def func(sef): pass class Meta: #类里面第一层的成员,比如方法func和类Meta都相当于类变量一样,类可以当做一个变量。类里面还可以定义类,创建这个类的时候它的第一层也会执行。 print('好') y = 123 def show(self): pass -------------结果: 你 好
4)直接传参进去可以调用
class mcw():
def func(self,name):
self.name=name
print(self.name)
obj=mcw()
obj.func("小马过河")
-----------结果:
小马过河
对象调用错误:
1)obj还是类。类.方法()会报错
class mcw():
def func(self):
print("mcw")
obj=mcw
obj.func()
----------结果:
TypeError: func() missing 1 required positional argument: 'self'
2.对象的作用
存储一些值,以后方便自己使用。
class File:
def read(self):
with open(self.xxxxx, mode='r', encoding='utf-8') as f:
data = f.read()
return data
def write(self, content):
with open(self.xxxxx, mode='a', encoding='utf-8') as f:
f.write(content)
# # 实例化了一个File类的对象
obj1 = File()
# # 在对象中写了一个xxxxx = 'test.log'
obj1.xxxxx = "test.log"
# # 通过对象调用类中的read方法,read方法中的self就是obj。
# # obj1.read()
obj1.write('alex')
# 实例化了一个File类的对象
obj2 = File()
# 在对象中写了一个xxxxx = 'test.log'
obj2.xxxxx = "info.txt"
# 通过对象调用类中的read方法,read方法中的self就是obj。
# obj2.read()
obj2.write('alex')
class Person:
def show(self):
temp = "我是%s,年龄:%s,性别:%s " %(self.name,self.age,self.gender,)
print(temp)
p1 = Person()
p1.name = '李邵奇'
p1.age = 19
p1.gender = '男'
p1.show()
p2 = Person()
p2.name = '利奇航'
p2.age = 19
p2.gender = '男'
p2.show()
class Person:
def __init__(self,n,a,g): # 初始化方法(构造方法),给对象的内部做初始化。
self.name = n
self.age = a
self.gender = g
def show(self):
temp = "我是%s,年龄:%s,性别:%s " % (self.name, self.age, self.gender,)
print(temp)
# 类() 实例化对象,自动执行此类中的 __init__方法。
p1 = Person('李兆琪',19,'男')
p1.show()
p2 = Person('利奇航',19,'男')
p2.show()
总结:将数据封装到对象,方便使用。
总结
"""
如果写代码时,函数比较多比较乱。
1. 可以将函数归类并放到同一个类中。
2. 函数如果有一个反复使用的公共值,则可以放到对象中。
"""
class File:
def __init__(self,path):
self.file_path = path
def read(self):
print(self.file_path)
def write(self,content):
print(self.file_path)
def delete(self):
print(self.file_path)
def update(self):
print(self.file_path)
p1 = File('log.txt')
p1.read()
p2 = File('xxxxxx.txt')
p2.read()
# 1. 循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。
# ########## 以前的写法
USER_LIST = []
while True:
user = input('请输入用户名:')
pwd = input('请输入密码:')
email = input('请输入邮箱:')
temp = {'username':user,'password':pwd,'email':email}
USER_LIST.append(temp)
for item in USER_LIST:
temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],)
print(temp)
# ########## 面向对象写法
class Person:
def __init__(self,user,pwd,email):
self.username = user
self.password = pwd
self.email = email
USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
user = input('请输入用户名:')
pwd = input('请输入密码:')
email = input('请输入邮箱:')
p = Person(user,pwd,email)
USER_LIST.append(p)
for item in USER_LIST:
temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
print(temp)
# ########## 面向对象写法
class Person:
def __init__(self,user,pwd,email):
self.username = user
self.password = pwd
self.email = email
def info(self):
return "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
user = input('请输入用户名:')
pwd = input('请输入密码:')
email = input('请输入邮箱:')
p = Person(user,pwd,email)
USER_LIST.append(p)
for item in USER_LIST:
msg = item.info()
print(msg)
3.游戏开发
class Police:
def __init__(self,name)
self.name = name
self.hp = 10000
def tax(self):
msg = "%s收了个税。" %(self.name,)
print(msg)
def fight(self):
msg = "%s去战了个斗。" %(self.name,)
lsq = Police('李邵奇')
zzh = Police('渣渣会')
tyg = Police('堂有光')
class Bandit:
def __init__(self,nickname)
self.nickname = nickname
self.hp = 1000
def murder(self,name):
msg = "%s去谋杀了%s" %(self.nickname, name,)
lcj = Bandit('二蛋')
lp = Bandit('二狗')
zsd = Bandit('狗蛋')
# 1. 二狗去谋杀渣渣会,二狗生命值-100; 渣渣会生命值减5000
lp.murder(zzh.name)
lp.hp = lp.hp - 100
zzh.hp = zzh.hp - 5000
# ...
class Police:
def __init__(self,name)
self.name = name
self.hp = 10000
def dao(self,other):
msg = "%s个了%s一刀。" %(self.name,other.nickname)
self.hp = self.hp - 10
other.hp = other.hp - 50
print(msg)
def qiang(self):
msg = "%s去战了个斗。" %(self.name,)
def quan(self,other):
msg = "%s个了%s一全。" %(self.name,other.nickname)
self.hp = self.hp - 2
other.hp = other.hp - 10
print(msg)
class Bandit:
def __init__(self,nickname)
self.nickname = nickname
self.hp = 1000
def qiang(self,other):
msg = "%s个了%s一全。" %(self.nickname,other.name)
self.hp -= 20
other.hp -= 500
lcj = Bandit('二蛋')
lsq = Police('李邵奇')
lsq.dao(lcj)
lsq.quan(lcj)
lcj.qiang(lsq)
4.继承
# 父类(基类)
class Base:
def f1(self):
pass
# 子类(派生类)
class Foo(Base):
def f2(self):
pass
# 创建了一个字类的对象
obj = Foo()
# 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。
obj.f2()
obj.f1()
# 创建了一个父类的对象
obj = Base()
obj.f1()
问题:什么时候才能用到继承?多个类中如果有公共的方法,可以放到基类中避免重复编写。
class Base:
def f1(self):
pass
class Foo(Base):
def f2(self):
pass
class Bar(Base):
def f3(self):
pass
obj1 = Foo()
obj2 = Bar()
继承关系中的查找方法的顺序:
# 示例一
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):
self.f1()
print('foo.f2')
obj = Foo()
obj.f2()
# 示例三
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
self.f1()
print('foo.f2')
def f1(self):
print('foo.f1')
obj = Foo()
obj.f2()
# 示例四
class Base:
def f1(self):
self.f2()
print('base.f1')
def f2(self):
print('base.f2')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f1()
# 示例五
class TCPServer:
pass
class ThreadingMixIn:
pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
# 示例六
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()
注意事项:
-
self 到底是谁?
-
self 是哪个类创建的,就从此类开始找,自己没有就找父类。
5.多态(多种形态/多种类型)鸭子模型
# Python
def func(arg):
v = arg[-1] # arg.append(9)
print(v)
# java
def func(str arg):
v = arg[-1]
print(v)
面试题:什么是鸭子模型。
对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法)。 这就是鸭子模型,类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们要想的类型)
总结
-
面向对象的三大特性:封装/继承/多态
-
封装
class File: def read(self): pass def write(self): passclass Person: def __init__(sef,name,age): self.name = name self.age = age p = Person('alex',19) -
继承
class Base: pass class Foo(Base): pass-
多继承
-
self到底是谁?
-
self是由于那个类创建,则找方法时候就从他开始找。
-
-
多态
def func(arg): # 多种类型,很多事物 arg.send() # 必须具有send方法,呱呱叫
-
-
格式和关键词
class 类: def __init__(self,x): self.x = x def 方法(self,name): print(self.x, name) # 实例化一个类的对象 v1 = 类(666) v2.方法('alex')三个词:
-
类
-
对象
-
方法
-
-
什么时候用面向对象?
-
函数(业务功能)比较多,可以使用面向对象来进行归类。
-
想要做数据封装(创建字典存储数据时,面向对象)。
-
游戏示例:创建一些角色并且根据角色需要再创建人物。
-
-
类的成员
class Request:
def __init__(self,a1,a2):
self.a1 = a1
self.a2 = a2
def func(arg):
print(arg.a1,arg.a2)
obj = Request(1,2) #实例化一个类,把对象的数据封装到类,以供下次使用
func(obj) #封装数据到对象,将对象以函数的参数形式传进函数,在函数中可以调用类变量
--------------结果:
1 2
2)类变量
class Foo:
city = '北京' #在类的内存空间里面创建变量。
def __init__(self, name): #方法是Foo类中成员。包括init方法
self.name = name
def func(self): #
pass
obj1 = Foo('小马过河') #类加括号创建对象,开辟内存,并且与类的地址有联系,执行init,初始化之后,在对象内存中赋值了。
obj2 = Foo('小郭吹雪') #对象和类的内存是两个
print(obj1.name) #外部访问类中init里的变量 :类.类变量(注意:类.init的变量是错的) 对象.变量(类变量,init里的变量都可以)
print(obj2.name)
print(Foo.city) #按理说对象取类中变量应该是类.类变量。python比较灵活,可以直接对象.类变量(对象内存中没找到类变量,去类空间中找到。)
print(obj1.city) #创建一个对象之后,创建对象内存空间。如果取一个变量,没有的话可以去类中定义的变量去取(类的内存空间中定义的变量)。java不可以这样
print(obj2.city) #所以Python访问类变量的方法有两种。假如对象里面有自己的同名变量,那么对象.变量先用自己的,没有才去类的内存空间中找这个变量
--------------结果:
小马过河
小郭吹雪
北京
北京
北京
#类变量。在类的内存空间里面创建变量。创建一个对象之后,如果取一个变量,没有的话可以去类中定义的变量去取。java不可以这样。按理说对象取类中变量应该是类.类变量。python比较灵活,可以直接对象.类变量。所以Python访问类变量的方法有两种。假如对象里面有自己的同名变量,那么对象.变量先用自己的,没有才去类的内存空间中找这个变量
3)
class Base:
x = 1
obj = Base() #类的空间和对象的空间不是同一个
print(obj.x) # obj使用变量x先去obj对象中找,没有再去类中找。
obj.y = 123 # 在obj对象中添加了一个y=123的变量。
print(obj.y)
obj.x = 123 #在对象obj里定义一个变量x=123,
print(obj.x) #obj里面有x,123,
print(Base.x) #Base里面有x,1
4)
class Parent:
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x) # 1 1 1
#P里的x是1;C1找x,没有找到就去基类P中去找x=1;C2找x,没有找到就去基类P中去找,
Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1
#P里的x是1;C1找x,x已经定义,x = 2;C2找x,没有找到就去基类P中去找,x=1,
Child2.x = 3
print(Parent.x, Child1.x, Child2.x) # 1 2 3
#P里的x是1;C1找x,x已经定义,x = 2;C2找x,x已经定义,x = 3
总结:找变量优先找自己,自己没有找 类 或 基类;修改或赋值只能在自己的内部设置。
1.3 方法(绑定方法/普通方法)
-
定义:至少有一个self参数
-
执行:先创建对象,由对象.方法()。
class Foo:
def func(self, a, b):
print(a, b)
obj = Foo()
obj.func(1, 2)
# ###########################
class Foo:
def __init__(self):
self.name = 123 #绑定方法: self代表对象
def func(self, a, b):#对象成员: 实例变量(即对象的变量name=123),obj创建后初始化类(执行init时在obj中创建)时被赋予的变量值
print(self.name, a, b)
obj = Foo() #实例化一个类,类.方法,传参1,2
obj.func(1, 2)
---------------结果:
1 2
123 1 2
4 静态方法
-
定义:
-
@staticmethod装饰器
-
参数无限制
-
-
执行:
-
类.静态方法名 ()
-
对象.静态方法() (不推荐)
-
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
@staticmethod #静态方法.方法前面加@静态方法 它是python内置装饰器
def f1(): #静态方法参数无限制,如果有形参也是需要传参的,否则报错。
print(123)
obj = Foo()
obj.func(1, 2)
Foo.f1() #静态方法执行直接类.方法()。
obj.f1() # 静态方法执行也可以:对象.静态方法 ,但是容易混淆,没有意义。java不可以使用对象调用静态方法
-------------结果:
123 1 2
123
123
#使用场景:封装数据用绑定方法,不用封装数据就用静态方法。如果只调用静态方法那么就不用创建对象了。类.方法
面试题: 在对象中赋值 对象.变量=值 在类中赋值 类.变量=值
继承,子类没有的类变量,可以去父类里面中。子类中赋值同名变量后,不会修改父类中的变量,而是在自己的空间里创建一个,调用的时候去自己空间去找,不再去父类中去找。别人的可以读到,但是不可以修改 p8规范:类前空两行 方法间空一行
1.5 类方法
-
定义:
-
@classmethod装饰器
-
至少有cls参数,当前类。
-
-
执行:
-
类.类方法()
-
对象.类方法() (不推荐)
-
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
@staticmethod #静态方法.方法前面加@静态方法 它是python内置装饰器
def f1():
print(123)
@classmethod #定义方法:方法前面加一个@类方法,至少一个参数cls,cls代表当前的类。
def f2(cls,a,b):
print('cls是当前类',cls)
print(a,b)
obj = Foo()
obj.func(1, 2)
Foo.f1() #静态方法执行直接类.方法()。
Foo.f2(1,2)#类方法的执行:类名.方法(类方法的执行也可以是:对象.方法调用,但是不建议使用)
----------结果:
123 1 2
123
cls是当前类 <class '__main__.Foo'>
1 2
-
# 问题: @classmethod和@staticmethod的区别?
"""
一个是类方法一个静态方法。
定义:
类方法:用@classmethod做装饰器且至少有一个cls参数。
静态方法:用staticmethod做装饰器且参数无限制。
调用:
类.方法直接调用。
对象.方法也可以调用。 -
使用场景:在类中用到当前的类名的时候使用类方法。 (类方法用静态方法也能实现,传递一个值,类名也可以实现)
1.6 属性
-
定义:
-
@property装饰器
-
只有一个self参数
-
-
执行:
-
对象.方法 不用加括号。
-
class Foo:
@property #@property 在除了self没有其它参数的方法前面加,由方法变成属性
def func(self): #属性:(方法变异过来的)
print(123)
return 666
obj = Foo()
result = obj.func #属性执行的时候就不用加括号了(其它方法执行的时候都是加括号才执行的,不加括号代表的是方法)
print(result)
-------------结果:
123
666
-
应用场景:分页功能,记录索引位置 (就是免去不需要传参的方法的括号)
# 属性的应用
class Page:
def __init__(self, total_count, current_page, per_page_count=10): #给每页显示的数量给个默认值10个
self.total_count = total_count #将总页数,每页显示的数,当前第几页以变量传参进来
self.per_page_count = per_page_count
self.current_page = current_page
@property #@property 在除了self没有其它参数的方法前面加,由方法变成属性
def start_index(self): #这样属性执行的时候就不用加括号了
return (self.current_page - 1) * self.per_page_count
@property #@property 在除了self没有其它参数的方法前面加,由方法变成属性
def end_index(self):
return self.current_page * self.per_page_count
USER_LIST = [] #创建空列表,并加加入321个列表元素,作为分页展示的条目
for i in range(321):
USER_LIST.append('小马过河-%s' % (i,))
# 请实现分页展示:
current_page = int(input('请输入要查看的页码:')) #接收参数,当前页是用户输入要查看的第几页
p = Page(321, current_page) #实例化一个对象,将用户输入的第几页的数据封装起来,以供后面使用
data_list = USER_LIST[p.start_index:p.end_index] #对象.start_index是对象执行类的属性,也代表属性的返回值,返回值是用户输入的页数-1再乘以每页显示的数,表示开始的索引
for item in data_list: #获取到第几页的元素列表,逐个打印
print(item)
-------------------结果:
请输入要查看的页码:1
小马过河-0
小马过河-1
小马过河-2
小马过河-3
小马过河-4
小马过河-5
小马过河-6
小马过河-7
小马过河-8
小马过河-9
2.成员修饰符
-
公有,所有地方都能访问到。
-
私有,只有自己可以访问到。
1)
class Foo:
def __init__(self, name):
self.__name = name #在init中定义变量是公有的,内部访问self.变量,外部访问对象.变量,先用对象自己空间内的,没有才去类的内存空间中找这个变量
def func(self): #变量变成私有的:__变量 。
print(self.__name) #变成私有的后,内部可以访问self.__变量,外部无法访问,不可以对象.__变量会报错
obj = Foo('小马过河')
#print(obj.__name) #类外部和它的子类都不能访问,访问报错AttributeError: 'Foo' object has no attribute '__name'
obj.func() #外部访问类中init里的变量 :类.变量 对象.变量
-----------结果:
小马过河
2)同过访问类中别的函数或变量等来访问类中的私有变量(有什么使用场景呢)
class Foo:
__x = 1 #公有变量变成私有变量后(这里的是个类变量),只能这个类中使用这个变量,
@staticmethod
def func(): #如果想在类这个类之外使用这个变量,那么可以在类中定义一个方法,方法里可以使用这个变量,在类外部通过使用这个方法而使用这个变量
print(Foo.__x) #这个方法有点像走后门用的
# print(Foo.__x) #类外部和它的子类都不能访问,访问报错 #变成私有之后,子类也不可以访问。(只能自己知道,其它类都不可以知道的)
Foo.func()
------------结果:
1
3)同过访问类中别的函数或变量等来访问类中的私有函数
class Foo:
def __fun(self): #变成私有之后,子类也不可以访问。(只能自己知道,其它类都不可以知道的)
print('msg')
def show(self):
self.__fun() #外部调用类中私有方法,可以调用在这个类中调用这个私有方法的公有方法
obj = Foo()
# obj.__fun()#类外部和它的子类都不能访问,访问报错
obj.show()
-------------结果:
msg
-
类外部强制访问私有成员方法:对象._类名私有对象变量。例如(obj. _ Foo __x)(对象. _类名 _ _变量)
# 强制访问私有成员
class Foo:
def __init__(self,name):
self.__x = name
obj = Foo('小马过河')
print(obj._Foo__x) # 强制访问私有实例变量
---------------结果:
小马过河
3.补充用法
1)将类添加进列表,循环类加括号变对象(有参的需要传参)
class Foo:
def __init__(self, num): #定义只有init接收变量的类
self.num = num
cls_list = []
for i in range(5):
cls_list.append(Foo) #将同一个类名多次追加到列表
for i in range(len(cls_list)):
obj = cls_list[i](i) #用列表中的每个类创建对象并传参。cls_list[i]是索引为i的类,cls_list[i](i)第二个i是创建对象并传参为i
print(obj.num) #循环打印对象中封装的变量num
-----------结果:
0
1
2
3
4
2)类可以取别名,用其它变量代指类
class Foo:
def __init__(self, num):
self.num = num
B = Foo
obj = B('小马过河')
print(obj.num)
-----------结果:
小马过河
3)在类外部,实例化对象并将对象的方法放到列表字典等,循环取值加括号执行(什么场景适合用呢)
class Foo:
def f1(self):
print('f1')
def f2(self):
print('f2')
obj = Foo()
v = [ obj.f1,obj.f2 ]
for item in v:
item()
-------------结果:
f1
f2
4)类中定义方法c,用来批量执行类中的方法a、b。使用这个类的时候外部只需创建对象并执行
class Account:
def login(self):
pass
def register(self):
pass
def run(self):
info = {'1':self.register, '2':self.login }
choice = input('请选择:')
if info.get(choice):
method()
if __name__=="__main__"
obj=Account()
obj.run
#在方法中,将对象的方法放到列表字典等(在类中,实现方法调用方法。实例化的每个对象执行一个方法时,也能调用其它方法。就是对象执行类中的运行其它方法的方法),循环取值加括号执行 ,然后外部实例化 ,....登录的run就是利用这个原理
类方法都可以当变量
5)新式类和经典类
class Foo:
pass
class Foo(object):
pass
# 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。
# 如果在python2中这样定义,则称其为:经典类 #影响的是继承顺序
class Foo:
pass
# 如果在python2中这样定义,则称其为:新式类
class Foo(object):
pass
class Base(object):
pass
class Bar(Base):
pass
6)将其它类的对象作为参数传进另一个类中 #对象和对象之间嵌套,复制一下,(联表查询似的)
class School(object):
def __init__(self, title, addr):
self.title = title
self.address = addr
class ClassRoom(object):
def __init__(self, name, school_object):
self.name = name
self.school = school_object
s1 = School('校区一', '北京')
s2 = School('校区二', '保定')
c1 = ClassRoom('工商管理1班', s1) #对象和对象之间嵌套
print(c1.name,c1.school.title,c1.school.address)
-----------------结果:
工商管理1班 校区一 北京
类成员:类变量 ,绑定方法,静态方法,类方法 (对象可以调用所有方法,#?类也可以调用所有方法吧) 对象成员:实例变量
===========小补充 数据类型之间可以嵌套,数据类型是类,那么类可以嵌套?某个数据类型的元素是另一个数据类型,那么某个类中的元素可以是另一个类?
#思考:什么时候用静态 类方法 ,什么时候用私有成员?
1、学生一个类,课程一个类。班级一个类。数据封装
类的嵌套特殊成员
##
-
嵌套
-
-
type/isinstance/issubclass/super
-
异常处理
-
谈谈你了解的面向对象? 从三个特性说起
-
类和对象是什么关系?对象是类的一个实例。
class Foo:
def __init__(self,name):
self.name = name
def run(self):
pass
obj1 = Foo('ale')
obj2 = Foo('eric') -
self是什么?
# self就是一个形式参数,对象调用方法时,python内部会将该对象传给这个参数。
class Foo:
def run(self,num):
pass
obj = Foo()
obj.run(5) -
类成员 & 对象成员 以及他们之间的关系。
class Foo:
name = 'alex'
def run(self):
pass
obj = Foo() -
类/方法/对象 都可以当作变量或嵌套到其他类型中。
class Foo:
def run(self):
pass
v = [Foo,Foo] #列表里面放多个同一个类
v = [Foo(),Foo()]# 列表里面可以放多个类+(),即放多个类的实例
obj = Foo()
v = [obj.run,obj.run,obj.run] #实例化一个对象,列表里面可以放多个对象的方法,这里不加括号执行
#多个同一个类,多个类的实例,多个对象的方法也可以放到别的数据类型的吧,比如字典。
#思考使用场景:当多次要使用同一个类的时候,可以构造一个类的列表;当多次要使用一个类的多个对象的时候,那么可以构造成列表;当多次要使用某个对象的同一个方法的时候,也可以构造成列表。当然不用嵌套在列表里面也一样可以实现功能的。
class School(object):
def __init__(self, title):
self.title = title
class Course(object):
def __init__(self, name, school_object):
self.name = name
self.school = school_object
class Classes(object):
def __init__(self, cname, course_object):
self.cname = cname
self.course = course_object
s1 = School('北京') #School的一个对象,.title是北京
c1 = Course('Python',s1) #Course的一个对象,.name是Python,.school是s1对象,内封装s1的变量title北京。想使用北京,可以print(c1.school.title)
c2 = Course('Go',s1) ##Course的第二个对象,.name是go,.school是s1对象,内封装s1的变量title北京。想使用北京,可以print(c2.school.title)
cl1 = Classes('全栈1期',c1)#Classes的一个对象,cname是全栈1期,c1是对象。cl1中封装了Course和School的两个对象的数据。可以进行调用
print(cl1.cname,cl1.course.name,cl1.course.school.title)
# ---------------结果:
# 全栈1期 Python 北京
#在对象cl1中调用另外两个类的对象中封装的数据。 cl1.cname是Classes中的self.cname,cl1.course是类Classes中的传参course_object即c1对象。
#cl1.course.name是c1对象中的self.name = "Python" ,cl1.course.school是类Course的对象c1中的self.school = s1这个对象。s1有title,cl1.course.school
# 是s1,s1有title北京,所以cl1.course.school.title是对象cl1使用到其它对象中封装的元素。这里就是类的嵌套。
#思考:这里将北京封装到了类School的一个对象,对象可以取出学校名;传参将Python封装到了类Course的对象c1,将学校封装到了类Course的对象c1,而学校传参是对象s1,于是c1中可以
# 取出s1中的学校名;传参将全栈1期封装到了类 Classes的对象cl1,将能取出课程名字和学校名字的对象c1传参入对象cl1中,cl1.course就代表c1对象。
class School(object):
def __init__(self,title):
self.title = title
def rename(self,new_title):
self.title=new_title
class Course(object):
def __init__(self,name,school_object):
self.name = name
self.school = school_object
def reset_price(self):
pass
class Classes(object):
def __init__(self,cname,course_object):
self.cname = cname
self.course = course_object
def shangke(self):
print(self.course.school.title)
s1 = School('北京')
c1 = Course('Python',s1)
c2 = Course('Go',s1)
cl1 = Classes('全栈1期',c1)
print(cl1.shangke())
#通过cl1执行Classes类中shangke方法,self.course是c1,self.course.school是c1.school(即s1)self.course.school.title是s1.title即北京
#cl1.shangke()会执行方法在shangke中打印北京,cl1.shangke()对象的cl1.shangke方法的返回值,默认为None,打印了一下是None
# ---------结果:
# 北京
# None
cl1.course.school.rename("小马过河学校")
print(cl1.course.school.title)
--------结果:
小马过河学校
#想要在cl1中执行School是北京的rename方法,那么先要找到cl1有关联的School的对象。
#先看cl1传参中有c1,c1传参中有s1,s1是School的对象,由此定位到School的对象,就可以使用里面的方法了。
#要想参数类中嵌套其它的类的对象,就可以在这个类的init中设置一个形参,形参作为接收其它类的对象,在init中重新初始化,就可以在这个类中对另一个类的对象做操作了。
内容详细
1.嵌套
-
函数:参数可以是任意类型。
-
字典:对象和类都可以做字典的key和value。(少量代码实现很长的一个字典吗?可以生成嵌套字典吗?在生成键值对的那里变成生成字典,在加到字典 里,就可以用一个类生成字典嵌套字典了吧)
-
继承的查找关系
1)类中列表追加对象
在一个类中初始化一个空列表,在这个类中再创建一个方法,用以将执行这个方法传参进来的参数加入到这个列表中,这个参数如果是其他的类,那么就实现了类的嵌套,可以将多个类追加到这个列表里面
class StarkConfig(object):
def __init__(self,a):
self.name=a
class AdminSite(object):
def __init__(self):
self.data_list = []
def register(self, arg):
self.data_list.append(arg)
site = AdminSite() #创建AdminSite对象
obj = StarkConfig("小马过河")#创建StarkConfig对象
site.register(obj.name) #将对象obj里封装的name传给site变量中的register方法,将小马过河加进列表
print(site.data_list)
----------------结果:
["小马过河"]
2) 在一个类的init中设置一个变量初始值,创建一个方法将这个变量重新赋值为传参进来的参数。这个参数可以是一个类,这样,通过这个变量就可以对另一个类做操作了
class StarkConfig(object):
def __init__(self,name,age):
self.name = name
self.age = age
class AdminSite(object):
def __init__(self):
self.data_list = []
self.sk = None
def set_sk(self,arg):
self.sk = arg
site = AdminSite() # site是AdminSite对象,初始化 对象中的变量 data_list = [] sk = None
site.set_sk(StarkConfig) #对对象site做操作,执行set_sk方法,将类StarkConfig传进去,给site.sk重新赋值为StarkConfig这个类。
bb=site.sk('小马过河',18) #site.sk已经代表StarkConfig这个类,传参进入
print(bb.name,bb.age) #site.sk=StarkConfig,实例化一个对象bb,打印bb中的变量name,age。
-----------------结果:
小马过河 18
3)在一个类的init中创建空字典。在类中创建一个方法,方法传入两个参数,一个是键,一个是值,在方法中将键值对添加到字典中。每次执行这个类的方法就可以不断添加键值对进这个字典。值可以为类,这样就可以在这个类中使用那些类了。
class StackConfig(object):
pass
class Foo(object):
pass
class Base(object):
pass
class AdminSite(object):
def __init__(self):
self._register = {}
def registry(self,key,arg):
self._register[key] = arg
site = AdminSite() #创建一个 AdminSite的对象
site.registry(1,StackConfig) #对实例使用registry函数,第一个参数为键,第二个参数为值,赋值给init中的空字典,
site.registry(2,StackConfig) #每次执行这个方法,都会添加键值对到init中的那个_register字典中。
site.registry(3,StackConfig) #值可以为类,这样就可以在这个对象中对那个类做操作
site.registry(4,Foo) #值可以是多个类
site.registry(5,Base)
for k,v in site._register.items():
print(k,v() ) #k代表键,v代表类,加括号后是对象
------------------------结果:
1 <__main__.StackConfig object at 0x021548F0>
2 <__main__.StackConfig object at 0x021548F0>
3 <__main__.StackConfig object at 0x021548F0>
4 <__main__.Foo object at 0x021548F0>
5 <__main__.Base object at 0x021548F0>
4)在一个类中创建空字典,创建一个能不断给字典赋值的方法,创建一个能使用字典的方法。字典值可以为类,这样就可以在这个类中的字典嵌套使用其它类了。(一个类集合几个类的功能)
#注解:在一个类的init中定义一个空字典。创建一个方法,传参为键值对,值为类名,并将它们添加到空字典中。创建一个方法,循环这个字典的值,或者取出某个字典的值,就可以对这个类进行操作了,加括号就创建这个类的对象。
class StackConfig(object):
pass
class UserConfig(StackConfig):
pass
class AdminSite(object):
def __init__(self):
self._register = {} #init中创建一个空字典,
def registry(self,key,arg=StackConfig): #通过registry方法将键值对通过这个方法传参进类中,然后键键值对加到init中的字典中。
self._register[key] = arg #如果执行这个方法时没有传递值进来,那么就就是使用默认值StackConfig这个类。 #
def run(self):
for key,value in self._register.items(): #执行registry方法就会生成值是类的字典,这里对字典元素进行操作。
obj = value() #将字典的每个值也就是每个类,加上括号变成类的对象,
print(key,obj) #打印出键,打印出这个值为类的对象。
site = AdminSite() #创建一个AdminSite类的对象
site.registry(1) #没有传参,第二个默认传参为StackConfig类
site.registry(2,StackConfig)#有传参,就使用传参
site.registry(3,UserConfig) #可以传多个类到字典
site.run()
-------------------结果:
1 <__main__.StackConfig object at 0x005F58D0>
2 <__main__.StackConfig object at 0x005F5DD0>
3 <__main__.UserConfig object at 0x005F58F0>
5)这个4)的使用案例一: 一个类中生成空字典,类中一个方法是给字典赋值,值为类。一个是使用字典的类,取出类生成对象并取对象的实例变量
class StackConfig(object):
list_display = '小马过河'
class UserConfig(StackConfig):
list_display = '魔降风云变'
class AdminSite(object):
def __init__(self):
self._register = {}
def registry(self,key,arg=StackConfig):
self._register[key] = arg
def run(self):
for key,value in self._register.items():
obj = value()
print(key,obj.list_display) #这样来使用类中元素
site = AdminSite()
site.registry(1)
site.registry(2,StackConfig)
site.registry(3,UserConfig)
site.run()
-------------------结果:
1 小马过河
2 小马过河
3 魔降风云变
#思考,如果是同一个属性不同的值,比如很多个人名,那么我把很多个人名写成一个列表,循环列表生成只需要传名字进类的一个对象,这样就可以实现给一个类创建多个对象了。这些对象要做相同的操作,我就写一个方法,对这些对象进行循环,实现一个的操作,就是实现很多个对象的相同的操作了。
#能少量代码实现很长的一个字典吗?可以生成嵌套字典吗?
6)这是4)的使用案例二,5)的基础上变化:一个类中生成空字典,类中一个方法是给字典赋值,值为类。一个是使用字典的类,取出类生成对象并执行对象可用的方法
class StackConfig(object):
list_display = '小马过河'
def changelist_view(self):
print(self.list_display)
class UserConfig(StackConfig):
list_display = '魔降风云变'
class AdminSite(object):
def __init__(self):
self._register = {}
def registry(self, key, arg=StackConfig):
self._register[key] = arg
def run(self):
for key, value in self._register.items():
obj = value()
obj.changelist_view()
site = AdminSite()
site.registry(1)
site.registry(2, StackConfig)
site.registry(3, UserConfig)
site.run()
-------------------结果:
小马过河
小马过河
魔降风云变
#用类和不用类的优势体现案例,有时间加一个
2.特殊成员
2.1 __init__
class Foo:
def __init__(self, a1):
self.a1 = a1
print(self.a1)
obj = Foo('mcw') #创建一个对象,会先执行类中__init__方法,将方法里的变量在对象里形成实例变量。
-------------结果:
mcw
2.2 __new__
class Foo(object):
def __init__(self): #用于给对象中赋值,初始化方法
self.x = 123
print("init")
def __new__(cls, *args, **kwargs): # 用于创建空对象,构造方法
print("new")
return object.__new__(cls) #如果没有返回object.__new__(cls) ,那么不能打印出init,什么道理
obj = Foo() #类()创建对象,先执行new方法,再执行init方法(父 object)
------------结果:
new #自己创建一个__new__方法,打印,可以看出先执行new,new是object的方法,用于创建对象,py3继承object类。
init #
2.3 __cal__
class Foo(object):
def __call__(self, *args, **kwargs):
print('执行call方法')
obj = Foo()
obj()
Foo()()
----------结果:
执行call方法
执行call方法
#类()创建对象,先执行new方法,再执行init方法(父 object) 函数()执行函数 方法()执行方法
类中定义__cal__方法,对象可以调用,可以对象(),对象+()执行类中cal方法
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server
def func(environ,start_response):
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
return ['你好'.encode("utf-8") ]
class Foo(object):
def __call__(self, environ,start_response):
start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
return ['你<h1 style="color:red;">不好</h1>'.encode("utf-8")]
# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('127.0.0.1', 8000, Foo())
server.serve_forever()
2.4 __getitem__ __setitem__ __delitem__
class Foo(object):
def __setitem__(self, key, value):
pass
def __getitem__(self, item):
return item + 'uuu'
def __delitem__(self, key):
pass
obj1 = Foo()
obj1['k1'] = 123 # 内部会自动调用 __setitem__方法
val = obj1['xxx'] # 内部会自动调用 __getitem__方法
print(val)
del obj1['ttt'] # 内部会自动调用 __delitem__ 方法
2.5 __str__
class Foo(object):
def __str__(self): #只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来
return '小马过河'
obj=Foo()
print(obj,type(obj)) 原本打印对象,返回的是对象的地址,使用str方法,就可以修改,指定打印对象,显示出想要显示的内容
-------------结果
小马过河 <class '__main__.Foo'> #以后看着像字符串的,要记得不一定是字符串
class User(object):
def __init__(self,name,email):
self.name = name
self.email = email
def __str__(self):
return "%s %s" %(self.name,self.email,)
user_list = [User('小马','2g@qq.com'),User('小明','2d@qq.com'),User('小红','xx@qq.com')]
for item in user_list:
print(item)
---------------------结果:
小马 2g@qq.com #返回的不是字符串
小明 2d@qq.com
小红 xx@qq.com
2.6 __dict__
class Foo(object):
lei="xiao"
def __init__(self,name,age,email):
self.name = name
self.age = age
self.email = email
obj = Foo('小马过河',18,'111@qq.com')
print(obj)
print(obj.name)
print(obj.age)
print(obj.email)
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val) #对象.__dict__ 只是将对象中init里的变量变成字典格式吗
-------------结果:
<__main__.Foo object at 0x01E45670>
小马过河
18
111@qq.com
{'name': '小马过河', 'age': 18, 'email': '111@qq.com'}
#想要将对象变量变成键值对的形式,就可以用,:对象.__dict__ ,返回的是字典
2.7 上下文管理【面试题】
class Foo(object):
def __enter__(self):
self.x = open('a.txt',mode='a',encoding='utf-8')
return self.x
def __exit__(self, exc_type, exc_val, exc_tb):
self.x.close()
with Foo() as ff:
ff.write('alex')
ff.write('alex')
ff.write('alex')
ff.write('alex')
# class Context:
# def __enter__(self):
# print('进入')
# return self
#
# def __exit__(self, exc_type, exc_val, exc_tb):
# print('推出')
#
# def do_something(self):
# print('内部执行')S
#
# with Context() as ctx:
# print('内部执行')
# ctx.do_something()
class Foo(object):
def do_something(self):
print('内部执行')
class Context:
def __enter__(self):
print('进入')
return Foo()
def __exit__(self, exc_type, exc_val, exc_tb):
print('推出')
with Context() as ctx:
print('内部执行')
ctx.do_something()
2.8 两个对象相加
val = 5 + 8
print(val)
val = "小马" + "过河" #字符串对象+对象。
print(val)
class Foo(object):
def __add__(self, other): #类的对象与对象做运算,需要定义方法才不报错。
return 44 #去掉return 报参数错,在实例化对象的时候加参数报参数错误
obj1 = Foo()
obj2 = Foo()
val = obj1 + obj2 #两个对象相加之后没报错,但是结果只有一个就是add的返回值,
print(val)
----------结果:
13
小马过河
44 #将44改为 other,打印结果:<__main__.Foo object at 0x006F5830>
特殊成员:就是为了能够快速实现执行某些方法而生。
3.内置函数补充
3.1 type,查看类型
class Foo:
pass
obj = Foo()
if type(obj) == Foo:
print('obj是Foo类的对象')
3.2 issubclass
class Base:
pass
class Base1(Base):
pass
class Foo(Base1):
pass
class Bar:
pass
print(issubclass(Bar,Base)) #issubclass 子类 父类 判断是否直系前辈 #前是后的子类吗
print(issubclass(Foo,Base))
3.3 isinstance
class Base(object):
pass
class Foo(Base):
pass
obj = Foo()
print(isinstance(obj,Foo)) # 判断obj是否是Foo类或其基类的实例(对象)
print(isinstance(obj,Base)) # 判断obj是否是Foo类或其基类的实例(对象)
#实例(对象,实例)前是后的实例吗,是Ture,否, #判断前面的对象是否是后面这个类或者是其基类的示例,是返回Ture否返回False
4.super
class Base(object):
def func(self):
print('base.func')
return 123
class Foo(Base):
def func(self):
v1 = super().func()
print('foo.func',v1)
obj = Foo()
obj.func()
# super().func() 去父类中找func方法并执行
class Bar(object):
def func(self):
print('bar.func')
return 123
class Base(Bar):
pass
class Foo(Base):
def func(self):
v1 = super().func()
print('foo.func',v1)
obj = Foo()
obj.func()
# super().func() 根据类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)
class Base(object): # Base -> object
def func(self):
super().func()
print('base.func')
class Bar(object):
def func(self):
print('bar.func')
class Foo(Base,Bar): # Foo -> Base -> Bar
pass
obj = Foo()
obj.func()
# super().func() 根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)
super案例一:如何用父的同名属性覆盖子的属性super
class Base(object):
def __init__(self, name):
self.name = name
class Foo(Base):
def __init__(self, name):
self.name = "于大爷" #self.name于大爷,下面由使用super(),往上级找到它的init函数,传参“小马过河”,于是name重新赋值了。
super().__init__(name) # super(Foo,self).__init__(name)
obj1 = Foo('小马过河')
print(obj1.name)
--------------结果:
小马过河
5.异常处理
5.1 基本格式
#基本格式:try 代码块 except Exception as e: pass
try:
pass
except Exception as e:
pass
try:
v = []
v[11111] # IndexError
except ValueError as e:
pass
except IndexError as e:
pass
except Exception as e:
print(e) # e是Exception类的对象,中有一个错误信息。
try:
int('asdf')
except Exception as e:
print(e) # e是Exception类的对象,中有一个错误信息。
finally:
print('最后无论对错都会执行')
#看一段代码执行是否会爆粗,捕获异常, e是错误信息,e可以打印。
# #################### 特殊情况 #########################
def func():
try:
# v = 1
# return 123
int('asdf')
except Exception as e:
print(e) # e是Exception类的对象,中有一个错误信息。
return 123
finally:
print('最后')
func()
5.2 主动触发异常
try:
int('123')
raise Exception('阿萨大大是阿斯蒂') # 代码中主动抛出异常
except Exception as e:
print(e)
def func():
result = True
try:
with open('x.log',mode='r',encoding='utf-8') as f:
data = f.read()
if 'alex' not in data:
raise Exception()
except Exception as e:
result = False
return result
5.3 自定义异常
class MyException(Exception):
pass
try:
raise MyException('asdf')
except MyException as e:
print(e)
class MyException(Exception):
def __init__(self,message):
super().__init__()
self.message = message
try:
raise MyException('asdf')
except MyException as e:
print(e.message)
总结
-
特殊成员 (**)
-
嵌套
-
type/issubclass/isinstacne
-
super
-
异常
-

浙公网安备 33010602011771号