自己对python一些不熟悉的地方的一些补充
1. 位运算符
&
:按位与 |
:按位或 ^
:按位异或 ~
:按位取反 <<
>>
:左移(高位丢弃,低位补0),右移操作
2. 六大数据结构
2.1 number
int, float, bool, complex(复数)
2.2 string
有一些常见的内置函数:`find`,`rfind`,`index`,`count`
mystr = 'aa hello world'
mystr.find('ihello', 0, 10) # -1 [0,10)寻找范围
mystr.find('hello', 0, 10) # 3 找到匹配的索引初始位置
mystr.rfind('hello') # 3 从右开始数,找到匹配的索引初始位置
# index 与find功能一致,但是当找不到的时候 index会报错,并不会返回-1
myStr.count('l',0,10) # 统计某个词语出现的次数, [0,10)子串
2.3 list
`append`,`extend`,`insert`,`del`,`pop`,`remove`,`sort`
# 所有这些函数都会直接修改a的值
a = [1,2,3]
a.append(4) # 在后面添加值
a.extend([5,6]) # 合并另一个list
a.insert(0,7) # 在0位置插入7
a.pop() # 弹出并返回最后一个值
a.remove(1) # 移除元素1 如果有多个首先删除index小的
a.sort() # 排序 默认从小到大 可以通过添加reverse=True从大到小
del a # 删除a所占的内存,访问a会报undifined错误 del(a)是一样的功能
2.4 dict
get
,del
,clear
info = {'name':'班⻓', 'id':100, 'sex':'f', 'address':'地球亚洲中国北京'}
age = info.get('age')#'age'键不存在,所以age为None
# 若info中不存在'age'这个键,就返回默认值18
age = info.get('age', 18)
# 删除元素
del info['name']
del(info['name'])
# 删除整个字典,info被销毁了
del info
del(info)
info.clear() #只是清空info中的元素 info还没有被销毁
- tuple
tuple与list类似,不同的是tuple的元素不能修改,元组使用小括号,list使用方括号
a = (1,2,3)
b = (4,5,6)
a * 2 # 返回的是(1,2,3,1,2,3) 相当于复制内容
a + b # 返回的是(1,2,3,4,5,6), 如果是两个list也是合并操作
- set
add
,update
,remove
#1.添加add
s4 = set([1,2,3,4,5])
#add
s4.add(3)
s4.add((1,2,3)) # {1, 2, 3, 4, 5, (1, 2, 3)}
# s4.add([1,2,3]) # 注意这里的参数不能是一个list 和dict
# s4.add({1:'hello'})
s5 = set([1,2,3,4,5])
s5.update([6,7,8]) # 1,2,3,4,5,6,7,8 #通过update向set中添加元素
s6 = set([1,2,3,4,5])
s6.remove(3) # 1,2,4,5
#5.交集(&)和并集(|)
s8 = set([1,2,3,4,5])
s9 = set([2,3,4,5,6])
#交集
# a = s8 & s9 # 2,3,4,5
#并集
a = s8 | s9 # 1,2,3,4,5,6
3. 函数
3.1 不定长参数
#案例:
def fun(a, b, *args, **kwargs):
"""可变参数演示示例"""
print ("a =", a)
print ("b =", b)
print ("args =", args)
print ("kwargs: ")
for key, value in kwargs.items():
print (key, "=", value) #⽅式1
fun(1, 2, 3, 4, 5, m=6, n=7, p=8)
#⽅式2
c = (3, 4, 5) d = {"m":6, "n":7, "p":8}
fun(1, 2, *c, **d)
#⽅式3
fun(1, 2, c, d)
3.2 lambda表达式
语法格式:lambda 参数1,参数2,……,参数n:expression
sum = lambda arg1, arg2: arg1 + arg2
#调⽤sum函数
print ("Value of total : ", sum( 10, 20 ))
print ("Value of total : ", sum( 20, 20 ))
4. 面向对象
4.1 定义类的私有属性
在类的属性前面添加两个下划线__
,私有属性只能通过方法访问,不能通过对象直接访问
#注意点:设置私有属性
class Animal(object):
def __init__(self, name='动物', color='⽩⾊'):
self.__name = name
self.color = color
def __test(self):
print(self.__name)
print(self.color)
def test(self):
print(self.__name)
print(self.color)
class Dog(Animal):
def dogTest1(self):
#print(self.__name) #不能访问到⽗类的私有属性
print(self.color)
def dogTest2(self):
#self.__test() #不能访问⽗类中的私有⽅法
self.test()
A = Animal()
#print(A.__name) #程序出现异常,不能访问私有属性
print(A.color)
#A.__test() #程序出现异常,不能访问私有⽅法
A.test()
print("------分割线-----")
D = Dog(name = "⼩花狗", color = "⻩⾊")
D.dogTest1()
D.dogTest2()
4.2 多继承
#Python中多继承的格式如下:
# 定义⼀个⽗类
class A:
def printA(self):
print('----A----')
# 定义⼀个⽗类
class B:
def printB(self):
print('----B----')
# 定义⼀个⼦类,继承⾃A、B
class C(A,B):
def printC(self):
print('----C----')
obj_C = C()
obj_C.printA()
obj_C.printB()
4.3 常见的方法类型
- 实例方法
- 静态方法
'''
定义:
需要通过修饰器@staticmethod来进⾏修饰,静态⽅法不需要多定义参数
案例:
'''
class People(object):
country = 'china'
@staticmethod
#静态⽅法
def getCountry():
return People.country
print(People.getCountry())
- 类方法
'''
是类对象所拥有的⽅法,需要⽤修饰器@classmethod来标识其为类⽅法,
对于类⽅法,第⼀个参数必须是类对象,⼀般以cls作为第⼀个参数(
当然可以⽤其他名称的变量作为其第⼀个参数,
但是⼤部分⼈都习惯以'cls'作为第⼀个参数的名字,就最好⽤'cls'了),
能够通过实例对象和类对象去访问。
案例:
'''
class People(object):
country = 'china'
#类⽅法,⽤classmethod来进⾏修饰
@classmethod
def getCountry(cls):
return cls.country
p = People()
print(p.getCountry()) #可以⽤过实例对象引⽤
print(People.getCountry()) #可以通过类对象引⽤
'''
类⽅法还有⼀个⽤途就是可以对类属性进⾏修改:
案例:
'''
class People(object):
country = 'china'
#类⽅法,⽤classmethod来进⾏修饰
@classmethod
def getCountry(cls):
return cls.country
@classmethod
def setCountry(cls,country):
cls.country = country
p = People()
print(p.getCountry()) #可以⽤过实例对象引⽤
print(People.getCountry()) #可以通过类对象引⽤
p.setCountry('japan')
print(p.getCountry())
print(People.getCountry())
5. 文件操作
5.1 文件与文件夹操作
# f = open('test.txt', 'wra') # 这种方式会报错 w r a 只能拥有一个 当需要读写模式同时存在,可以使用 a+ w+ r+ 的模式
f = open('test.txt', 'r+')
content = f.read(5) #读取前5个字符
print(content)
f.seek(0) # 由于read直接读到了 文件中间某个位置 我们需要使用seek将指针跳至最前面
f.read() # 读取所有内容 有\n符
f.seek(0)
f.readlines() # 读取所有内容,返回一个list,每个元素为每一行 包含换行符
f.write('yes') # 向文件中写入内容
position = f.tell() # 通过tell函数来获取目前光标开始的位置
f.seek(5, 0) # 移动光标指针位置
5.2 seek函数讲解
f.seek(p, 0) 或 f.seek§
将文件读取指针移动到文件的第p个字节处,表示绝对位置。f.seek(0)移动到文件头位置。
f.seek(p, 1)
在当前位置的基础上,将文件读取指针移动p个字节,表示相对位置。
f.seek(p, 2)
在文件尾的基础上,将文件读取指针移动p个字节,表示相对位置。f.seek(0, 2)移动到文件尾位置。
5.3 文件重命名
import os
os.rename('1.txt', '2.txt')
5.4 文件删除
import os
os.remove('1.txt')
5.5 文件夹操作
import os
- 创建文件夹
os.mkdir('dir_name')
- 获取当前目录
os.getcwd()
- 获取目录列表
os.listdir(dir_name)
6. 异常处理
try:
print('-----test--1---')
open('123.txt','r')
print('-----test--2---')
except IOError:
pass
finally:
print('finally')
6.1 自定义异常
class ShortInputException(Exception):
def __init__(self, length, atleast):
#super().__init__()
self.length = length
self.atleast = atleast
try:
s = input('请输⼊ --> ')
print(s)
if len(s) < 3:
# raise引发⼀个你定义的异常
raise ShortInputException(len(s), 3)
except ShortInputException as result:#x这个变量被绑定到了错误的实例
print('ShortInputException: 输⼊的⻓度是 %d,⻓度⾄少应是 %d'%
(result.length, result.atleast))
else:
print('没有异常发⽣.')
7. 高阶函数使用
7.1 map
map函数可以理解会对可迭代对象中的每一个元素进行函数操作,第一个参数可以使lambda表达式,也可以是函数名
a=(1,2,3,4,5)
b=[1,2,3,4,5]
c="zhangkang"
la=map(str,a)
lb=map(lambda x: x+1,b)
lc=map(str,c)
print(list(la))
print(list(lb))
print(list(lc))
7.2 reduce
reduce函数会对参数序列中的元素进行累积操作
reduce有三个参数:
- function:必需参数
- sequence:必需参数(可迭代对象)
- init val:初始值,可选参数
reduce的工作过程:
- 首先把前两个元素传给 函数参数,函数加工值
- 然后把得到的结果和第三个元素作为两个参数传递给函数
- 函数加工之后得到的结果又和第四个元素作为两个参数传给函数参数,以此类推
注:如果传入了init值,那么首先传的就不是sequence的第一个和第二个元素,而是init值和第一个元素,经过这样的累积计算之后,合并序列到一个单一返回值
from functools import reduce
def add(x,y):
return x + y
def my(x, y):
return 2 * x * y
print (reduce(my, [2,3,4,5]))#960
print (reduce(add, range(1, 101)))#5050
练习
#练习:获取每个词出现的次数(以空格分割)
from functools import reduce
aa=str="an apple a banana three apple a desk"
list1=str.split(' ')
def fun(x,y):
if y in x:
x[y]=x[y]+1
else:
x[y]=1
return x
result=reduce(fun,list1,{})
print(result) # {'an': 1, 'apple': 2, 'a': 2, 'banana': 1, 'three': 1, 'desk': 1}
7.3 filter
函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表
接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
list1 = [1,2,3,4,5,6,7,8,9,]
#定义筛选函数,保留偶数
def func(num):
if num % 2 == 0:
return True
return False
l = filter(func, list1)
print(list(l))
print(list1)
7.4 sorted
a = [8,6,4,2,1,3,5,7]
print(sorted(a))
sorted函数会返回一个对象,不会对原list进行修改
list.sort()函数没有返回值,会对原数组进行修改
8. 迭代器_生成器_装饰器
8.1 生成器
列表生成式
list(range(0,7))
[x*x for x in range(1,7) if x%2==0]
[a+b for a in '123' for b in '456']
Generator = (x*2 for x in range(5))
print(Generator)
# next()
# temp = next(Generator)
# print(temp)
for temp in Generator:
print(temp)
⽣成器是这样⼀个函数,它记住上⼀次返回时在函数体中的位置。
对⽣成器函数的第⼆次(或第 n 次)调⽤跳转⾄该函数中间,⽽上次调⽤的所有局部变量都保持不变。
⽣成器不仅“记住”了它数据状态;⽣成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
def fib():
a = 0
b = 0
c = 1
while a < 5:
yield c
b, c = c, b+c
a += 1
# print(b)
f = fib()
print(next(f))
print(next(f))
print(next(f))
print(next(f))
⽣成器的特点:
- 节约内存
- 迭代到下⼀次的调⽤时,所使⽤的参数都是第⼀次所保留下的,即是说,在整个所有函数调⽤的参数都是第⼀次所调⽤时保留的,⽽不是新创建的
8.2 迭代器
在可迭代对象进⾏迭代的时候,即⽤for…in…循环语法依次取出数据时,过程是怎样的呢?
我们发现,每迭代⼀次(即在for…in…中每循环⼀次)都会返回对象中的下⼀条数据,⼀直向后读取数据直到迭代了所有数据后结束。
迭代器的特点:
迭代器只能往前不能后退
迭代对象
- ⼀类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
- ⼀类是 generator ,包括⽣成器和带 yield 的generator function。
from collections import Iterable
a = isinstance([], Iterable) # True
b = isinstance({}, Iterable) # True
c = isinstance("abc", Iterable) # True
d = isinstance(100, Iterable) # False
e = isinstance((x for x in range(10)), Iterable)# True
from collections import Iterator
a = isinstance([], Iterator) #False
b = isinstance({}, Iterator) #False
c = isinstance("abc", Iterator) #False
d = isinstance(100, Iterator) #False
e = isinstance((x for x in range(10)), Iterator) #True
#⽣成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator
#把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使⽤ iter() 函数:
from collections import Iterator
a = isinstance(iter([]), Iterator) # True
b =isinstance(iter('abc'), Iterator) # True
- 凡是可作⽤于 for 循环的对象都是 Iterable 类型;
- 凡是可作⽤于 next() 函数的对象都是 Iterator 类型
- 集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter() 函数获得⼀个 Iterator 对象。
作⽤:找到⼀种不依赖索引的迭代取值⽅式
8.3 生成器与迭代器之间的区别
- 迭代器⼀定是⼀个可迭代对象,因为既有可迭代对象的iter⽅法,也有可迭代对象不具备的next⽅法。
- 但反过来,可迭代对象却不⼀定是⼀个迭代器,但能通过iter函数实现。
- 迭代器可以通过next函数访问下⼀个值,也可以和可迭代对象⼀样for循环遍历。
- ⽣成器就是⽤来创建迭代器的函数,使⽤yield关键字,返回⼀个⽣成器。
- ⽣成器既是⼀个可迭代对象,也是⼀个迭代器。
- for循环就是迭代器调⽤next函数依次访问下⼀个值
1、共同点
⽣成器是⼀种特殊的迭代器
2、不同点
- 语法上:⽣成器是通过函数的形式中调⽤ yield 或iter()的形式创建的
迭代器可以通过iter()内置函数创建 - ⽤法上:⽣成器在调⽤next()函数或for循环中,所有过程被执⾏,且返回值。迭代器在调⽤next()函数或for循环中,所有值被返回,没有其他过程或动作。
8.4 装饰器
8.4.1 闭包
返回函数的函数
如果在⼀个函数内部,嵌套了函数,这个内部函数对(⾮全局作⽤域)外部作⽤域的变量进⾏引⽤
那么这个内部函数称为闭包。闭包每次运⾏是能记住引⽤的外部作⽤域的变量的值。
def func1():
print("haha")
def outer(func):
def inner():
print("*" * 20)
func()
return inner
f = outer(func1)
f()
#*******************
#haha
#装饰器的基本使⽤
#定义函数:完成包裹数据
def makeBold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
#定义函数:完成包裹数据
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1())
print(test2())
print(test3())
# <b>hello world-1</b>
# <i>hello world-2</i>
# <b><i>hello world-3</i></b>
装饰器的作用
(1)可以在不对被装饰函数做任何修改的前提下,给被装饰函数附加上⼀些功能。使⽤@makeBold对test1函数进⾏装饰时,我们没有对test1函数的代码做什么的改变,但是被装饰后的test1函数却多了外⾯的b标签。
(2)不改变被装饰函数的调⽤⽅式。在被装饰前,我们通过test1调⽤这个函数,被装饰后,还是通过test1()调⽤这个函数。
(3)代码更加精简。在上⾯代码中,我们只是⽤@makeBold装饰了test1这个个函数,但是如果有多个函数需要添加开始运⾏和结束运⾏的提示功能,如果不⽤装饰器,那么就需要对每⼀个函数进⾏修改,则⼯作量和需要修改的代码量……⽤了装饰器之后,只需要在需要添加这⼀功能的函数前⾯添加@func就可以了。
示例
'''
来个例⼦:
玩游戏
'''
def play_game(name,game):
print('{}正在玩{}'.format(name,game))
#调⽤函数
play_game('张三','王者')
play_game('李四','吃鸡')
def play_game(name,game,clock):
if clock > 22:
print('太晚了不能玩了')
else:
print('{}正在玩{}'.format(name,game))
#调⽤函数
play_game('张三','王者',23)
play_game('李四','吃鸡',18)
#定义⼀个装饰器
def can_play(fn):
#在这个⾥⾯增加两个不定⻓参数就可以,这样下次在改需求的时候是不是就很好操作了
def inner(name,game,*args,**kwargs):
fn(name,game)
return inner
@can_play
def play_game(name,game):
print('{}正在玩{}'.format(name,game))
play_game('张三','王者')
play_game('李四','吃鸡')
def can_play(fn):
def inner(name,game,*args,**kwargs):
if args[0] <= 22:
fn(name,game)
else:
print('太晚了,洗洗睡吧')
return inner
@can_play
def play_game(name,game):
print('{}正在玩{}'.format(name,game))
play_game('张三','王者',18)
play_game('李四','王者',23)
9. 元类
只要使用class关键字,Python解释器都会在执行的时候创建一个对象。
class Test(Object):
pass
这段代码将在内存中创建一个对象,名字就是Test
,但是,它的本质仍然是⼀个对象,于是乎你可以对它做如下的操作:
- 你可以将它赋值给⼀个变量
- 你可以拷⻉它
- 你可以为它增加属性
- 你可以将它作为函数参数进⾏传递
class Test(Object):
pass
test = Test()
print(test)
def echo(o):
print(o)
echo(test)
print(hasattr(Test,"new_attribute"))
# 为类增加新的属性 new_attribute
Test.new_attribute = "foo"
print(hasattr(Test,"new_attribute"))
print(Test.new_attribute)
在Python中,类也是对象,这样的对象就是“类的类”。
9.1 动态创建类
因为类也是对象,你可以在运⾏时动态的创建它们,就像其他任何对象⼀样。
⾸先,你可以在函数中创建类,使⽤class关键字即可
def choose_name(name):
if name == 'foo':
class foo(object):
pass
return foo
else:
class Bar(object):
pass
return Bar
myClass = choose_name('foo')
print(myClass)
print(myClass())
9.2 type创建类
"""
type还有⼀种完全不同的功能,动态的创建类。
type可以接受⼀个类的描述作为参数,然后返回⼀个类。
type可以像这样⼯作:
type(类名, 由⽗类名称组成的元组(针对继承的情况,可以为空),
包含属性的字典(名称和值))
"""
#⽐如下⾯的代码:
class Test(object):
pass
print(Test())
Test2 = type("Test2",(),{})
print(Test2())
class Test2:
pass
9.3 动态添加属性和方法
#type(类名,(⽗类),{key:value})
Foo = type('Foo',(),{'bar':True})
# class Foo(object):
# bar = True
print(Foo)
print(Foo.bar)
# class Foochild(Foo):
# pass
# foo = Foochild()
# print(foo.bar)
Foochild = type('Foochild',(Foo,),{})
print(Foochild)
print(Foochild.bar)
9.4 动态创建函数
#实例
def echo_bar(self):
pass
type('Foochild',(Foo,),{'echo_bar':echo_bar})
hasattr(Foo,'echo_bar')#boolean
Foochild = type('Foochild',(Foo,),{'echo_bar':echo_bar})
hasattr(Foochild,'echo_bar')
10 拷贝
深拷贝和浅拷贝:浅拷贝指不拷贝子对象的内容,只是拷贝子对象的引用。深拷贝连子对象的内容也拷贝一份,对子对象的修改不影响原对象
copy()
、 deepcopy()
分别来实现浅拷贝、深拷贝
import copy
def testCopy():
'''测试浅拷贝'''
a = [10, 20, [5, 6]]
b = copy.copy(a)
print(id(a) == id(b)) # false
b.append(30)
b[2].append(7)
print("浅拷贝......")
print("a", a) # [10, 20, [5, 6]]
print("b", b) # [10, 20, [5, 6, 7], 30]
a = [10, 20, [5, 6]]
b = copy.deepcopy(a)
print(id(a) == id(b)) # false
b.append(30)
b[2].append(7)
print("深拷贝......")
print("a", a) # [10, 20, [5, 6]]
print("b", b) # [10, 20, [5, 6, 7], 30]
testCopy()