day07 类

一、目录

1.模块

2.包

3.isinstance issubclass type

4.方法和函数

5.反射

6.约束

7.继承

8.特殊成员

9.异常处理

补充知识点

10.hashlib模块

11.logging日志模块

二、内容

一.模块

 模块的概述:模块本质上就是一个py文件,一行一行代码多了会通过函数来封装,函数多了以后会通过class类来封装,class类多了就通过一个个py文件,也就是我们

所说的模块。导入模块的方式:import py文件  或者 from py文件 import py文件里面的具体xxx 

导入模块的工作原理:

1.判断内存中是否有master   ps:以master文件为例
2.如果有,直接拿过来使用
3.如果没有,会开辟一个内存空间
4.在该内存空间中执行模块中的代码
5. 默认把名称空间的名字引入进来

导入模块的规则:
规则
1.导入模块写入py文件的最开始
2.顺序
内置模块》第三方模块》自己定义的模块

__name__ 在当前文件作为启动文件的时候"__main__"  
当py文件作为模块被导入的时候是文件自己的名字

python程序的模块搜索路径 通过sys.path查看
sys.modules 当前已经导入的模块
sys.path 模块的搜索路径
sys.path.append ps:可添加xx路径到path路径下

二.包

  包的概述: 包下面存放的是一个个py文件,好处:结构清晰易于管理

包的导入方式:from 路径 import 包    ps: import 不能直接加点, 点在这里代表的是xx下的xx。import 后直接写目录默认会导入__init__.py文件。导入包的path以包的启动文件为准。导入包有 两种方式相对导入和绝对导入,相对导入容易出问题,相对导入在导入的那个文件里面执行代码会报错,原因是不能出当前path文件,所以一般推荐绝对导入。

三.isinstance issubclass type

isinstance:查看某数据的类型

insubclass:查看xx 是否是xx的子类

type: 查看数据的具体类型

class Animal:
def run(self):
print("动物会跑")
class dog(Animal):
def play(self):
print("dog can run")


cat = Animal()
print(type(cat))
print(isinstance(cat,Animal))
print(issubclass(dog,Animal))

<class '__main__.Animal'>
True
True

type的应用小场景

def Sum(a,b):
"""

:param a:
:param b:
:return:
"""
if (type(a) == int or type(a) == float) and (type(b) == int or type(b) == float):
return a + b
else:
print("输入类型错误")
ret = Sum(9.99,9)
print(ret) ps:在python里面三个双引号然后回车是文本注释,可以对你的代码进行阐述。

四.方法和函数

 首先理解创建对象的概念,通过类来创建对象的时候,会生成一个兑现的命名空间然后把类的init方法下的属性都拿过来,再把类下面的方法名写到对象的命名空间里面,此时对于对象下的方法名就是一个绑定方法,当执行对象.方法的时候,实际上还是执行类下面的方法,在这里就能体现出绑定方法了。但对于类来说如果通过类名.方法调用。本质上还是一个函数。因此可以得出一个结论  对象.方法 = 方法   类.方法 = 函数  (实例方法)类方法classmethod 类.方法 = 方法 对象.方法 = 方法 (类方法和类属性一般都是比较推荐通过类调用) 最后一种是静态方法: staticclass 不管通过什么方式来调用始终都是函数。

class Person:
def __init__(self,name,age):
self.name = name
self.age = age
@classmethod
def eat(cls):
print("this is a class method")

@staticmethod
def drink():
print("this is a staic method")

def sleep(self):
print("this is a instance method")

p = Person("jack",19)
print(p.eat)
print(Person.eat)
print(Person.sleep)
print(p.drink)
print(p.sleep)

<bound method Person.eat of <class '__main__.Person'>>
<bound method Person.eat of <class '__main__.Person'>>
<function Person.sleep at 0x0000013C3CD5E510>
<function Person.drink at 0x0000013C3CD5E488>
<bound method Person.sleep of <__main__.Person object at 0x0000013C3CD6A128>>

