本文整理和解答了关于python的一些常见问题,由于水平有限,难免出现错漏,敬请批评改正。
import pickle # 使用pickle模块将数据对象保存到文件 data1 = {'a': [1, 2.0, 3, 4+6j], 'b': ('string', u'Unicode string'), 'c': None} data2 = (1,2,3) selfref_list = [1, 2, 3] selfref_list.append(selfref_list) output = open('data.pkl', 'wb') # Pickle字典使用协议0 pickle.dump(data1, output) # Pickle使用协议1 pickle.dump(data2, output) # 使用可用的最高协议Pickle列表 pickle.dump(selfref_list, output, -1) output.close() #使用pickle模块从文件中重构python对象 pkl_file = open('data.pkl', 'rb') data1 = pickle.load(pkl_file) print(data1) data2 = pickle.load(pkl_file) print(data2) data3 = pickle.load(pkl_file) print(data3) pkl_file.close()
{'a': [1, 2.0, 3, (4+6j)], 'b': ('string', 'Unicode string'), 'c': None} (1, 2, 3) [1, 2, 3, [...]]
def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell") a_function_requiring_decoration() # 现在a_function_requiring_decoration被wrapTheFunction()包装了 a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) print('装饰后:') a_function_requiring_decoration()
I am the function which needs some decoration to remove my foul smell 装饰后: I am doing some boring work before executing a_func() I am the function which needs some decoration to remove my foul smell I am doing some boring work after executing a_func()
上面,这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为。现在你也许疑惑,我们在代码里并没有使用 @ 符号?那只是一个简短的方式来生成一个被装饰的函数。这里是我们如何使用 @ 来运行之前的代码:
from functools import wraps def decorator_name(f): @wraps(f) def decorated(*args, **kwargs): if not can_run: return "Function will not run" return f(*args, **kwargs) return decorated @decorator_name # 装饰器,相当于decorator_name(func) def func(): return("Function is running") can_run = True print(func())# Function is running can_run = False print(func()) # Function will not run
Function is running Function will not run
注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中。
日志是装饰器运用的另一个亮点。例如:
from functools import wraps def logit(func): @wraps(func) def with_logging(*args, **kwargs): print(func.__name__ + " was called") return func(*args, **kwargs) return with_logging @logit # 装饰器,相当于logit(addition_func) def addition_func(x): return x + x result = addition_func(4)# addition_func was called print(result)
addition_func was called 8
hash((0,1,2)) # 元组可以被哈希,得到对应的哈希值
1267305975155491464
Python 中的一切都是类,所有的变量都是一个对象的引用。引用的值是由函数确定的,因此无法被改变。但是如果一个对象是可以被修改的,你可以改动对象。
可更改(mutable)与不可更改(immutable)对象
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
def change(a): print(id(a)) # 指向的是同一个对象 a=10 print(id(a)) # 一个新对象 a=1 print(id(a)) change(a) # 传不可变对象实例
1359458496 1359458496 1359458784
可以看见在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。
可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。例如:
# 可写函数说明 def change2(mylist): "修改传入的列表" mylist.append([1,2,3,4]) print ("函数内取值: ", mylist) print("函数内id(mylist):",id(mylist)) return # 调用change2函数 mylist = [10,20,30] print("函数外id(mylist):",id(mylist)) change2(mylist) print ("函数外取值: ", mylist)
函数外id(mylist): 2594297892744 函数内取值: [10, 20, 30, [1, 2, 3, 4]] 函数内id(mylist): 2594297892744 函数外取值: [10, 20, 30, [1, 2, 3, 4]]
它们是可以轻松创建字典和列表的语法结构。
列表推导式 - 计算 30 以内可以被 3 整除的整数:
multiples = [i for i in range(30) if i % 3 == 0] print(multiples)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
dic = {x: x**2 for x in (2, 4, 6)} print(dic) print(type(dic))
{2: 4, 4: 16, 6: 36} <class 'dict'>
# var1 是全局名称 var1 = 5 def some_func(): # var2 是局部名称 var2 = 6 def some_inner_func(): # var3 是内嵌的局部名称 var3 = 7
x = lambda a : a + 10 print(x(5)) # x(a)
15
# 可写函数说明 sum = lambda arg1, arg2: arg1 + arg2 # 调用sum函数 print ("相加后的值为 : ", sum( 10, 20 )) print ("相加后的值为 : ", sum( 20, 20 ))
相加后的值为 : 30 相加后的值为 : 40
def myfunc(n): return lambda a : a * n mydoubler = myfunc(2) mytripler = myfunc(3) print(mydoubler(11)) print(mytripler(11))
22 33
# 输出 Python 的每个字母 for letter in 'Python': if letter == 'h': pass print ('这是 pass 块') print ('当前字母 :', letter) print ("END!")
当前字母 : P 当前字母 : y 当前字母 : t 这是 pass 块 当前字母 : h 当前字母 : o 当前字母 : n END!
while False: pass
import unittest class TestStatisticalFunctions(unittest.TestCase): def test_average(self): self.assertEqual(average([20, 30, 70]), 40.0) self.assertEqual(round(average([1, 5, 7]), 1), 4.3) self.assertRaises(ZeroDivisionError, average, []) self.assertRaises(TypeError, average, 20, 30, 70) unittest.main() # 从命令行调用将调用所有测试
E ====================================================================== ERROR: C:\Users\TFX\AppData\Roaming\jupyter\runtime\kernel-1e1a7ebb-89d6-4e47-9989-8c6a327199db (unittest.loader._FailedTest) ---------------------------------------------------------------------- AttributeError: module '__main__' has no attribute 'C:\Users\TFX\AppData\Roaming\jupyter\runtime\kernel-1e1a7ebb-89d6-4e47-9989-8c6a327199db' ---------------------------------------------------------------------- Ran 1 test in 0.001s FAILED (errors=1) An exception has occurred, use %tb to see the full traceback. SystemExit: True E:\Users\TFX\Anaconda3\envs\tensorflow24\lib\site-packages\IPython\core\interactiveshell.py:3351: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
myslice = slice(5) # 设置截取5个元素的切片 print(myslice) arr = range(10) print(arr) print(arr[myslice])# 截取 5 个元素
slice(None, 5, None) range(0, 10) range(0, 5)
# 创建一个迭代器 class MyNumbers: ''' __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。 __next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。 创建一个返回数字的迭代器,初始值为 1,逐步递增 1: ''' def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 1 return x myclass = MyNumbers() myiter = iter(myclass) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter)) print(next(myiter))
1 2 3 4 5
class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import copy a = [1,2,3] b = a c = a.copy() d = copy.deepcopy(a) print("id(a)",id(a)) print("id(b)",id(b)) print("id(c)",id(c)) print("id(d)",id(d))
id(a) 2594298381064 id(b) 2594298381064 id(c) 2594298155144 id(d) 2594298124040
num = 1 print(str(num)) print(oct(num)) print(hex(num))
1 0o1 0x1
对象的引用计数机制
垃圾回收
内存池机制
a=lambda x,y:x+y a(3,11)# lambda(3,11):3+11,此表达式只是为了方便说明,语法是错误的
14
a = (1,2,3) b = [1,2,3] print(a,b) print(list(a),tuple(b))
(1, 2, 3) [1, 2, 3] [1, 2, 3] (1, 2, 3)
a=[1,2,4,2,4,5,6,5,7,8,9,0,10,2,4,6] set(a)
{0, 1, 2, 4, 5, 6, 7, 8, 9, 10}
a=[1,2,4,2,4,5,6,5,7,8,9,0,10,2,4,6] b={} b=b.fromkeys(a) list(b.keys())
[1, 2, 4, 5, 6, 7, 8, 9, 0, 10]
a=[1,2,4,2,4,5,6,5,7,8,9,0,10,2,4,6] a.sort() last=a[-1] for i in range(len(a)-2,-1,-1): if last==a[i]: del a[i] else: last=a[i] print(a)
[0, 1, 2, 4, 5, 6, 7, 8, 9, 10]
for i in range(10): print(i,end=" ")
0 1 2 3 4 5 6 7 8 9
import re p=re.compile('blue|white|red') print(p.sub('colour','blue socks and red shoes')) print(p.sub('colour','blue socks and red shoes',count=1))
colour socks and colour shoes colour socks and red shoes
import re p=re.compile('blue|white|red') print(p.subn('colour','blue socks and red shoes')) print(p.subn('colour','blue socks and red shoes',count=1))
('colour socks and colour shoes', 2) ('colour socks and red shoes', 1)
import re print(re.match('super', 'superstition').span()) print(re.match('super', 'insuperable')) print(re.search('super', 'superstition').span()) print(re.search('super', 'insuperable').span())
(0, 5) None (0, 5) (2, 7)
import re s = '<html><head><title>Title</title>' print(re.match('<.*>', s).group())
<html><head><title>Title</title>
import re s = '<html><head><title>Title</title>' print(re.match('<.*?>', s).group())
<html>
import random random.randint(0,10)
10
random.randrange(0,10,2)
2
random.random()
0.3569320956561295
random.uniform(0,1)
0.5371507256725325
def f(): global a
s1 = 'Let\'s go' s2 = "Let's go" s3 = 'I realy like "python"!' print(s1,'|',s2,'|',s3)
Let's go | Let's go | I realy like "python"!
注:自定义 new() 方法一般并不常用,而且容易与 init() 相混淆。实际上这两个方法也确实相似,比如他们都是在创建类的实例时会被默认调用的方法,而且创建实例时传入的参数也都会传到这两个方法里。但他们也有很重要的区别,比如对 new() 的调用比 init() 要早,new() 有返回值,init() 没有。
真正完成构造实例工作的是 new() 方法,调用它需要一个默认参数 cls,就是将要返回的这个实例所属的类(MyClass)。一般情况下因为 new() 极少被覆盖,最终调用的都是 object.new()。这个时候我们的实例已经被创建了,就可以当做 self 参数传给 init() 了,init() 做的工作其实仅是初始化一些属性值之类的,与严格意义下的“构造”实例无关。
class Myclass(object):# 创建一个音乐播放器 def __init__(self): # 初始化方法;对这个实例化对象再次加工 print("初始化") def __new__(cls): print("创建对象,分配空间") # 创建对象时,new方法会被自动调 instance = super().__new__(cls) # 为对象分配空间 # 创建对象 my = Myclass() print(my)
创建对象,分配空间 None
class Myclass(object):# 创建一个音乐播放器 def __init__(self): # 初始化方法;对这个实例化对象再次加工 print("初始化") def __new__(cls): print("创建对象,分配空间") # 创建对象时,new方法会被自动调 instance = super().__new__(cls) # 为对象分配空间 return instance # 返回对象的引用,必须的有这个返回,不然self找不到对象 # 创建对象 my = Myclass() print(my)
创建对象,分配空间 初始化 <__main__.Myclass object at 0x0000025C084952B0>
注:
- self:self代表自身的意思,就是代表这个类对象自身的意思不代表类本身,创建对象后self就代表这个对象自身。
- cls:cls代表这个类,这个类的所有属性、方法都在里面。
class SeftAndCls(object):# class(父类) a = 'a' @staticmethod # 静态方法(装饰器) def f1(): return SeftAndCls.a # 正常 def f2(self): return 'f2' @classmethod # 类方法(装饰器) def f3(cls, name): print('f3函数输出:') print('类.类属性调用一个类属性:',SeftAndCls.a) # 使用类.类属性调用一个类属性 print('类.类方法调用一个类方法:',cls().f2()) # 使用类.类方法调用一个类方法 newobj = SeftAndCls() print('调用类的静态方法:', SeftAndCls.f1()) print('正常调用:', newobj.f2()) print('直接调用类属性', SeftAndCls.a) SeftAndCls.f3('World')
调用类的静态方法: a 正常调用: f2 直接调用类属性 a f3函数输出: 类.类属性调用一个类属性: a 类.类方法调用一个类方法: f2