本文主要整理了关于Python的面试/笔试的一些考点,可用于查漏补缺。
涉及到的一些Python进阶知识,可以查看专栏学习:《Python进阶》
\quad
\quad
注意:Java 有些特殊,java程序也需要编译,但是没有直接编译成为机器语言,而是编译称为字节码,然后用解释方式执行字节码。
\quad
\quad
\quad
\quad
字符串:
'luobodazahui'[1:3]
format
:"welcome to luobodazahui, dear {name}"format(name="baby")
join
:可以用来连接字符串,将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串。'-'.join(['luo', 'bo', 'da', 'za', 'hui'])
String.replace(old,new,count)
:将字符串中的 old
字符替换为 New
字符,count
为替换的个数 'luobodazahui-haha'.replace('haha', 'good')
>>> mystr5 = 'luobo,dazahui good'
>>> print(mystr5.split()) # 默认以空格分割
['luobo,dazahui', 'good']
>>> print(mystr5.split('h')) # 以h分割
['luobo,daza', 'ui good']
>>> print(mystr5.split(',')) # 以逗号分割
['luobo', 'dazahui good']
列表:
append
和 extend
向列表中添加元素>>> mylist1 = [1, 2]
>>> mylist2 = [3, 4]
>>> mylist3 = [1, 2]
>>> mylist1.append(mylist2)
>>> print(mylist1)
[1, 2, [3, 4]]
>>> mylist3.extend(mylist2)
>>> print(mylist3)
[1, 2, 3, 4]
del
:
pop
:删除最后一个元素remove
:根据元素的值进行删除>>> mylist4 = ['a', 'b', 'c', 'd']
>>> del mylist4[0]
>>> print(mylist4)
['b', 'c', 'd']
>>> mylist4.pop()
>>> print(mylist4)
['b', 'c']
>>> mylist4.remove('c')
>>> print(mylist4)
['b']
sort
:是将list
按特定顺序重新排列,默认为由小到大,参数 reverse=True
可改为倒序,由大到小。>>> mylist5 = [1, 5, 2, 3, 4]
>>> mylist5.sort()
>>> print(mylist5)
[1, 2, 3, 4, 5]
>>> mylist5.reverse()
>>> print(mylist5)
[5, 4, 3, 2, 1]
reverse
:是将list
逆置。字典:
dict.clear()
>>> dict1 = {'key1':1, 'key2':2}
>>> dict1.clear()
>>> dict1
{}
pop
方法来指定删除字典中的某一项(随机的)。>>> dict1 = {'key1':1, 'key2':2}
>>> d1 = dict1.pop('key1')
>>> dict1
{'key2': 2}
>>> d1
1
>>> dict2 = {'key1':1, 'key2':2}
>>> mykey = [key for key in dict2] # ['key1', 'key2']
>>> mykey
['key1', 'key2']
>>> myvalue = [value for value in dict2.values()]
>>> myvalue
[1, 2]
>>> key_value = [(k, v) for k, v in dict2.items()]
>>> key_value
[('key1', 1), ('key2', 2)]
fromkeys
用于创建一个新字典,以序列中元素做字典的键,value
为字典所有键对应的初始值。>>> keys = ['zhangfei', 'guanyu', 'liubei', 'zhaoyun']
>>> dict.fromkeys(keys, 0)
{'zhangfei': 0, 'guanyu': 0, 'liubei': 0, 'zhaoyun': 0}
\quad
\quad
计算机在最初的设计中,采用了8个比特(bit)作为一个字节(byte)的方式。一个字节能表示的最大的整数就是255,如果要表示更大的整数,就必须用更多的字节。最早,计算机只有 ASCII 编码,即只包含大小写英文字母、数字和一些符号,这些对于其他语言,如中文,日文显然是不够用的。后来又发明了Unicode,Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。UTF-8 是隶属于 Unicode 的可变长的编码方式。
在 Python 中,以 Unicode 方式编码的字符串,可以使用 encode()
方法来编码成指定的 bytes
,也可以通过 decode()
方法来把 bytes
编码成字符串。
>>> "你好".encode('utf-8')
b'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
"你好"
\quad
\quad
>>> a, b = 1, 2
>>> a, b = b, a
>>> print(a, b)
\quad
\quad
==
是比较操作符,只是判断对象的值(value)是否一致,而 is
则判断的是对象之间的身份(内存地址)是否一致。对象的身份,可以通过 id()
方法来查看。
>>> c = d = [1, 2]
>>> e = [1, 2]
>>> print(c is d)
True
>>> print(c == d)
True
>>> print(c is e)
False
>>> print(c == e)
True
只有 id
一致时,is
比较才会返回 True
,而当 value
一致时,==
比较就会返回 True
。
\quad
\quad
位置参数,默认参数,可变参数,关键字参数。
\quad
\quad
*arg
和 **kwarg
作用允许我们在调用函数的时候传入多个实参
>>> def test(*arg, **kwarg):
... if arg:
... print("arg:", arg)
... if kwarg:
... print("kearg:", kwarg)
...
>>> test('ni', 'hao', key='world')
arg: ('ni', 'hao')
kearg: {'key': 'world'}
可以看出,*arg
会把位置参数转化为 tuple
,**kwarg
会把关键字参数转化为 dict
。
\quad
\quad
>>> import time
>>> import datetime
>>> print(datetime.datetime.now())
2022-09-12 19:51:24.314335
>>> print(time.strftime('%Y-%m-%d %H:%M:%S'))
2022-09-12 19:51:24
\quad
\quad
简单列举10条:
l
’,大写字母’O
’,以及大写字母’I
’等容易混淆的字母。has
或 is
前缀命名布尔元素,如: is_connect = True
; has_member = False
。object
继承。_
表明此为内部使用的。
\quad
\quad
>>> import copy
>>> list1 = [1, 2, 3, [1, 2]]
>>> list2 = copy.copy(list1)
>>> list2.append('a')
>>> list2[3].append('a')
>>> list1
[1, 2, 3, [1, 2, 'a']]
>>> list2
[1, 2, 3, [1, 2, 'a'], 'a']
浅拷贝只成功”独立“拷贝了列表的外层,而列表的内层列表,还是共享的。(划重点!!!)
>>> import copy
>>> list1 = [1, 2, 3, [1, 2]]
>>> list3 = copy.deepcopy(list1)
>>> list3.append('a')
>>> list3[3].append('a')
>>> list1
[1, 2, 3, [1, 2]]
>>> list3
[1, 2, 3, [1, 2, 'a'], 'a']
深拷贝使得两个列表完全独立开来,每一个列表的操作,都不会影响到另一个。
\quad
\quad
[lambda x:i*x for i in range(4)]
🧡🧡这是一道非常经典的题目了。
>>> def num():
... return [lambda x:i*x for i in range(4)]
...
>>> [m(1) for m in num()]
[3, 3, 3, 3]
why?
详细看链接:《Python面试题目:[lambda x: x*i for i in range(4)]》
\quad
\quad
>>> for i in range(1, 10):
... for j in range(1, i + 1):
... print(f"{i}*{j}={i * j}", end=" ")
... print()
...
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
知识点:print
函数默认是会换行的,其有一个默认参数 end
。
\quad
\quad
filter
、map
、reduce
的作用filter
函数用于过滤序列,它接收一个函数和一个序列,把函数作用在序列的每个元素上,然后根据返回值是True
还是False
决定保留还是丢弃该元素。>>> mylist = list(range(10))
>>> list(filter(lambda x: x % 2 == 1, mylist))
[1, 3, 5, 7, 9]
map
函数传入一个函数和一个序列,并把函数作用到序列的每个元素上,返回一个可迭代对象。>>> list(map(lambda x: x % 2, mylist))
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
>>> list(map(lambda x: x * 2, mylist))
[2, 4, 6, 8, 10, 12, 14, 16, 18]
reduce
函数用于递归计算,同样需要传入一个函数和一个序列,并把函数和序列元素的计算结果与下一个元素进行计算。
reduce()
将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce
中的function
函数 (有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用function
函数运算,最后得到一个结果。
>>> from functools import reduce
>>> reduce(lambda x, y: x + y, range(101))
5050
reduce()
的应用:
reduce(lambda x, y: x * y, [1, 2, 3, 4])
reduce(lambda x, y: x if x > y else y, [1, 2, 3, 4])
[3, 5, 8, 1]
对应的是3581的每一个数字,要从这个列表计算出原来的数,可以这样做:reduce(lambda x, y: x * 10 + y, [3, 5, 8, 1])
可以看出,上面的三个函数与匿名函数相结合使用,可以写出强大简洁的代码。
\quad
\quad
例如:
>>> def test(L=[]):
... L.append('test')
... print(L)
...
>>> test()
['test']
>>> test()
['test', 'test']
默认参数是一个列表,是可变对象[]
,Python在函数定义的时候,默认参数 L
的值就被计算出来了,是[]
,每次调用函数,如果 L
的值变了,那么下次调用时,默认参数的值就已经不再是[]
了。
\quad
\quad
__new__
和 __init__
区别(🧡🧡)__new__
是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法。__init__
是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候,是一个实例方法。__new__
至少要有一个参数cls
,代表当前类,此参数在实例化时由 Python 解释器自动识别。__new__
必须要有返回值,返回实例化出来的实例,这点在自己实现__new__
时要特别注意,可以 return
父类(通过 super(当前类名, cls)
)__new__
出来的实例,或者直接是 object
的__new__
出来的实例。__init__
有一个参数 self
,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值。__new__
创建的是当前类的实例,会自动调用__init__
函数,通过 return
语句里面调用的__new__
函数的第一个参数是 **cls**
** 来保证是当前类实例**,如果是其他类的类名,那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__
函数,也不会调用其他类的__init__
函数。
\quad
\quad
看下面的例子:如果 a>b
成立 就输出 a-b
否则a+b
。
>>> >>> a, b = 1, 2
>>> h = a - b if a > b else a + b
>>> h
3
\quad
\quad
>>> import random
>>> random.random()
0.7571910055209727
>>> random.randint(1, 100)
23
>>> random.uniform(1, 5)
3.0640732831151687
用
np.random
也可以!
\quad
\quad
zip()
函数将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表。
>>> list1 = ['zhangfei', 'guanyu', 'liubei', 'zhaoyun']
>>> list2 = [0, 3, 2, 4]
>>> list(zip(list1, list2))
[('zhangfei', 0), ('guanyu', 3), ('liubei', 2), ('zhaoyun', 4)]
\quad
\quad
range
和xrange
的区别只有Python2中才有xrange()
和range()
,Python3中的range()
其实就是Python2中xrange()
。
range([start,] stop[, step])
,根据start
与stop
指定的范围以及step
设定的步长,生成一个序列;xrange()
生成一个生成器,可以很大的节约内存。
\quad
\quad
with
方法打开文件的作用打开文件在进行读写的时候可能会出现一些异常状况,如果按照常规的f.open()
写法,我们需要 try
,except
,finally
,做异常判断,并且文件最终不管遇到什么情况,都要执行f.close()
关闭文件,with
方法帮我们实现了finally
中 f.close()
。
with open("hello.txt", "a") as f:
f.write("hello world!")
\quad
\quad
>>> s = "1,2,3,4,5,6,7,8,9"
>>> s.split(",")
['1', '2', '3', '4', '5', '6', '7', '8', '9']
\quad
\quad
>>> s = "1,2,3,4,5,6,7,8,9"
>>> list(map(lambda x: int(x), s.split(",")))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
\quad
\quad
利用集合去重:
>>> mylist = [1, 2, 3, 4, 5, 5, 6, 7, 4, 3]
>>> list(set(mylist))
[1, 2, 3, 4, 5, 6, 7]
\quad
\quad
统计字符串中字母个数:
>>> from collections import Counter
>>> mystr = 'sdfsfsfsdfsd,were,hrhrgege.sdfwe!sfsdfs'
>>> Counter(mystr)
Counter({'s': 9,
'd': 5,
'f': 7,
',': 2,
'w': 2,
'e': 5,
'r': 3,
'h': 2,
'g': 2,
'.': 1,
'!': 1})
统计字符串中单词个数
>>> mystr2 = "hello, Nice to meet you!"
>>> len(mystr2.split(" "))
5
\quad
\quad
>>> [x for x in range(20) if x % 2 == 1]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
\quad
\quad
>>> list1 = [[1, 2], [3, 4], [5, 6]]
>>> [j for i in list1 for j in i]
[1, 2, 3, 4, 5, 6]
\quad
\quad
二分查找算法也称折半查找,基本思想就是折半,对比大小后再折半查找,必须是有序序列才可以使用二分查找。
非递归算法:
def binary_search(data, item):
left = 0
right = len(data) - 1
while left <= right:
mid = (left + right) // 2
if data[mid] == item:
return True
elif data[mid] < item:
left = mid + 1
else:
right = mid - 1
return False
递归算法:
def binary_search(data, item):
n = len(data)
if n > 0:
mid = n // 2
if data[mid] == item:
return True
elif data[mid] > item:
return binary_search(data[:mid], item)
else:
return binary_search(data[mid + 1:], item)
return False
\quad
\quad
如:("zhangfei", "guanyu"),(66, 80)
-> {'zhangfei': 66, 'guanyu': 80}
。
>>> a = ("zhangfei", "guanyu")
>>> b = (66, 80)
>>> dict(zip(a, b))
{'zhangfei': 66, 'guanyu': 80}
\quad
\quad
例子1:
>>> a = (1, 2, 3, [4, 5, 6, 7], 8)
>>> a[3] = 2
报错:TypeError: ‘tuple’ object does not support item assignment。
原因:元组不能修改!tuple 是不可变类型,不能改变 tuple 里的元素。
例子2:
>>> a = (1, 2, 3, [4, 5, 6, 7], 8)
>>> a[3][2] = 2
>>> a
(1, 2, 3, [4, 5, 2, 7], 8)
list 是可变类型,改变其元素是允许的。
\quad
\quad
dict1 = {'zhangfei':1, "liubei":2, "guanyu": 4, "zhaoyun":3}
myjson = json.dumps(dict1) # 字典转JSON
mydict = json.loads(myjson) # JSON转字典
\quad
\quad
列表推导式:返回一个列表。
>>> td_list = [i for i in range(10)]
>>> td_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> type(td_list)
list
生成器:
>>> ge_list = (i for i in range(20))
>>> ge_list
<generator object <genexpr> at 0x000001C3C127AAC8>
>>> type(ge_list)
generator
字典推导式:
>>> dic = {k: 2 for k in ["a", "b", "c", "d"]}
>>> dic
{'a': 2, 'b': 2, 'c': 2, 'd': 2}
>>> type(dic)
dict
\quad
\quad
read()
读取整个文件readline()
读取下一行,使用生成器方法readlines()
读取整个文件到一个迭代器以供我们遍历
\quad
\quad
>>> import random
>>> list = list(range(1, 10))
>>> random.shuffle(list)
>>> list
[3, 9, 1, 4, 6, 2, 8, 7, 5]
\quad
\quad
>>> 'luobodazahui'[::-1]
'iuhazadoboul'
\quad
\quad
__foo__
:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突,就是例如__init__()
,__del__()
,__call__()
些特殊方法。_foo
:一种约定,用来指定变量私有。不能用from module import *
导入,其他方面和公有变量一样访问。__foo
:这个有真正的意义:解析器用_classname__foo
来代替这个名字,以区别和其他类相同的命名,它无法直接像公有成员一样随便访问,通过对象名._类名__xxx
这样的方式可以访问。
\quad
\quad
object
的类,都是新式类object
的是新式类,没有写父类的是经典类
\quad
\quad
__init__()
)方法不会被自动调用,它需要在其派生类的构造中专门调用;self
参数变量。区别于在类中调用普通函数时并不需要带上 self
参数。
\quad
\quad
super()
函数是用于调用父类(超类)的一个方法
class A():
def funcA(self):
print("this is func A")
class B(A):
def funcA_in_B(self):
super(B, self).funcA()
def funcC(self):
print("this is func C")
>>> ins = B()
>>> ins.funcA_in_B()
this is func A
>>> ins.funcC()
this is func C
\quad
\quad
主要分为实例方法、类方法和静态方法。
定义:第一个参数必须是实例对象,该参数名一般约定为“self
”,通过它来传递实例的属性和方法(也可以传类的属性和方法)。
调用:只能由实例对象调用。
定义:使用装饰器@classmethod
。第一个参数必须是当前类对象,该参数名一般约定为“cls
”,通过它来传递类的属性和方法(不能传实例的属性和方法)。
调用:实例对象和类对象都可以调用。
定义:使用装饰器@staticmethod
。参数随意,没有“self
”和“cls
”参数,但是方法体中不能使用类或实例的任何属性和方法。
调用:实例对象和类对象都可以调用。
静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互。即在静态方法中,不会涉及到类中的方法和属性的操作。可以理解为将静态方法存在此类的名称空间中。
类方法是将类本身作为对象进行操作的方法。他和静态方法的区别在于:不管这个方式是从实例调用还是从类调用,它都用第一个参数把类传递过来。
\quad
\quad
function
都属于函数(function)function
都属于方法(method)普通函数:
def func1():
pass
>>> print(func1)
<function func1 at 0x000001C3C12A4438>
类中的函数:
class People(object):
def func2(self):
pass
@staticmethod
def func3():
pass
@classmethod
def func4(cls):
pass
>>> people = People()
>>> print(people.func2)
<bound method People.func2 of <__main__.People object at 0x000001C3C12A6A48>>
>>> print(people.func3)
<function People.func3 at 0x000001C3C12A4A68>
>>> print(people.func4)
<bound method People.func4 of <class '__main__.People'>>
\quad
\quad
isinstance
的作用以及与type()
的区别(🧡🧡)isinstance()
函数来判断一个对象是否是一个已知的类型,类似type()
。
区别:
type()
不会认为子类是一种父类类型,不考虑继承关系;isinstance()
会认为子类是一种父类类型,考虑继承关系。class A(object):
pass
class B(A):
pass
>>> a = A()
>>> b = B()
>>> print(isinstance(a, A))
True
>>> print(type(a) == A)
True
>>> print(isinstance(b, A))
True
>>> print(type(b) == A)
False
\quad
\quad
单例模式:
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
举例:操作一个文件,应该用一个唯一的实例去操作。
工厂模式:
工厂类模式设计的核心是:让“生产”和“产品”解耦。
工厂模式的主要解决的问题:将原来分布在各个地方的对象创建过程单独抽离出来,交给工厂类负责创建。其他地方想要使用对象直接找工厂(即调用工厂的方法)获取对象。
优点:
\quad
\quad
>>> import os
>>> print(os.listdir('.'))
\quad
\quad
for i in range(1, 6):
for j in range(1, 6):
for k in range(1, 6):
if (i != j) and i != k and j != k:
print(f"{i}{j}{k}")
\quad
\quad
>>> " hello world ".strip()
'hello world'
\quad
\quad
方法一:
>>> "hello you are good".replace(" ", "")
'helloyouaregood'
方法二:
>>> "".join("hello you are good".split(" "))
'helloyouaregood'
\quad
\quad
方法一:使用 %
操作符
print("This is for %s" % "Python")
print("This is for %s, and %s" %("Python", "You"))
方法二:str.format
(在 Python3 中,引入了这个新的字符串格式化方法)
print("This is my {}".format("chat"))
print("This is {name}, hope you can {do}".format(name="zhouluob", do="like"))
方法三:f-strings
(在 Python3-6 中,引入了这个新的字符串格式化方法)
name = "luobodazahui"
print(f"hello {name}")
一个复杂些的例子:
def mytest(name, age):
return f"hello {name}, you are {age} years old!"
>>> people = mytest("luobo", 20)
>>> print(people)
hello luobo, you are 20 years old!
\quad
\quad
title()
函数:
>>> str1 = "hello world"
>>> str1.title()
'Hello World'
不使用 title()
函数
>>> str1 = "hello world"
>>> " ".join(list(map(lambda x: x.capitalize(), str1.split(" "))))
'Hello World'
>>> " ".join(list(map(lambda x: x[0].upper() + x[1:], str1.split(" "))))
'Hello World'
\quad
\quad
如:[1, 2, 3] -> [“1”, “2”, “3”]
>>> list1 = [1, 2, 3]
>>> list(map(lambda x: str(x), list1))
['1', '2', '3']
\quad
\quad
反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
简单理解就是用来判断某个字符串是什么,是变量还是方法。
例子:先定义一个类:
class NewClass(object):
def __init__(self, name, male):
self.name = name
self.male = male
def myname(self):
print(f'My name is {self.name}')
def mymale(self):
print(f'I am a {self.male}')
>>> people = NewClass('luobo', 'boy')
>>> print(hasattr(people, 'name'))
True
>>> print(getattr(people, 'name'))
luobo
>>> setattr(people, 'male', 'girl')
>>> print(getattr(people, 'male'))
girl
getattr
,hasattr
,setattr
,delattr
对模块的修改都在内存中进行,并不会影响文件中真实内容。
详情请看博客:《Python进阶系列》十八:详解Python中的反射——通过字符串的形式操作对象
\quad
\quad
类与实例:首先定义类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例;
类与元类:先定义元类, 根据 metaclass 创建出类,所以:先定义 metaclass,然后创建类。
class MyMetaclass(type):
def __new__(cls, class_name, class_parents, class_attr):
class_attr['print'] = "this is my metaclass's subclass %s" %class_name
return type.__new__(cls, class_name, class_parents, class_attr)
class MyNewclass(object, metaclass=MyMetaclass):
pass
>>> myinstance = MyNewclass()
>>> myinstance.print
"this is my metaclass's subclass MyNewclass"
详细内容见博客:《Python进阶系列》十五:详解Python中的元类(metaclass)
\quad
\quad
sort()
是可变对象列表(list)的方法,无参数,无返回值。sort()
会改变可变对象。
>>> list1 = [2, 1, 3]
>>> print(list1.sort())
None
>>> list1
[1, 2, 3]
>>> dict1.sort()
Traceback (most recent call last):
File "" , line 1, in <module>
AttributeError: 'dict' object has no attribute 'sort'
sorted()
是产生一个新的对象。sorted(L)
返回一个排序后的L
,不改变原始的L
,sorted()
适用于任何可迭代容器。
>>> dict1 = {'test1':1, 'test2':2}
>>> list1 = [2, 1, 3]
>>> print(sorted(dict1))
['test1', 'test2']
>>> print(sorted(list1))
[1, 2, 3]
\quad
\quad
GIL 是 Python 的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行 Python 程序的时候会占用 Python 解释器(加了一把锁即 GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。
\quad
\quad
string 模块用法:
1、将大写的ASCII字符列表和数字组合起来
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
2、string.printable
输出被视为可打印符号的 ASCII 字符组成的字符串。
>>> string.printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
string.printable[:-7]
去除被视为空白符号的 ASCII 字符组成的字符串。
使用python的random模块,使用其中的choice
方法,从给定的字符序列中随机选择字符组合。
>>> import random
>>> import string
>>> "".join(random.choice(string.printable[:-7]) for i in range(8))
这就产生了8位随机密码。
\quad
\quad
python提供了输出原始字符串“r
”的方法。
>>> print('hello\nworld')
hello
world
>>> print(b'hello\nworld')
b'hello\nworld'
>>> print(r'hello\nworld')
hello\nworld
\quad
\quad
any()
和 all()
方法all
:如果存在 0
,Null
,False
返回 False,否则返回 True
;
any
:如果都是 0
,None
,False
时,返回 False
。
例子:
>>> all([1, 2, 3, 0])
False
>>> all([1, 2, 3])
True
>>> any([1, 2, 3])
True
>>> any([0, None, False])
False
\quad
\quad
首先判断是否是整数,再判断是否是一位数字,最后再判断是不是负数。
def reverse_int(x):
if not isinstance(x, int):
return False
if -10 < x < 10:
return x
tmp = str(x)
if tmp[0] != '-':
tmp = tmp[::-1]
return int(tmp)
else:
tmp = tmp[1:][::-1]
x = int(tmp)
return -x
>>> reverse_int(-23837)
-73832
\quad
\quad
函数式编程是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。由于 Python 允许使用变量,因此,Python 不是纯函数式编程语言。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
函数作为返回值例子:
def sum(*args):
def inner_sum():
tmp = 0
for i in args:
tmp += i
return tmp
return inner_sum
>>> mysum = sum(2, 4, 6)
>>> print(type(mysum))
<class 'function'>
>>> mysum()
12
\quad
\quad
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
闭包特点:
详细看链接:《Python面试题目:[lambda x: x*i for i in range(4)]》
\quad
\quad
装饰器是一种特殊的闭包,就是在闭包的基础上传递了一个函数,然后覆盖原来函数的执行入口,以后调用这个函数的时候,就可以额外实现一些功能了。
一个打印 log 的例子:
import time
def log(func):
def inner_log(*args, **kw):
print("Call: {}".format(func.__name__))
return func(*args, **kw)
return inner_log
@log
def timer():
print(time.time())
timer()
# Call: timer
# 1560171403.5128365
本质上,decorator就是一个返回函数的高阶函数。
详细看链接:《Python进阶系列》八:装饰器的用法
\quad
\quad
协程的优点:
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
其他一些重要的点:
协程只有和异步IO结合起来才能发挥出最大的威力。
\quad
\quad
斐波那契数列:又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:
F
(
1
)
=
1
,
F
(
2
)
=
1
,
F
(
n
)
=
F
(
n
−
1
)
+
F
(
n
−
2
)
(
n
≥
2
,
n
∈
N
∗
)
F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n\geq2,n\in N*)
F(1)=1,F(2)=1,F(n)=F(n−1)+F(n−2)(n≥2,n∈N∗)
生成器法:
def fib(n):
if n == 0:
return False
if not isinstance(n, int) or (abs(n) != n):
return False
a, b = 0, 1
while n:
a, b = b, a + b
n -= 1
yield a
>>> fib(10)
<generator object fib at 0x000001AF2F2395C8>
>>> [i for i in fib(10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
递归法:
def fib(n):
if n == 0:
return False
if not isinstance(n, int) or (n < 0):
return False
if n <= 1:
return 1
return fib(n - 1) + fib(n - 2)
>>> fib(10)
55
>>> [fib(i) for i in range(1, 11)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
\quad
\quad
>>> import re
>>> str1 = "hello world:luobo dazahui"
>>> re.split(r":| ", str1)
['hello', 'world', 'luobo', 'dazahui']
\quad
\quad
yield
是用来生成迭代器的语法,在函数中,如果包含了 yield
,那么这个函数就是一个迭代器。当代码执行至 yield
时,就会中断代码执行,直到程序调用 next()
函数时,才会在上次 yield
的地方继续执行。
详情见:《Python中的迭代器和生成器》 。
\quad
\quad
def Bubble(data, reversed):
for i in range(len(data) - 1):
for j in range(len(data) - i - 1):
if data[j] > data[j + 1]:
data[j], data[j + 1] = data[j + 1], data[j]
if reversed:
data.reverse()
return data
>>> Bubble(list1, True)
[11, 9, 8, 5, 3, 2]
>>> Bubble(list1, False)
[2, 3, 5, 8, 9, 11]
\quad
\quad
def partition(arr, low, high):
pivot = arr[low]
while low < high:
while low < high and arr[high] >= pivot:
high -= 1
arr[low], arr[high] = arr[high], arr[low]
while low < high and arr[low] <= pivot:
low += 1
arr[low], arr[high] = arr[high], arr[low]
return low
def quickSort(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quickSort(arr, low, pi - 1)
quickSort(arr, pi + 1, high)
>>> list1 = [8, 5, 1, 3, 2, 10, 11, 4, 12, 20]
>>> quickSort(list1, 0, len(list1) - 1)
>>> list1
[1, 2, 3, 4, 5, 8, 10, 11, 12, 20]
\quad
\quad
该库是发起 HTTP 请求的强大类库,调用简单,功能强大。
>>> import requests
>>> url = "http://www.baidu.com"
>>> response = requests.get(url) # 获得请求
>>> response.encoding = "utf-8" # 改变其编码
>>> html = response.text # 获得网页内容
>>> binary_content = response.content # 获得二进制数据
>>> raw = requests.get(url, stream=True) # 获得原始响应内容
>>> headers = {'user-agent': 'my-test/0.1.1'} # 定制请求头
>>> r = requests.get(url, headers=headers)
>>> cookies = {"cookie": "# your cookie"} # cookie的使用
>>> r = requests.get(url, cookies=cookies)
\quad
\quad
方法一:
key
排好序,然后使用zip()
函数将两个字典对应的元素打包成元组。比较对应的元素的value
是否相等;zip()
函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组。>>> file_text2 = '{"name":"john","age":22,"sex":"woman","address":"USA"}'
>>> file_text1 = '{"name":"john","age":22,"sex":"man","address":"USA"}'
>>> dict1 = json.loads(file_text1)
>>> dict2 = json.loads(file_text2)
>>> for s1, s2 in zip(sorted(dict1), sorted(dict2)):
if str(dict1[s1]) != str(dict2[s2]):
print(s1 + ":" + dict1[s1] + "!=" + s2 + ":" + dict2[s2])
sex:man!=sex:woman
方法二:引入第三方模块jsonpatch
。
>>> import jsonpatch
>>> src = {'numbers': [1, 3, 4, 8], 'foo': 'bar'}
>>> dst = {'foo': 'bar', 'numbers': [1, 3, 8]}
>>> patch = jsonpatch.JsonPatch.from_diff(src, dst)
>>> print(patch)
[{"op": "remove", "path": "/numbers/2"}]
说明:两个json
对象,src
要变成dst
,需要移除numbers
下索引是2
的元素。
>>> src = {'numbers': [1, 3, 4, 8], 'foo': 'bar'}
>>> dst = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
>>> patch = jsonpatch.JsonPatch.from_diff(src, dst)
>>> print(patch)
[]
若相等的话直接返回空列表。
有了这个模块,判断json串是否相等不用遍历内部属性,直接判断
patch
长度即可。
\quad
\quad
def forinput():
input_text = input()
print("your input text is: ", input_text)
>>> forinput()
>? 2
your input text is: 2
\quad
\quad
enumerate()
的用法enumerate()
是 Python 内置函数。enumerate()
函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在for
循环当中。
它允许我们遍历数据并自动计数,用法如下:
for counter, value in enumerate(some_list):
print(counter, value)
不只如此,enumerate()
也接受一些可选参数,这使它更有用。
>>> my_list = ['apple', 'banana', 'grapes', 'pear']
>>> for c, value in enumerate(my_list, 1):
... print(c, value)
...
1 apple
2 banana
3 grapes
4 pear
上面这个可选参数允许我们定制从哪个数字开始枚举。
此外,还可以用来创建包含索引的元组列表, 例如:
>>> my_list = ['apple', 'banana', 'grapes', 'pear']
>>> counter_list = list(enumerate(my_list, 1))
>>> print(counter_list)
[(1, 'apple'), (2, 'banana'), (3, 'grapes'), (4, 'pear')]
\quad
\quad
pass
是空语句,是为了保持程序结构的完整性。pass
不做任何事情,一般用做占位语句。
def forpass(n):
if n == 1:
pass
else:
print('not 1')
>>> forpass(1)
\quad
\quad
>>> import re
>>> email_list= ["test01@163.com","test02@163.123", ".test03g@qq.com", "test04@gmail.com" ]
>>> for email in email_list:
ret = re.match("[\w]{4,20}@(.*)\.com$", email)
if ret:
print("%s 是符合规定的邮件地址,匹配后结果是:%s" % (email, ret.group()))
else:
print("%s 不符合要求" % email)
test01@163.com 是符合规定的邮件地址,匹配后结果是:test01@163.com
test02@163.123 不符合要求
.test03g@qq.com 不符合要求
test04@gmail.com 是符合规定的邮件地址,匹配后结果是:test04@gmail.com
\quad
\quad
>>> str2 = 'werrQWSDdiWuW'
>>> counter = 0
>>> for i in str2:
if i.isupper():
counter += 1
>>> counter
6
\quad
\quad
普通序列化:
>>> import json
>>> dict1 = {'name': '萝卜', 'age': 18}
>>> dict1_new = json.dumps(dict1)
>>> print(dict1_new)
{"name": "\u841d\u535c", "age": 18}
保留中文:
>>> import json
>>> dict1 = {'name': '萝卜', 'age': 18}
>>> dict1_new = json.dumps(dict1, ensure_ascii=False)
>>> print(dict1_new)
{"name": "萝卜", "age": 18}
\quad
\quad
一个类继承自另一个类,也可以说是一个孩子类/派生类/子类,继承自父类/基类/超类,同时获取所有的类成员(属性和方法)。继承使我们可以重用代码,并且还可以更方便地创建和维护代码。
Python 支持以下类型的继承:
\quad
\quad
猴子补丁是指在运行时动态修改类和模块。
猴子补丁主要有以下几个用处:
详细看链接:《Python进阶系列》十七:详解Python中的猴子补丁——允许在运行时更改对象的行为
\quad
\quad
help()
函数和 dir()
函数help()
函数返回帮助文档和参数说明
>>> help(dict)
Help on class dict in module builtins:
class dict(object)
| dict() -> new empty dictionary
| dict(mapping) -> new dictionary initialized from a mapping object's
| (key, value) pairs
| dict(iterable) -> new dictionary initialized as if via:
| d = {}
| for k, v in iterable:
| d[k] = v
| dict(**kwargs) -> new dictionary initialized with the name=value pairs
| in the keyword argument list. For example: dict(one=1, two=2)
|
| Methods defined here:
......
dir()
函数返回对象中的所有成员 (任何类型)
>>> dir(dict)
['__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
......
\quad
\quad
//
,%
和**
运算符//
运算符执行地板除法,返回结果的整数部分 (向下取整)。%
是取模符号,返回除法后的余数。**
符号表示取幂。 a**b
返回 a
的b
次方。
\quad
\quad
使用raise
:
def test_raise(n):
if not isinstance(n, int):
raise Exception("not a int type")
else:
print("good")
>>> test_raise(8.9)
Traceback (most recent call last):
File "D:\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "" , line 1, in <module>
test_raise(8.9)
File "" , line 3, in test_raise
raise Exception("not a int type")
Exception: not a int type
\quad
\quad
>>> tuple1 = (1, 2, 3, 4)
>>> list1 = list(tuple1)
>>> print(list1)
>>> tuple2 = tuple(list1)
>>> print(tuple2)
\quad
\quad
Python 的断言就是检测一个条件,如果条件为真,它什么都不做;反之它触发一个带可选错误信息的 AssertionError
。
def testassert(n):
assert n == 2, "n is not 2"
print("n is 2")
>>> testassert(2)
n is 2
>>> testassert(3)
Traceback (most recent call last):
File "D:\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3331, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "" , line 1, in <module>
testassert(3)
File "" , line 2, in testassert
assert n == 2, "n is not 2"
AssertionError: n is not 2
\quad
\quad
同步异步指的是调用者与被调用者之间的关系。
阻塞非阻塞是线程或进程之间的关系。
\quad
\quad
Python 中的序列是有索引的,它由正数和负数组成。正的数字使用’0’作为第一个索引,‘1’作为第二个索引,以此类推。负数的索引从’-1’开始,表示序列中的最后一个索引,’ - 2’作为倒数第二个索引,依次类推。
\quad
\quad
不是的,那些具有对象循环引用或者全局命名空间引用的变量,在 Python 退出时往往不会被释放,
另外不会释放 C 库保留的部分内容。
\quad
\quad
\quad
\quad
>>> f = open('test.txt', 'w')
>>> f.close()
>>> os.listdir()
['.idea',
'test.txt',
'__pycache__']
>>> os.remove('test.txt')
>>> os.listdir()
['.idea',
'__pycache__']
\quad
\quad
logging 模块是 Python 内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比 print,具备如下优点:
简单配置:
>>> import logging
>>> logging.debug("debug log")
>>> logging.info("info log")
>>> logging.warning("warning log")
>>> logging.error("error log")
>>> logging.critical("critica log")
默认情况下,只显示了大于等于WARNING级别的日志。logging.basicConfig()
函数调整日志级别、输出格式等。
详细看链接:《Python进阶系列》九:别再用print来打印了,试试logging模块
\quad
\quad
>>> from collections import Counter
>>> str1 = "nihsasehndciswemeotpxc"
>>> print(Counter(str1))
Counter({'s': 3, 'e': 3, 'n': 2, 'i': 2, 'h': 2, 'c': 2, 'a': 1, 'd': 1, 'w': 1, 'm': 1, 'o': 1, 't': 1, 'p': 1, 'x': 1})
\quad
\quad
re.compile
是将正则表达式编译成一个对象,加快速度,并重复使用。
\quad
\quad
try..except..else
没有捕获到异常,执行 else
语句try..except..finally
不管是否捕获到异常,都执行 finally
语句
\quad
\quad
第一种方法:使用切片
>>> list1 = list(range(10))
>>> list1[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
第二种方法:使用reverse()
>>> list1 = list(range(10))
>>> list1.reverse()
>>> list1
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
需要注意的是:这两种方法都可以反转列表,但内置函数 reverse()
会更改原始列表,而切片方法会创建一个新列表。内置函数 reverse()
比列表切片方法更快!
\quad
\quad
使用 re
正则替换:
>>> import re
>>> str1 = '我是周萝卜,今年18岁'
>>> re.sub(r"\d+", "20", str1)
'我是周萝卜,今年20岁'
\quad
\quad
现要处理一个大小为10G的文件,但是内存只有4G,如果在只修改get_lines 函数而其他代码保持不
变的情况下,应该如何实现?需要考虑的问题都有那些?
def get_lines():
with open('file.txt','rb') as f:
return f.readlines()
if name == ' main ':
for e in get_lines():
process(e) # 处理每一行数据
方法一:readlines()
函数在文件过大时并不适用,应添加参数,限制读取的字节数,并使用生成器。
def get_lines():
l = []
with open('file.txt','rb') as f:
data = f.readlines(60000)
l.append(data)
yield l
方法二:使用mmap
from mmap import mmap
def get_lines(fp):
with open(fp, "r+") as f:
m = mmap(f.fileno(), 0)
tmp = 0
for i, char in enumerate(m):
if char==b"\n":
yield m[tmp:i + 1].decode()
tmp = i + 1
if name ==" main ":
for i in get_lines("fp_some_huge_file"):
print(i)
详细看链接:《Python进阶系列》二十八:mmap模块(处理大文本)
\quad
\quad
import datetime
def dayofyear():
year = input("请输入年份: ")
month = input("请输入月份: ")
day = input("请输入天: ")
date1 = datetime.date(year=int(year), month=int(month), day=int(day))
date2 = datetime.date(year=int(year), month=1, day=1)
return (date1 - date2).days + 1
>>> dayofyear()
请输入年份: >? 2022
请输入月份: >? 5
请输入天: >? 23
143
\quad
\quad
根据字典按值排序
现有字典d= {'a':24,'g':52,'i':12,'k':33}
请按value
值进行排序?
>>> d = {'a': 24, 'g': 52, 'i': 12, 'k': 33}
>>> d.items()
dict_items([('a', 24), ('g', 52), ('i', 12), ('k', 33)])
>>> sorted(d.items(), key=lambda x: x[1])
[('i', 12), ('a', 24), ('k', 33), ('g', 52)]
x[0]
代表用key
进行排序;x[1]
代表用value
进行排序。
请按alist中元素的age由大到小排序
>>> alist = [{'name': 'a', 'age': 20}, {'name': 'b', 'age': 30}, {'name': 'c', 'age': 25}]
>>> sorted(alist, key=lambda x:x['age'], reverse=True)
[{'name': 'b', 'age': 30}, {'name': 'c', 'age': 25}, {'name': 'a', 'age': 20}]
列表内,字典按照 value 大小排序
>>> list1 = [{'name': 'guanyu', 'age':29},
... {'name': 'zhangfei', 'age': 28},
... {'name': 'liubei', 'age':31}]
>>> sorted(list1, key=lambda x:x['age'])
[{'name': 'zhangfei', 'age': 28}, {'name': 'guanyu', 'age': 29}, {'name': 'liubei', 'age': 31}]
>>> sorted(list1, key=lambda x:x['name'])
[{'name': 'guanyu', 'age': 29}, {'name': 'liubei', 'age': 31}, {'name': 'zhangfei', 'age': 28}]
\quad
\quad
>>> k = "k:1|k1:2|k2:3|k3:4"
>>> dict1 = {}
>>> for items in k.split("|"):
... key, value = items.split(":")
... dict1[key] = value
字典推导式:
>>> {k:v for items in k.split("|") for k, v in (items.split(":"), )}
{'k': '1', 'k1': '2', 'k2': '3', 'k3': '4'}
\quad
\quad
list = ['a','b','c','d','e']
print(list[10:])
代码将输出[]
,不会产生IndexError
错误,就像所期望的那样,尝试用超出成员的个数的index来获取某个列表的成员。例如,尝试获取list[10]
和之后的成员,会导致IndexError
。然而,尝试获取列表的切片,开始的index
超过了成员个数不会产生IndexError
,而是仅仅返回一个空列表。这成为特别让人恶心的疑难杂症,因为运行的时候没有错误产生,导致Bug很难被追踪到。