判断是方法还是函数

from types import FunctionType,MethodType
print(isinstance(p.sleep,FunctionType))
print(isinstance(p.sleep,MethodType))
print(isinstance(p.eat,FunctionType))
print(isinstance(p.eat,MethodType))
print(isinstance(p.drink,FunctionType))
print(isinstance(p.drink,MethodType))

五.反射

  反射只用四个方法,常用的就hasattr和getattr

hasattr(obj,str)判断对象里面是否有xx属性

getattr(obj,str) 获取obj里面的str属性

delattr(obj,str)删除obj里面的str属性

setattr(obj, str,xx) 给obj设置str属性

import daniu
while 1:
skill = input("请输入你要测试的功能: ")
if hasattr(daniu,skill):
new_skill = getattr(daniu,skill)
if callable(new_skill):
new_skill()
else:
print(f"{new_skill}不能被调用")
else:
print("还没有这个功能")
代码解读:导入daniu模块,判断daniu里面是否有skill属性,如果有获取然后在判断是否可调用,如果可调用就执行否则直接打印不可调用。

删除属性的例子:
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def haha(self):
print("haha")
p = Person("ivy","18")
print(hasattr(p,"haha"))
fn = getattr(p,"haha")
fn()
delattr(p,"name")

设置属性的例子
setattr(Person,"eat", lambda self:print("我要吃"))  ps:person类 设置eat方法 通过匿名函数打印我要吃。

六.约束

约束有一种方式

1.通过父类抛异常 raise ImplementedError  代表子类必须重写这个方法

2.通过抽象类约束 没有具体的实例。导入abc模块的ABCmate 和abstractclass

from abc import ABCclass,abstractclass

class Foo(maetaclass=ABCclass):

    @abstractclass

    def login:pass

实例1:抛异常

class Foo:
def login(self):
#报错,抛出异常
raise NotImplementedError("没有重写login")

class Member(Foo):
def login(self):
print("普通人员登录")

class Member_admin(Foo):
def login(self):
print("吧务登录")

class Admin(Foo):
def login(self):
print("管理员登录")

def login(obj):
obj.login()

m = Member()
m_a = Member_admin()
a = Admin()

实例2抽象类
from abc import ABCMeta,abstractmethod
class Foo(metaclass=ABCMeta):
@abstractmethod
def login(self):pass

class Member(Foo):
def login(self):
print("普通人员登录")

class Member_admin(Foo):
def login(self):
print("吧务登录")

class Admin(Foo):
def login(self):
print("管理员登录")

def login(obj):
obj.login()

m = Member()
m_a = Member_admin()
a = Admin()

login(m)
login(m_a)
login(a)

七.继承


class A:
pass
class B(A):
pass

py2:
经典类 -> 默认不继承object
新式类 -> 默认继承object
py3:
新式类

万事万物皆为对象 -> 所有的东西都要继承object

  __mro__() 查看继承的顺序

super(Branch, self).__init__(name,address) 
super的两种用法:
1.指定要从哪儿继承方法过来
class A:
def test(self):
print("testA")
class B(A):
def test(self):
print("testB")
class C(B):
def test(self):
#print("testC")
super(B, self).test() super的第一个参数可根据想访问那个方法来指定,如果想访问A里面的test 把一个参数写成B即可

c = C()
c.test()

2.访问父类里面的构造方法
class School:
def __init__(self,name,adress):
self.name = name
self.address = adress
class Branch(School):
def __init__(self,name,address,leader):
self.leader = leader
super(Branch, self).__init__(name,address)

b = Branch("beida","shahe","Jackson")
print(b.name)

补充点:通过类创建对象 类是通过type来创建的,type是什么鬼我也不知道......

八.特殊特殊成员方法

__doc__  打印类的描述信息

class Person:
"""计算a,b 的和"""
def __init__(self,name):
self.name = name
def eat(self,a,b):
return a+b
print(Person.__doc__)

__module__表示当前操作的对象在哪个模块

