85.请写一段 Python 连接 MySQL 数据库的代码
import pymsql try: conn = pymsql.connect(host="localhost",db='test',user="ceshi",pwsswd="ceshi",port='3306',charset='utf-8') # 建立游标 cur = conn.cursor() cur.excute("select * from t_user") # 获取所有数据,同时还有fetchone(只获取一条)、fetchmany(num)(获取num条数据) # 获取数据返回多个元组 data = cur.fetchall() for d in data: print('姓名:'+d[0],'年龄:'+str(d[1]),'联系方式:'+d[2]) # 关闭游标 cur.close() # 释放数据库连接 conn.close() except: print("连接数据库失败")
86.数据库三范式
- 第一范式(确保每列的原子性)
第一范式是最基本的范式,如果数据库表中所有字段都是不可分解的原子值,则表明该数据库满足了第一范式
- 第二范式(每列都和主键相关)
第二范式是在第一范式的基础上更进一步,确保数据表的每列都和主键相关,而不是只和主键部分相关(主要是针对联合主键);也就是说,一个数据库表中只能保存一种数据,而不是把多种数据都保
保存在一张表中
- 第三范式(每列都和主键直接相关)
第三范式是数据库表每列都和主键直接相关,而不是间接相关
87.Python 使用 Mongo 数据库创建索引
import pymongo url = 'mongodb://localhost:27017' db_name = 'test' mc = pymongo.MongoClient(url) mydb = mc[db_name] # 连接collection col = mydb['temp001'] ''' 创建mongo索引 如果不指定名称,系统会使用默认名称'index' 创建唯一索引需要加上unique=True 1:表示正序排序;-1:表示倒叙排序 ''' col.create_index('{"name":1,"mobile":1}',name='test_index')
88.函数装饰器有什么用,举例说明
作用:在其他函数不做任何代码变动的情况下增加额外的功能
from datetime import datetime def get_time(func): def wrapper(*args,**kwargs): now_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') print('现在的时间是:'+ now_time) return func(*args,**kwargs) return wrapper @get_time def printHello(): print('hello world!') printHello()
89.__call__函数的用法
''' __doc__: 类(实例).__doc__ 类或实例的描述信息(注释) __module__: 类(实例).__module__ 表示对象属于哪个模块 __dict__:查看类或实例的所有属性,结果为字典 __class__: 表示当前操作对象的类 __str__:打印对象时显示 __call__:类(实例)加小括号调用时执行 ''' # __call__使用案例 class Reader(): def __init__(self,name,nationality): self.name = name self.nationality = nationality # 可以传参数 def __call__(self,age): print('Reader: %s Nationality: %s Age: %s' % (self.name, self.nationality,age)) r = Reader('张三','ada') r(20)
90.如何判断一个对象时函数还是方法
# 使用instance from types import MethodType,FunctionType def func1(): pass class TestClass(): def func2(self): pass tc = TestClass() print(isinstance(func1,FunctionType)) print(isinstance(tc.func2,MethodType))
91.@classmethod 和@staticmethod 用法和区别
''' 普通方法: 第一个参数self,表示对象本身,只能访问实例属性,不能访问类属性,实例名.方法名()调用 类方法:第一个参数cls,表示类本身,只能访问类属性,不能访问实例属性,不需要实例化,直接【类名.方法名()】,可通过类对象或类对象实例访问 静态方法:名义上归类管,实际上与类无关,只是类下面一个单独的函数,可以不传参数,不需要实例化,直接【类名.方法名()】,可通过类对象或类对象实例访问 ''' class Fruits(): p_name = 'xiaoguo' def __init__(self,f_name): self.f_name = f_name # 普通方法 def say(self): print('我是普通方法,至少要有一个参数self') print("我爱吃%s" % self.f_name) # 类方法 @classmethod def make(cls,f_name): print('我是类方法,至少要有一个参数cls') print('%s爱吃%s' %(cls.p_name,f_name)) # 静态方法 @staticmethod def other(f_name): print('我是静态方法,可以不传参数!') print('我也爱吃%s' %f_name) f1 = Fruits('芒果') f1.say() print("="*30) f2 = Fruits('苹果') f2.make('香蕉') Fruits.make('香蕉') print("="*30) f3 = Fruits('车厘子') f3.other('车厘子') Fruits.other('车厘子')
92.Python 中的接口如何实现
什么是接口:接口只是定义了一些方法,而没有去实现,多用于程序设计时,只是设计需要哪些功能,并没有实现这些功能;这些功能需要由另一个类继承后,实现部分或全部功能。
''' 接口的实现 ''' # 方法一:通过抽象类和抽象方法,抽象类只能被继承,不能被实例化 # 抽象类可以有普通函数和抽象函数,抽象函数需要被标识,且子类必须全部重写,否则会报错;普通函数在子类中也可以正常调用 from abc import ABCMeta,abstractmethod class Interface(metaclass=ABCMeta): @abstractmethod def a(self): pass @abstractmethod def b(self): pass def c(self): pass class Temp(Interface): def __init__(self): print('我是实现类') def a(self): print('我是方法A') def b(self): pass t = Temp() t.a() t.b() # c()是抽象类中的普通方法,子类也可以正常使用 t.c() # 方法二:普通类(推荐) class MyClass(): def func_a(self): pass def func_b(self): pass class Test(MyClass): def func_a(self): print("我是a") def func_b(self): print("我是b") tt = Test() tt.func_a() tt.func_b()
93.Python 中的反射了解么
- 定义:通过字符串映射object对象的方法或属性
-
方法
- hasattr():判断对象中是否有属性或者方法,返回布尔值
- setattr:给对象添加属性或方法
- getattr: 获取对象中变量或方法的内存地址
- delattr:删除对象中的属性,注意!不能删除对象方法!
class Test(): def __init__(self,name): self.name = name def say(self): print("%s say:Heelo World" %self.name) t = Test('zhangsan') t.say() # hasattr:判断对象中是否有属性或者方法,返回布尔值 print(hasattr(t,"name")) # True print(hasattr(t,"say")) # True print(hasattr(t,'abc')) # False # getattr: 获取对象中变量或方法的内存地址 n = getattr(t,'name') print(n) # 打印zhangsan f = getattr(t,'say') f() abc = getattr(t,'abc','not found') # 第三个参数表示没有找到指定的属性或方法时,显示的内容 print(abc) # setattr:给对象添加属性或方法 def abc(self): print("我是abc") setattr(t,'abc',abc) # 添加方法 t.abc(t) # 额外添加的方法要手动传入对象 setattr(t,'age',18) # 添加属性 print(t.age) # delattr:删除对象中的属性,注意!不能删除对象方法! delattr(t,"age") print(t.age) # 会报没有该属性的错
94.metaclass 作用以及应用场景
- 作用:metaclass用来创建类的,好比类是用来创建对象的;如果说类是对象的模板,那么metaclass就是类的模板
- 应用场景:暂时没能理解
95.什么是猴子补丁
''' 定义:在运行时动态修改模块、类或函数,通常是添加功能或者修正缺陷 ''' class A(): def func(self): print('hello') def monkey(self): print("hello world") A.func = monkey a = A() a.func()
96.在 Python 中是如何管理内存的
-
对象的引用计数机制(使用引用计数来追踪内存中对象,python内部记录了对象有多少个引用,即引用计数)
-
增加引用计数的情况
- 创建对象:x=123
- 赋值:y = x
- 对象被作为参数传递给函数(新的本地引用):func(x)
- 对象成为容器对象的一个元素:myList = [x,123,'abc']
-
减少引用计数的情况
- 对象的别名被赋值给了其他对象:x = 456
- 显示的销毁对象:del x
- 离开本地作用域:比如func()函数结束时,里面的局部变量(全局变量不会)
- 窗口对象中移除对象:myList.remove(x)
- 窗口对象被销毁:del myList
-
增加引用计数的情况
-
垃圾回收机制
- 当引用计数变为0时,说明没用任何引用指向该对象,此时该对象就会被当做垃圾回收
- 垃圾回收主要是以引用计数为主,标记清除和分代清除为辅的机制,分代清除和标记清除是为了处理循环引用的问题
-
内存池机制
- python对内存提供了垃圾收集机制,但是它将不用的内存放到了内存池,而不是返回给操作系统
-
python中分为大内存和小内存(256k为界限)
- 大内存使用malloc分配内存空间
- 小内存使用内存池分配空间
- python针对内存管理机制有两套实现:小于256K的内存(即小内存),使用pymalloc在内存池中申请空间;大于256K的内存(即大内存)直接执行系统的malloc行为申请内存空间
97.当退出 Python 时是否释放所有内存分配
不会。循环引用其他对象或者引用自全局命名空间对象的模块,在python退出时并非全部释放;另外,也不会释放C库保留的内存部分
98.python中的作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域
python作用域遵循LEGB原则,优先级L>E>G>B,即:
L(Local):局部作用域
E(Enclosing):闭包函数外的函数中
G(Global):全局作用域
B(Built-in):内建作用域
# dir为Python内建函数 dir = 1 # Global def test(): dir = 2 # Enclosing def wrapper(): dir = 3 #Local return dir return wrapper print(test()()) # 输出3
作用域和命名空间的关系:作用域一定是命名空间,但命名空间不一定是作用域。
99..三元运算写法和应用场景
写法:result = 返回结果 if 条件 else 条件不满足返回结果
应用场景:简化if条件语句,比如lambda表达式
res = 'true' if 2 < 1 else 'false' print(res) # 打印'false' res1 = lambda x: x if x > 0 else '404' print(res1(-1)) # 打印404
100.了解enumerate么
系统的一个内置函数,为可迭代对象里每个元素配上一个索引,索引与每个元素组成tuple类型
l = ['姓名','班级','带班老师'] e = [i for i in enumerate(l)] print(e) # [(0, '姓名'), (1, '班级'), (2, '带班老师')]
101.pathlib 的用法举例
较常用的用法是导入pathlib模块中的Path类,可以读取或拼接路径并转换成当前系统下的分隔符,用来操作文件。
from pathlib import Path p = Path() # 输出'.' p1 = Path('a','b','c','d') # 输出 a\b\c\d print(p1.parts) # 返回路径中每一个部分 ('a', 'b', 'c', 'd') p2 = p1 / 'e' # 操作符'/' 拼接 print(p2) # 输出a\b\c\d\e data_folder = Path("source_data/text_files/") # 输出source_data\text_files file_to_open = data_folder / "raw_data.txt" with open(file_to_open,'rw+',encoding='utf-8') as f: print(f.read())
102.Python 中递归的最大次数,如何突破
最大递归深度为999
import sys sys.setrecursionlimit(10000) # 设置最大递归深度为10000
103.什么是面向对象的 mro
对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能定义在基类;所以在方法调用的时需要对当前类和基类进行搜索以确定方法所在的位置,这种搜索的顺序就是所谓的方法解析
顺序(即MRO)。对于只支持单继承的编程语言来说,MRO就比较简单,而对于Python这种支持多继承的语言来说,MRO就复杂的多。
104.isinstance作用以及应用场景
作用:判断一个对象是否是一个已知的类型
l = [1,2,3] print(isinstance(l,list)) # True
105.什么是断言以及应用场景
assert,是一种调试工具,用来测试某个断言条件;如果条件为真,则程序继续正常执行,如果条件为假,则会报AssertionError,并显示相关错误信息。
106.新式类和旧式类的区别
python有两种类:经典类和新式类;两者不同之处在新式类继承自object,python2.2引入了新式类,但在python3中,新式类是唯一支持的类。
107.dir()是干什么用的
dir():如果没带参数,将返回当前范围内的变量,方法和定义的类型列表;如果带参数,则返回参数的属性和方法,如果参数中包含__dir__()方法,则该方法将被执行,如果不包含,则最大限度的收集
参数的信息。
108.一个包里有三个模块,demo1.py, demo2.py, demo3.py,但使用 from tools import 导入模块时,如何保证只有 demo1、demo3 被导入了
可以在__init__.py文件中添加__all__=['demo1','demo3']
109.代码中经常遇到的*args, **kwargs 含义及用法
这两个是python中的可变参数,*args表示任意多个参数,是一个tuple;**kwargs表示关键字参数,是dict,如果同时使用*args和**kwargs时,*args必须在**kwargs前面。
110.Python 中会有函数或成员变量包含单下划线前缀和结尾,和双下划线前缀结尾,区别是什么
- 前置单下划线_var:命名约定,表示该名称仅内部使用
- 后置单下划线var_:命令约定,避免和python关键字发生冲突
- 前置双下划綫__var:在类环境使用时会触发名称改写,对python解释器有特殊含义
- 前后双下划綫__var__:表示python定义的特殊方法,在自定义属性时要避免使用这种命名方式
111.举例 sort 和 sorted 的区别
sort()是在原位重新排列一个列表,sorted()是重新生成一个列表
112.什么是负索引
负索引是从最右边开始检索数据,例如,-1是获取列表最后一个数据,-2是获取倒数第二个数,以此类推。
113.pprint模块是干什么的
print()和pprint()都是python的打印模块,功能基本一致,唯一的区别,pprint()是分行打印输出结果,方便查看,print()打印在一行;对于数据结构复杂,数据长度较长的数据,推荐使用pprint()
114.解释一下python中的赋值运算符
python中使用“=”给变量赋值,在算数运算中,为了简化代码编写,Python还提供了一系列赋值运算符,例如,b += a,等价于b = b + a
115.解释一下python中的逻辑运算符
and、or、not
116.讲讲python中的位运算符
该运算符按二进制位对值进行操作
- &:按位与运算符,参与运算的两个值,如果对应位都为1,则该位结果为1,例如(110011 & 001111),返回结果000011
- |:按位或运算符,参与运算的两个值,如果对应位有一个为1,则该位结果为1,上面例子返回111111
- ^:按位异或运算符,当参数运算的两个值对应位相异时,结果为1
- ~:按位取反运算符,对数据的每个二进制位取反,即把1变成0,0变成1
- <<:左位移,数据的每个二进制位向左移若干位,由<<右边的数字指定移动的位数,高位丢弃,低位补0;例如,001100 << 2,返回结果 110000
- >>:右位移,数据的每个二进制位向右移若干位,由>>右边的数字指定移动的位数,低位丢弃,高位补0;例如,001100 << 2,返回结果 000011
117.python中如何使用多进制数
- 二进制:由0或1数字组成,0b或0B开头表示二进制数,使用bin()函数将数字转换成二进制形式
- 八进制:由0-7数字组成,0o或0O开头表示八进制数,使用oct()函数将数字转换成八进制形式
- 十六进制:由数字0-15组成,0x或0X开头表示十六进制数,使用hex()函数将数字转换成十六进制形式
118.已知AList=[1,2,3],BSet={1,2,3} ,从AList和BSet中查找4,哪个最坏时间复杂度大?从AList和BSet中插入4,哪个最坏时间复杂度大?
最坏时间复杂度:算法完成工作,最多需要多少基本操作
常见的时间复杂度高低排序:O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)
查找:列表的最坏时间复杂度是O(n),集合是O(1),所以列表大
插入:两个都是O(1)
119.用 Python 实现一个二分查找的函数
二分查找:二分搜索是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元
素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。
优点:比较次数少,查找速度快,平均性能好
缺点:待查序列必须为有序,且不经常变动(插入和删除)