python面向对象--快速入门
1面向对象基本用法
1.1基本格式
class 类名:
def __init__(self,x):
self.x = x
def 方法名字 (self): #函数在类里称为方法,self就是固定参数,必须写self
print('方法')
return
def 方法名字 (self):
print('方法')
return
#实例化一个类的对象
v1 = 类(可以传参)
v2.方法()
-
单例模式: 无论实例化多少次,都用第一次实例化的对象.
-
标准格式
__new__
创建一个实例化对象,并且在init之前执行
class Singleton(object): instance= None def __new__ (cls,*args,**kwargs): if not cls.instance: cls.instance= object.__new__(cls) return cls.instance
1.2调用方法
-
创建类的对象(实例化对象)
obj=类名()
#创建了一个Account类的对象 -
使用对象调用类的方法
obj.函数名字()
调用时方法是有返回值的,与函数类似
- 应用场景:
- 函数(业务功能)比较多,可以使用面向对象来进行归类。
- 想要做数据封装(创建字典存储数据时,面向对象)。
- 游戏示例:创建一些角色并且根据角色需要再创建人物。
1.3对象的作用
-
存储一些值,方便自己使用
class file: def read(self): with open(self.xxx, mode='mode='r', encoding='utf-8') as f: data = f.read() return data def write(self,content): with open(self.xxx, mode='mode='a', encoding='utf-8') as f: f.write(content) # 实例化一个file的对象 v1 = file() # 在对象中写了一个xxx='test.log' v1.xxx = 'test.log' # 通过对象调用类中的read方法,read方法中的self就v1: #v1.read() obj1.write('alex')
1.4类的初始化方法
- 类() 实例化对象,自动执行此类中的 __ init __方法。
- __ init __ 初始化方法(构造方法),为对象内部做初始化
- 如果有一个反复使用的公共值,课可以放到对象中
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('bigox',20,'男')
p1 = show()
2.面向对象的三大特性
2.1封装
class File:
def read(self):
pass
def write(self):
pass
class Person:
def __init__(sef,name,age):
self.name = name
self.age = age
p = Person('alex',19)
2.2继承
#基本格式
class Base:
pass
class Foo(Base):
pass
-
在多个类中如果有公共的方法,可以使用继承,增加代码的重用性.
-
继承关系中查找方法的顺序
- self是谁?
- self是哪个类创建的,就从此类开始找,自己没有就找父类
-
多继承就从左往右
# 父类(基类) class Base: def f1(self): pass # 子类(派生类) class Foo(Base): def f2(self): pass # 创建了一个字类的对象 obj = Foo() # 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。 obj.f2() obj.f1() # 创建了一个父类的对象 obj = Base() obj.f1()
-
继承扩展
- 单继承 :字类可以使用父类的方法
- 多继承: 查找顺序
- 深度优先: 对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。
- 广度优先:从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。
# 新式类和经典类 # py2 继承object就是新式类 # 默认是经典类 # py3 都是新式类,默认继承object # 新式类 # 继承object # 支持super # 多继承 广度优先C3算法 # mro方法 # 经典类 # py2中不继承object # 没有super语法 # 多继承 深度优先 # 没有mro方法
2.3多态
- 一个类表现出来的多种状态 --> 多个类表现出相似的状态
#经典例题题,什么是鸭子模型
对于一个函数,python对于参数的类型不会限制,传入参数时就可以是各种类型,但是在函数中如果有类似于索引等特有方法,就会对传入的参数类型有一个限制(类似于字符串的.append.send方法)
类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只要有.send方法,就是我们要想的类型)
# Python
def func(arg):
v = arg[-1] # arg.append(9)
print(v)
# java
def func(str arg):
v = arg[-1]
print(v)
3面向对象成员
=成员
- 类成员
- 类变量
- 绑定方法
- 类方法
- 静态方法
- 属性
- 实例成员(对象)
- 实例变量
3.1实例变量
- 类实例化后的对象内部的变量
3.2类变量
-
类中的变量,写在类的下一级和方法同一级。
-
访问方法:
- 类.类变量名称(推荐)
- 对象.类变量名称
-
经典例题:
- 总结:找变量优先找自己,自己没有找 类 或 基类;修改或赋值只能在自己的内部设置。
class Base: x = 1 obj = Base() print(obj.x) # 先去对象中找,没有再去类中找。 obj.y = 123 # 在对象中添加了一个y=123的变量。 print(obj.y) obj.x = 123 print(obj.x) print(Base.x)
3.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 def func(self, a, b): print(self.name, a, b) obj = Foo() obj.func(1, 2)
3.4静态方法
- 定义:
- @staticmethod装饰器
- 参数无限制
- 调用:
- 类.静态方法名()
- 对象.静态方法名()不推荐
- 在方法不进行传参时使用
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
@staticmethod
def f1():
print(123)
obj = Foo()
obj.func(1, 2)
Foo.f1()
obj.f1() # 不推荐
3.5类方法
-
定义:
- @classmethod装饰器
- 至少有cls一个参数,当前类
-
执行
- 类.方法()
- 对象.类方法()不推荐
class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) @staticmethod def f1(): print(123) @classmethod def f2(cls,a,b): print('cls是当前类',cls) print(a,b) obj = Foo() obj.func(1, 2) Foo.f1() Foo.f2(1,2)
-
经典例题
# 问题: @classmethod和@staticmethod的区别? """ 一个是类方法一个静态方法。 定义: 类方法:用@classmethod做装饰器且至少有一个cls参数。 静态方法:用staticmethod做装饰器且参数无限制。 调用: 类.方法直接调用。 对象.方法也可以调用。 """
3.6属性
- 定义:
- @property装饰器
- 只有一个self参数
- 调用:
- 对象.方法 不加括号
class Foo:
@property
def func(self):
print(123)
return 666
obj = Foo()
result = obj.func
print(result)
-
属性的应用
# 属性的应用 class Page: def __init__(self, total_count, current_page, per_page_count=10): self.total_count = total_count self.per_page_count = per_page_count self.current_page = current_page @property def start_index(self): return (self.current_page - 1) * self.per_page_count @property def end_index(self): return self.current_page * self.per_page_count USER_LIST = [] for i in range(321): USER_LIST.append('alex-%s' % (i,)) # 请实现分页展示: current_page = int(input('请输入要查看的页码:')) p = Page(321, current_page) data_list = USER_LIST[p.start_index:p.end_index] for item in data_list: print(item)
4成员修饰符
4.1 公有
-
公有,所有地方都能访问到。
class Foo: def __init__(self, name): self.__name = name def func(self): print(self.__name) obj = Foo('alex') # print(obj.__name) obj.func()
4.2 私有
-
私有,只有自己可以访问到。
class Foo: __x = 1 @staticmethod def func(): print(Foo.__x) # print(Foo.__x) Foo.func() #--------------------------------------------- class Foo: def __fun(self): print('msg') def show(self): self.__fun() obj = Foo() # obj.__fun() obj.show()
4.3强制访问私有成员
# 强制访问私有成员
class Foo:
def __init__(self,name):
self.__x = name
obj = Foo('alex')
print(obj._Foo__x) # 强制访问私有实例变量
4.4内容补充py2/3区别
-
py2/3区别:
-
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
4.5嵌套
- 类/方法/对象都可以当做变量或嵌套到其他类型中.
- 函数的参数可以是任意类型.
- 可哈希(不可变)数据类型可以做字典的key.
- 类和对象可以做字典的key.
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('上海','浦东')
s3 = School('深圳','南山')
c1 = ClassRoom('全栈21期',s1)
c1.name
c1.school.title
c1.school.address
# ############################################
v = [11,22,33,{'name':'山海','addr':'浦东'}]
v[0]
v[3]['name']
5 特殊方法(8个)
-
补充:
-
类的类变量可以直接操作输出,方法内不可以
class fun: print(123) def func(self): print(1234) class fuu(self): print(456) #输出 123 456
-
-
__init__
#初始化方法: 用于给对象赋值class Foo: """ 类是干啥的。。。。 """ def __init__(self,a1): """ 初始化方法 :param a1: """ self.a1 = a1 obj = Foo('alex')
-
__new__
#构造方法: 在init之前用于创建对象class Foo(object): def __init__(self): """ 用于给对象中赋值,初始化方法 """ self.x = 123 def __new__(cls, *args, **kwargs): """ 用于创建空对象,构造方法 :param args: :param kwargs: :return: """ return object.__new__(cls) obj = Foo()
-
__call__
对象后面加()执行cal方法;class Foo(object): def __call__(self, *args, **kwargs): print('执行call方法') # obj = Foo() # obj() Foo()()
-
__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__ 方法
-
__str__
打印一个对像时,str返回什么打印什么class Foo(object): def __str__(self): """ 只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来 :return: """ return 'asdfasudfasdfsad' obj = Foo() print(obj)
-
__dict__
class Foo(object): def __init__(self,name,age,email): self.name = name self.age = age self.email = email obj = Foo('alex',19,'xxxx@qq.com') val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典 print(val)
-
上下文管理<<经典例题>>
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()
-
__add__
两个对象相加(经典例题)val = 5 + 8 print(val) val = "alex" + "sb" print(val) class Foo(object): def __add__(self, other): return 123 obj1 = Foo() obj2 = Foo() val = obj1 + obj2 print(val)
- 特殊成员:就是为了能够快速实现执行某些方法而生。
6 内置函数补充
importlib 用字符串的形式导入模块
模块 = importlib.import_module('utils.redis')
- 示例:
import importlib
#用字符串的模式导入模块
redis = importlib.import_module("utils.redis")
#用字符串的形式去对象(模块)找到他的成员
getattr(redis,"func")()
7 栈与队列初识
- 栈:类似弹夹,先进后出
- 队列:类似水管,先进先出
class Stack(object):
"""
先进后出
"""
def __init__(self):
self.data_list=[]
def push(self,val):
"""
向栈中压入一个数据(入栈)
"""
self.data_list.append(val)
def pop(self):
"""
从栈中拿走一个数据(出栈)
"""
return self.data_list.pop()
8 可迭代对象
-
表象:可以被for循环的对象就是可迭代对象
-
在类中实现
__iter__
方法且返回一个迭代器(生成器)class Foo: def __iter__(self): return iter([1,2,3,4]) obj = Foo() class Foo: def __iter__(self): yield 1 yield 2 yield 3 obj = Foo()
9 约束
-
约束子类内必须使用方法,不然主动异常
class BaseMessage(object): def send(self,a1): raise NotImplementedError('字类中必须有send方法') class Msg(BaseMessage): def send(self): pass class Email(BaseMessage): def send(self): pass class Wechat(BaseMessage): def send(self): pass class DingDing(BaseMessage): def send(self): print('钉钉') obj = Email() obj.send()
10反射
-
python一切皆对象,所以想要通过字符串的形式操作内部成员都可以通过反射去完成操作.
-
py文件 包 类 对象...
-
反射:根据字符串的形式去某个对象操作对象的成员.
-
getattr(对象名,"方法名")
- 根据字符串的形式去某个对象中获取对象的成员.
- attribute属性
class Foo(object): def __init__(self,name): self.name = name def login(self): pass obj = Foo('alex') # 获取变量 v1 = getattr(obj,'name') # 获取方法 method_name = getattr(obj,'login') method_name()
-
setattr(对象名称,"变量",值 )
- 根据字符串的形式去某个对象中设置成员.
class Foo: pass obj = Foo() obj.k1 = 999 setattr(obj,'k1',123) # obj.k1 = 123 print(obj.k1)
-
hasattr(对象名称,"方法名")
- 根据字符串的形式去某个对象中判断是否含有某成员.返回布尔类型
class Foo: pass obj = Foo() obj.k1 = 999 hasattr(obj,'k1') print(obj.k1)
-
delattr(对象,"方法名")
- 根据字符串的形式去某个对象中删除某成员.
class Foo: pass obj = Foo() obj.k1 = 999 delattr(obj,'k1') print(obj.k1)
-
补充:
-
模块importlib
- importlib 用字符串的形式导入模块
模块 = importlib.import_module('utils.redis')
- 示例:
import importlib #用字符串的模式导入模块 redis = importlib.import_module("utils.redis") #用字符串的形式去对象(模块)找到他的成员 getattr(redis,"func")()
self.MIDDLEWARE_CLASSES = [
'utils.session.SessionMiddleware',
'utils.auth.AuthMiddleware',
'utils.csrf.CrsfMiddleware',
]
for mes in self.MIDDLEWARE_CLASSES:
module_path,class_name=mes.rsplit('.',maxsplit=1) #切割路径和类名
module_object = importlib.import_module(module_path) #插入模块-字符串操作
cla=getattr(module_object,class_name) #根据模块对象找到类名(字符串操作-反射)
obj = cla() #实例化对象
obj.process() #运行内部函数process