1. 面向对象三大特性
-
封装
- 归类,将函数放置到一个类中
- 打包, 将数据打包到一个对象中,限制范围
-
继承
- 多个类有相似功能时
-
多态
- python原生支持多态,崇尚鸭子模型,由于python函数传参时,无需指定类型
def func(arg): # arg可以接受多种类型,只需要其中有send方法即可(实现了其他语言的接口功能)
arg.send()
2. 类成员
- 1.类的成员
# 定义一个基类
class Base(object):
def func(self):
print(123)
# 子类 继承 基类
class Foo(Base):
country = "中国" # 类变量/静态字段
def __init__(self,name):
self.name = name # 实例变量/字段
self.__salary = 2000 # 实例化的外部不能访问
# 实力方法
def func(self):
print(Foo.country) # 推荐是用类名+变量名
print(self.country)
# 调用类的成员
Base.func(self)
super.func(self) # 推荐使用
# 静态方法 建议是用类调用 Foo.salary()
# 如果方法中无需使用对象中封装的自己的变量
@staticmethod
def salary(self): # 私有变量 外部使用函数访问
return self.__salary
# 类方法
# 调用 Foo.show(1,2)
# 什么时候写: 如果该方法中使用了当前类的方法或者变量的时候写类方法
@classmethod
def show(cls,x1,x2):
print("类方法",cls.salary())
# 私有实例方法
def __display(self,arg):
print(arg)
# 私有静态方法
@staticmethod
def __display1(arg):
print(arg)
# 私有类方法
@classmethod
def __display2(cls,arg):
print(arg)
# 方法包装访问私有方法
def func(self):
self.__display("123")
Foo.__display1(456)
Foo.__display2(789)
# 属性 无法加参数
# 使用 obj.start 不用加括号, 有返回值
# 共有私有 属性 __start
@property
def start(self):
return 1
Foo.country
obj = Foo("Jeecy") # Foo类的对象/实例
-
分为三类
- 实例变量(字段)
- 类变量(静态字段)
- 私有变量
-
方法
- 实例方法
- 静态方法 @staticmethod
- 类方法 @classmethod
- 私有方法: 内部才能访问
-
静态方法和类方法和实力方法的区别?
- 定义不一样 装饰器一不一样
- 调用不一样 obj.func() cls.func
- 类方法 为了不想写当前类名,使用类方法 cls
-
属性:
方法构造出来的
- 使用 @property 修饰
- 无法加参数
- 使用 obj.start 不用加括号, 有返回值
- 共有私有 属性 __start
-
主动调用其它类成员的方法
Base.func(self) super.func(self) # 推荐使用
类的内置魔术方法
class Foo(object):
# 在类生成之前自动调用的方法,多用于单例模式
def __new__(cls, *args, **kwargs):
return object.__new__(cls) # 创建一个当前类的对象(内部时空的)
# 类的构造方法, 在类实例化成对象的时候自动执行的方法
def __init__(self,name,age):
self.name = name
self.age = age
# obj() 对象加() 自动调用 __call__方法
def __call__(self, *args, **kwargs):
# 打印接受值
print(*args, **kwargs)
# 返回一个值
return 6
# obj["yu"] 对象加['item'] 调用 __getItem__方法
def __getitem__(self, item):
# 打印接受值
print(item)
# 返回值
return 666
# obj["key"] = value 调用 __setItem__ 方法 无返回值
def __setitem__(self, key, value):
print(key,value)
# del obj["key"] 调用 __delitem__ 方法 没有返回值
def __delitem__(self, key):
print(key)
# obj + obj
def __add__(self, other):
print(self.age + object.age)
return 888
# with obj as f: 就要执行 如果有返回值就 as f 接受
def __enter__(self):
print('111')
return 6
# with 执行完内部代码后要执行的内容
def __exit__(self, exc_type, exc_val, exc_tb):
print('222')
# 直接打印这个类或者对象的时候显示的内容
def __str__(self):
return self.name
# 类的注释
# 无需定义
#def __doc__(self):
#pass
# 获取对象封装的数据
# 无需定义
# def __dict__(self):
# pass
# 使对象便可的迭代 返回一个迭代器
def __iter__(self):
return iter(11,22,33,44,55,66)
- 特殊成员
def __init__(self)
def __new__(cls)
obj() 对象加括号会调用 下面call方法
def __call__(self,*args,**kwargs)
obj[] 自动执行
__gitItem__(self,item)
def __getItem(self,item):
print(item)
return 6
- issubclass
issubclass(Foo,Base)
Foo 是不是 Base的子子孙孙类 - type
from types import MethodType,FunctionType
type(obj) == Foo
obj是不是 Foo的实例 - isinstance
isinstance(obj,Foo)
对象 是不是 类/基类的 实例
使用类写一个分页
class Pagenation(object):
def __init__(self, data_list, page, per_page_num=10):
'''
初始化
:param data_list: 数据源
:param page: 当前要查看的页码数
:param per_page_num: 每页要显示的页码数
'''
self.data_list = data_list
self.page = page
self.per_page_num = per_page_num
@property
def start(self):
'''
起始条数索引
:return:
'''
return (self.page - 1) * self.per_page_num
@property
def end(self):
'''
结束条数索引
:return:
'''
return self.page * self.per_page_num
def show(self):
page_data_list = data_list[self.start:self.end]
for item in page_data_list:
print(item)
# 数据源
data_list = []
for i in range(1, 901):
data_list.append(f"Jack-{i}")
while True:
page = int(input("请输入要查看的页码数:"))
obj = Pagenation(data_list, page) # 实例化一个分页
obj.show() # 展示
方法 和 函数的区分
- 类 -> 方法
- 函数 - 函数
反射
hasattr(handler,val) # 有没有这个属性
f = getattr(handler,val) # 根据字符串为参数,去模块/类/对象中寻找与之同名的成员
class Foo(object):
pass
setattr(Foo,'x2',"sdfasdfa") # 添加变量
setattr(Foo,"xx",lambda x:x+1) # 添加方法
a = getattr(Foo,"xx")
print(a(2))
判断一个 arg() arg是否能被调用
callable(arg)
返回 True False
类的约束
class BaseMessage(object):
def send(self):
raise NotImplementedError("send() 必须被重写")
# 约束 派生类必须重写父类方法 有几个参数 子类也需要有几个参数
- 抽象类 抽象方法
from abc import ABCMeta,abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def f2(self): # 抽象方法
pass
- 抽象类 和抽象方法 子类必须重写 来实现这个方法
- 接口: 易中数据类型 用于约束派生类中必须实现指定的方法
python中不存在,java和c#中是存在的
python中使用抽象类和抽象方法:编写麻烦 或者 认为的主动抛出异常
抛出的异常是 raise NotImplementedError("send() 必须被重写")
自定义异常
import os
class ExistsError(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
class KeyInvalidError(Exception):
def __init__(self,code,message):
self.code = code
self.message = message
def func(path,prev):
"""
去 path路径中的文件中 找到前缀为prev的一行数据,获取数据并返回给调用者
1000 成功
1001 文件不存在
1002 关键字为空
1003 未知错误
:param path: 文件路径
:param prev: 关键字
:return: response
"""
response = {
"code": 1000,
"data":None
}
try:
if not os.path.exists(path):
raise ExistsError(1001,"文件不存在")
if not prev:
raise KeyInvalidError(1002,"关键字为空")
except ExistsError as e:
response["code"] = e.code
response["data"] = e.message
except KeyInvalidError as e:
response["code"] = e.code
response["data"] = e.message
except Exception as e:
response["code"] = 1003
response["data"] = "未知错误"
return response