class M:
def __init__(self,name):
self.name = name
print(M.__module__) ps:结果是main

__class__表示当前操作的对象的类是什么

 

__del__析构方法,当对象在内存中被释放的时候自动执行

__call__对象后面加括号触发执行

__dict__查看类或对象中的所有成员

__str__如果一个类中定义了str方法,打印对象时默认输出该方法的返回值

__getitem__,__setitem__,__delitem__ 用于索引操作

class Foo(object):
 
    def __getitem__(self, key):
        print('__getitem__',key)
 
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
 
    def __delitem__(self, key):
        print('__delitem__',key)

obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'alex'   # 自动触发执行 __setitem__
del obj['k1']  

__new__用于创建实例的 在init方法前执行

__metaclass__ 定义一个类如何被创建

例子详解:
class Person:
#c创建对象的时候自动调用init
def __init__(self):
print("我是特殊成员")
#在对象加括号的时候自动调用
def __call__(self):
print("我是call")
#with的时候自动调用
def __enter__(self):
print("我是enter")
#离开with的时候自动调用
def __exit__(self, exc_type, exc_val, exc_tb):
print("我是exit")
#执行[]会调用
def __getitem__(self, item):
print("我是getitem")
return "haha"
#执行p[key] = value的时候自动执行
def __setitem__(self, key, value):
print(key)
print(value)
def __delitem__(self, key):
pass
def __hash__(self): ps:hash必须返回一个数字
print("我是hash")
return 1
   #z执行==的时候自动执行
def __eq__(self, other):
print("这是eq")
return True
#执行加的时候自动执行
def __add__(self, other):
print("这是加")
p = Person()

__new__详细说明__new__在init之前执行
创建对象的时间轴,首先写好一个类 然后加载类,
new开辟一个内存空间,(构造) 然后在执行init
创建类的时候如果不写new自动执行object里面的new开辟一个新的内存空间

1. 加载类 2. 开辟内存(__new__) 3. 初始化(__init__) 4. 使⽤用对象xxxxxxxxx

例子1:
class A:
def __init__(self):
print("我是init")
def __new__(cls, *args, **kwargs):
print("我是new")
return object.__new__(cls) #开辟内存
a = A() #不写new默认使用object中的new

例子2:new的单例模式
#单例模式(恶汉式),在内存里面保存一个对象,并且能反复使用
class Singleton:
__instance = None
def __init__(self):
print("我是singleton")
def __new__(cls, *args, **kwargs):
if Singleton.__instance:
return Singleton.__instance
else:
obj = object.__new__(cls)
Singleton.__instance = obj
return Singleton.__instance
s1 = Singleton()
s2 = Singleton()
print(id(s1),id(s2))
#目前问题:高并发的情况下,这个单例有问题

九.异常处理

try:
xxxx
except 错误:
xxx
finally:
最终的...

traceback
查看调用过程的报错信息

raise 抛出异常对象
定义类的时候继承Exception就是异常类

try:
print("各种操作....")
except ZeroDivisionError as e:
print("除数不不能是0")
except FileNotFoundError as e:
print("⽂文件不不存在")
except Exception as e:
print("其他错误")
else:
'''保护不不抛出异常的代码, 当try中⽆无异常的时候执⾏行行'''
finally: '''最后总是要执⾏行行我'''

import traceback  # 可以看见堆栈信息(谁掉了谁)
try:
print(1/0)
except Exception:
print("报错了")
print(traceback.format_exc()) #查看调用过程的报错信息

自定义异常
class shujuleixingcuowu(Exception): #只要继承了Exception就是异常类
pass

def func(a,b):
"""
计算a+b的结果
:param: a必须是数字
:param: b必须是数字
:return: 和
"""
if (type(a) == int or type(a) == float) and (type(b) == int or type(b) == float):
return a + b
else:
raise shujuleixingcuowu("a和b的数据类型错误")

补充知识点

修改@property属性里面的值

