bytes类型是指一堆字节的集合,在python中以b开头的字符串都是bytes类型
b'\xe5\xb0\x8f\xe7\x8c\xbf\xe5\x9c\x88' #b开头的都代表是bytes类型,是以16进制来显示的,2个16进制代表一个字节。 utf-8是3个字节代表一个中文,所以以上正好是9个字节
计算机只能存储2进制。
在python中,数据转成2进制后不是直接以01010101的形式表示的,而是用一种叫bytes(字节)的类型来表示的。
>>> s = "小猿圈"
>>> s.encode("utf-8") # 以utf-8编码
b'\xe5\xb0\x8f\xe7\x8c\xbf\xe5\x9c\x88' #b开头的都代表是bytes类型,是以16进制来显示的,2个16进制代表一个字节。 utf-8是3个字节代表一个中文,所以以上正好是9个字节
在python中,字符串必须编码成bytes后才能存到硬盘上。
在python3中文件存储的默认编码是utf-8.
'''
自行改变文件的默认编码,改成gbk格式的
'''
f = open('book.txt', 'w','gbk')
当然,在打开文件时如果你不想让open这个对象帮你自动编码,你也可以直接往文件里存入bytes数据。
f = open(file="encode_test",mode="wb") # wb以2进制模式打开文件
s = "自学编程,谁不上小猿圈".encode("utf-8") # 自行编码
print(s )
f.write(s)
f.close()
#以下是print(s)的输出
b'\xe8\x87\xaa\xe5\xad\xa6\xe7\xbc\x96\xe7\xa8\x8b\xef\xbc\x8c\xe8\xb0\x81\xe4\xb8\x8d\xe4\xb8\x8a\xe5\xb0\x8f\xe7\x8c\xbf\xe5\x9c\x88'
2进制模式打开文件有
编码转换是指将一种编码转成另外一种编码,比如 utf-8 to gbk。
为何需要编码转换呢? 因为不同操作系统编码不同, utf-8在win上没办法直接看,因为windows是GBK编码的,得转成gbk。 反过来如果你的GBK字符相在Linux\Mac上正常显示,就得转成utf-8编码。
>>> s.encode("utf-8") # 编码
b'\xe5\xb0\x8f\xe7\x8c\xbf\xe5\x9c\x88'
>>> s_utf8=s.encode("utf-8")
>>>
>>> s_utf8.decode("utf-8") #解码
'小猿圈'
在py3里,内存里的字符串是以unicode编码的,unicode的其中一个特性就是跟所有语言编码都有映射关系。所以你的utf-8格式的文件,在windows电脑上若是不能看,就可以把utf-8先解码成unicode,再由unicode编码成gbk就可以了。
注意,不管在Windows or Mac or Linux上,你的pycharm IDE都可以支持各种文件编码,所以即使是utf-8的文件,在windows下的pycharm里也可以正常显示
str的赋值(=)
a = 1243
b = a
a = 12
a和b指向同一内存地址,a改变不影响b
list,set,dict(=)和后面函数里list,set,dict(函数传递列表,字典,集合时发生的现象)
a = [1,2,3,4]
b = a
a.append(5)# append返回的是None,所以不能赋值
a和b 也是指向同一内存地址,但是这个[]的内存地址没有变(杯子问题),a里面的元素变了,b也会跟着变
data = {‘name’: ‘yekai’,
'age': 18,
'scores': {}
}
d2 = data
data['age'] = 20
print(d2)
你说d2打印的值里,age是18,还是20?
{'name': 'alex', 'age': 20, 'scores': {}}
为何是20呢? 因为d2=data相当于只是拿到了data
的==内存地址==,但data里的每个k,v都是有单独的内存的地址的。d2,data会一直共享这个dict里的数据,不会出现像之前字符串a=1,b=a, a=2, b依然等于1的情况。
如果我确实想复制一份完成的dict数据怎么办呢?
==可以用浅copy语法==(python自带,不用导入模块)
因为浅copy会仅复制dict的第一层数据,更深层的scores下面的值依然是共享一份。
注意图中的2个dict中的name都是alex,内存地址也一样,在没改前,两个name都确实指向同一个内存地址,但只要改任何一个的值,内存地址都会变更, 如age这个key一样。
==深copy==(必须导入python中的一个工具模块)(很少用,因为完全复制一份数据,占空间)
==函数是什么?==
函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。
==定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可==
特性:
### 语法定义 ###
def sayhi():#函数名
print("Hello, I'm nobody!")
sayhi() #调用函数
可以带参数
#下面这段代码
a,b = 5,8
c = a**b
print(c)
#改成用函数写
def calc(x,y):
res = x**y
return res #返回函数执行结果
c = calc(a,b) #结果赋值给c变量
print(c)
参数可以让你的函数更灵活,不只能做死的动作,还可以根据调用时传参的不同来决定函数内部的执行流程
### 函数参数 ###
形参变量
只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参
可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先给实参赋值
==注意,参数优先级顺序是 位置参数>关键参数==
函数的顺序:位置参数,默认参数,可变参数*args
(结果为元组),命名关键字参数(带参数名调用),关键字参数**kwargs
(结果为字典)
函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回
注意
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
name = "Alex Li"
def change_name():
name = "金角大王,一个有Tesla的高级屌丝"
print("after change", name)
change_name()
print("在外面看看name改了么?",name)
输出
after change 金角大王,一个有Tesla的高级屌丝
在外面看看name改了么? Alex Li
为什么在函数内部改了name的值后, 在外面print的时候却没有改呢? 因为这两个name根本不是一回事
name = "Alex Li"
def change_name():
global name #声明一个全局变量
name = "Alex 又名金角大王,爱生活、爱自由、爱姑娘"
print("after change", name)
change_name()
print("在外面看看name改了么?", name)
global name
的作用就是要在函数里声明全局变量name ,意味着最上面的name = “Alex Li”
即使不写,程序最后面的print也可以打印name
d = {"name":"Alex","age":26,"hobbie":"大保健"}
l = ["Rebeeca","Katrina","Rachel"]
def change_data(info,girls):
info["hobbie"] = "学习"
girls.append("XiaoYun")
change_data(d,l)
print(d,l)
执行结果{‘name’: ‘Alex’, ‘age’: 26, ‘hobbie’: ‘学习’ } [‘Rebeeca’, ‘Katrina’, ‘Rachel’, ‘XiaoYun’]
不是说不能在函数里改全局变量么,怎么改了呀?
函数里不仅可以写代码,还可以嵌套函数
name = "小猿圈"
def change():
name = "小猿圈,自学编程"
def change2():
# global name 如果声明了这句,下面的name改的是最外层的全局变层
name = "小猿圈,自学编程不要钱" #这句注释掉的话,下面name打印的是哪个值?
print("第3层打印", name)
change2() # 调用内层函数
print("第2层打印", name)
change()
print("最外层打印", name)
输出
第3层打印 小猿圈,自学编程不要钱
第2层打印 小猿圈,自学编程
最外层打印 小猿圈
通过上面的例子,我们理解了,每个函数里的变量是互相独立的,变量的查找顺序也是从当前层依次往上层找。
问个哲学问题,这东西有什么用呢?哈,现在没用,不解释,长大后学了装饰器你就知道有啥用了。
匿名函数就是不需要显式的指定函数名
#这段代码
def calc(x,y):
return x**y
print(calc(2,5))
#换成匿名函数
calc = lambda x,y:x**y
print(calc(2,5))
你也许会说,用上这个东西没感觉有毛方便呀, 。。。。呵呵,如果是这么用,确实没毛线改进,不过匿名函数主要是和其它函数搭配使用的呢,如下
res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
print(i)
输出
1
25
49
16
64
总结:lambda函数就是可以接受任意多个参数(包括可选参数)并且返回单个表达式的函数。好处有以下:
- lambda函数比较轻便,即用即扔,适合完成只在一处使用的简单功能
- 匿名函数,一般用来给filter,map这样的函数式编程服务
- 作为回调函数,传递给某些应用,比如消息处理
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def get_abs(n):
if n < 0 :
n = int(str(n).strip("-"))
return n
def add(x,y,f):
return f(x) + f(y)
res = add(3,-6,get_abs)
print(res)
只需满足以下任意一个条件,即是高阶函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自已本身,这个函数就叫做递归函数。上面我们写的这个代码就是递归
递归特性:
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
如x = 1,名称空间正是存放名字x与1 绑定关系的地方
名称空间有4种:L-->E-->G-->B
- locals:函数内部的名字空间,locals()方法可以查看
- enclosing function:嵌套空间,
- globals:类似全局变量,有globals()方法
__builtins__
:内置模块空间
==不同变量的作用域不同就是由这个变量所在的名称空间决定的==
作用域的范围
查看作用域的方法:globals(),locals()
闭包就是函数定义和函数表达式位于另一个函数的函数体内,内部函数可以在外部函数执行返回后被调用执行。(也就是内层函数被当成对象返回的时候夹带了外部函数的局部变量,就会形成一个闭包)
==闭包的意义:返回的对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域==
- 封闭:已实现的功能代码不应该被修改
- 开放:对现有的功能的扩展开放
是python内置的来创建list的生成式,可以用一行语句来代替循环来生成一个列表
==语法:[要生成的元素x * x 放在前面,后面跟for循环]==
>>>[x * x for x in range(1, 11) if x % 2 == 0]
结果为[4, 16, 36, 64, 100]
使用两层循环来生成全排列
>>>[m + n for m in 'ABC' for n in 'XYZ']
结果为['AX', 'AY', 'AZ', 'BX','BY', 'BZ','CX', 'CY', 'CZ']
把一个list中的所有字符串变成小写
>>>L = ['Hello', 'World', 'IBM','Apple']
>>>[s.lower() for s in L]
结果为['hello', 'world', 'ibm', 'apple']
在python中,一边循环一边计算的机制,称为生成器
创建生成器(generator)的方法:
generator函数的调用实际返回一个generator对象。
把函数改成generator后,一般不会用next()来获取下一个返回值,而是常使用for循环来迭代。
>>>g = (x * x for x in range(10))
>>>for i in g:
print(i)
斐波拉契数列:除第1个和第2个数字外.任意一个数都是其前面2个数相加得到.(用列表生成式写不出来,因为没有合适的表达式)
def fib(max):
n, a, b = 0, 0 , 1
while n < max:
yield b
a, b = b, a + b
n += 1
return 'done'
迭代器,可以被next()函数调用并不断返回下一个值的对象.
1.集合数据类型(list,tuple,set ,dict ,str) 2.generator,包括生成器和带yield的generator function,以上这些可直接作用于for循环的对象统称为可迭代对象(iterable),==可迭代的意思就是可遍历,可循环.==
generator 都是Iterable,但list,dict,str,tuple,set,虽然都是可迭代对象(iterable),但都不是迭代器.
[typora中添加数学公式](https://blog.csdn.net/Ernest_YN/article/details/84064233#0_2)
$$
interable 对象--->>
\begin{cases}
list\
dict\
tuple\
set\
str\
\end{cases}
$$
都可以通过iter()方法转化为Iterator(迭代器)
python 中,for循环本质上就是通过不断调用next()函数来实现的
for x in [1,2,3,4,5]:
pass
it = iter([1,2,3,4,5])
while True:
try:
x = next(it)
except StopIteration:
break
==总结:1.凡是可以作用于for循环的对象都是Iterable对象.2.凡是可作用于next()函数的对象都是Iterator类型,它表示一个惰性计算的序列==
Python的len为什么你可以直接用?肯定是解释器启动时就定义好了
内置参数详解https://docs.python.org/3/library/functions.html?highlight=built#ascii
文件操作中的不同打开方式.
原文:https://www.cnblogs.com/ylkx/p/11253052.html