class Person:
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name+"_sb"
@name.setter
def name(self,_name):
self.__name = _name

p = Person("Jack")
print(p.name)
p.name = "haha"
print(p.name)

十.hashlib模块

import hashlib  #机密包 最著名的是MD5用来验证文件或者密码的一致性
password = "123456"
obj = hashlib.md5()
obj.update(password.encode("utf-8")) #必须是字节
s = obj.hexdigest()
print(s)

加盐
import hashlib 
password = "123456"
obj = hashlib.md5(b'wang') 在这儿加
obj.update(password.encode("utf-8")) #必须是字节
s = obj.hexdigest()
print(s)

例子:实现登录和注册功能
import hashlib
username = ""
password = ""
def my_md5(s):
obj = hashlib.md5(b'asdasd')
obj.update(s.encode("utf-8"))
return obj.hexdigest()

def reg():
uname = input("请输入用户名:")
upwd = input("请输入密码:")
global username
username = uname
global password
password = my_md5(upwd)
print(password)

def login():
uname = input("请输入用户名:")
upwd = input("请输入密码:")
if uname == username and my_md5(upwd) == password:
print("登录成功")
else:
print("登录失败")
reg()
login()

十一.logging日志模块

单文件记录日志

#logging  记录日志
import logging
# filename: ⽂文件名
# format: 数据的格式化输出. 最终在⽇日志⽂文件中的样⼦子
# 时间-名称-级别-模块: 错误信息
# datefmt: 时间的格式
# level: 错误的级别权重, 当错误的级别权重⼤大于等于leval的时候才会写⼊入⽂文件
logging.basicConfig(filename='x1.txt',
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=0) # 当前配置表示 10以上的分数会被写⼊入⽂文件
logging.critical("报错了") #*别#50
logging.error("报错了") #40
logging.warn("1")
logging.warning("警告") #警告30
logging.info("信息")
logging.debug("调错") #10
logging.log(999,"地球飞了")

结合自定义异常类打印日志
#logging  记录日志
import logging
# # filename: ⽂文件名
# # format: 数据的格式化输出. 最终在⽇日志⽂文件中的样⼦子
# # 时间-名称-级别-模块: 错误信息
# # datefmt: 时间的格式
# # level: 错误的级别权重, 当错误的级别权重⼤大于等于leval的时候才会写⼊入⽂文件
logging.basicConfig(filename='x1.txt',
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=0) # 当前配置表示 10以上的分数会被写⼊入⽂文件
logging.critical("报错了") #*别#50
logging.error("报错了") #40
logging.warn("1")
logging.warning("警告") #警告30
logging.info("信息")
logging.debug("调错") #10
logging.log(999,"地球飞了")

import logging
import traceback
class JackError(Exception):
pass
for i in range(10):
try:
if i % 3 ==0:
raise FileNotFoundError("文件不存在")
elif i % 3 == 1:
raise KeyError
elif i % 3 == 2:
raise JackError("Jackexception")
except FileNotFoundError:
val = traceback.format_exc()
logging.error(val)
except KeyError:
val = traceback.format_exc()
logging.error(val)
except JackError:
val = traceback.format_exc()
logging.error(val)
except Exception:
val = traceback.format_exc()
logging.error(val)

多日志文件系统
import logging

# 创建⼀一个操作⽇日志的对象logger(依赖FileHandler)
file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8')
file_handler.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s"))
logger1 = logging.Logger('用户名1', level=logging.ERROR)
logger1.addHandler(file_handler)
logger1.error("错了错了")

# 再创建⼀一个操作⽇日志的对象logger(依赖FileHandler
file_handler2 = logging.FileHandler('l2.log', 'a', encoding='utf-8')
file_handler2.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s %(levelname)s -%(module)s: %(message)s"))
logger2 = logging.Logger('用户名2', level=logging.ERROR)
logger2.addHandler(file_handler2)
logger2.error("好像真的错了")
上一篇:day07 分支,循环


下一篇:爬虫学习笔记day07