第1章 python基础

一. 计算机核心基础

参考: 计算机核心基础, 计算机核心基详解

二. 编程语言

参考: 编程语言与python介绍

1. 简述解释性型语言和编译型的区别

# 解释型
"""
编译型语言类于同声传译,翻译工具就叫解释器。解释器读取程序源代码,解释一行,交给计算机执行一行。

从三个方面回答: 执行效率,开发效率,跨平台性
    解释型执行效率对比编译型较低, 是因为解释型语言的实现中,翻译器并不产生目标机器代码,而是产生易于执行的中间代码。这种中间代码与机器代码是不同的,中间代码的解释是由软件支持的,不能直接使用硬件,软件解释器通常会导致执行效率较低。
    开发效率高, 是因为用解释型语言编写的程序是由另一个可以理解中间代码的解释程序执行的,与编译程序不同的是,解释程序的任务是逐一将源程序的语句解释成可执行的机器指令,不需要将源程序翻译成目标代码再执行。解释程序的优点是当语句出现语法错误时,可以立即引起程序员的注意,而程序员在程序开发期间就能进行校正。
    具有极强的跨平台性, 是因为代码运行是依赖于解释器,不同平台有对应版本的解释器,所以解释型的跨平台性强.
"""

# 编译型
"""
编译型语言类似于谷歌翻译,翻译工具就叫编译器。(例:C语言编译器GCC). 编译器把程序所有的代码完完整整的编译成计算机能识别的二进制指令,之后操作系统会拿着编译好的二进制指令直接操作硬件。

从三个方面回答: 执行效率,开发效率,跨平台性
    编译型执行效率高, 是因为编译是指在应用源程序执行之前,就将程序源代码“翻译”成目标代码(即机器语言),因此其目标程序可以脱离其语言环境独立执行,使用比较方便,执行效率较高。
    开发效率慢, 是因为应用程序一旦需要修改,必须先修改源代码,然后重新编译、生成新的目标文件才能执行,而只有目标文件而没有源代码,修改会很不方便。所以开发效率低于解释型.
    跨平台性差, 是因为编译型代码是针对某一个平台翻译的,当前平台翻译的结果无法拿到不同的平台使用,针对不同的平台必须重新编译,即跨平台性差.
"""

# 编译型与解释型语言简介
'''
编译型: c, java
	java比较特殊, 它是先编译成中间字节码, 再通过jvm讲中间字节码解释成机器指令.
	补充: jvm虚拟机的运行至少需要300M内存
	
解释型: python, js, go
'''

2. 列举你所知道的python2与python3之间的区别

# 编码
"""
py2:默认编码ascii
py3:默认编码utf-8
"""

# 用户交互
"""
# py2
>>> print("hello", "world")
('hello', 'world')
# py3
>>> print("hello", "world")
hello world

# py2中input只能接受数值类型, input_raw可以接收任意类型并返回字符串. py3与input_raw等同
py2:input_raw()  
py3:input()

# py2中的/运算符, 无法处理被除数大于除数的情况
1/2的结果
py2:返回0
py3:返回0.5
"""

# 字符串
"""
py2:unicode类型表示字符串,str类型表示字节. py2要在字符串前面加小u来保证py2得的字符串类型不乱码.
py3: str类型表示字符串, bytes类型表示字节. py中字符串前面帮我们默认加了小u,我们加不加都是一样,并不影响使用。
"""

# 作用域关系
"""
py2中函数用关键字global声明某个变量为全局变量,但是在嵌套函数中,想要给一个变量声明为非局部变量是没法实现的。
py3中,新增了关键字nonlocal,使得非局部变量成为可能
"""

# xrange和range
"""
py2中: range返回列表类型, xrange返回可迭代对象
py3中: range返回可迭代对象
"""

3. 列举你所知道的PEP8 Python编码规范

'''
行长度: 每行不超过80个字符(长的导入模块语句和注释里的URL除外)

缩进: 用4个空格来缩进代码,不要用tab, 也不要tab和空格混用.

空行:顶级定义之间空2行, 方法定义之间空1行.
    顶级定义之间空两行, 比如函数或者类定义.
    方法定义, 类定义与第一个方法之间, 都应该空一行.
    函数或方法中, 某些地方要是你觉得合适, 就空一行.

空格:
    1. 各种右括号前不要加空格。
    2. 逗号、冒号、分号前不要加空格。
    3. 当’='用于指示关键字参数或默认参数值时, 不要在其两侧使用空格.
    4. 在二元操作符两边都加上一个空格, 比如赋值(=), 比较(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布尔(and, or, not).
'''
# 顶级定义
name = 'yang'


def foo():
    """顶级定义"""
    pass


class Foo:
    """顶级定义"""

    def bar(self):
        """方法定义"""
        pass

    def mor(self):
        """方法定义"""
        pass


'''
导入格式:
    1. 每个导入应该独占一行
        Yes: import os
             import sys
        No:  import os, sys
    2. 导入总应该放在文件顶部, 位于模块注释和文档字符串之后, 模块全局变量和常量之前. 导入应该按照从最通用到最不通用的顺序分组:
        标准库导入
        第三方库导入
        自定义导入
'''
import os                # 内置导入
from faker import Faker  # 第三方库导入
import settings          # 自定义导入


'''
命名:
    1. 命名应该见名知意. 尽量单独使用小写字母‘l’,大写字母‘O’等容易混淆的字母。
    2. 常量命名使用全部大写的方式,可以使用下划线。
    3. 函数命名使用全部小写的方式,可以使用下划线。
    4. 类的命名使用驼峰体.
    5. 类的属性(方法和变量)命名使用全部小写的方式,可以使用下划线。
    6. 类的方法第一个参数必须是self,而静态方法第一个参数必须是cls。

注释:
    1. 对函数,类的文档字符串的惯例是使用三重双引号""".
    2. 对于复杂的操作, 应该在其操作开始前写上若干行注释
    3 .对于不是一目了然的代码, 应在其行尾添加注释.为了提高可读性, 注释应该至少离开代码2个空格.
'''
def foo():
    """文档字符串"""
    pass


class Foo:
    """文档字符串"""
    pass


# 复杂的操作: 将li列表中嵌套列表中的值列表长度大于二的保留, 将li列表中嵌套的列表中的字符的值或者浮点数的值如果大于3的数值保留并乘以2
li = [[1, 2], [1, 2, 9, 'a'], [5, 2.2, 3.3, 'b']]
new_list = [[value * 2 for value in item if isinstance(value, (int, float)) and value > 3] for item in li if len(item) > 2]
print(new_list)  # [[18], [10, 6.6]]

4. 强类型动态语言与弱类型动态语言

# 强类型动态语言:  不同类型之间不能进行相互运算(python)
int_demo = 1
str_demo = 'a'

print(int_demo + str_demo)  # TypeError: unsupported operand type(s) for +: 'int' and 'str'


# 弱类型动态语言:  不同类型之间可以进行相互运算(js)
let intDemo = 1;
let strDemo = 'a';

console.log(intDemo + strDemo); // 1a

强类型:

image-20200630223439205

弱类型:

image-20200630223337010

5. 字节码和机器码的区别?

# 机器码
'''
是电脑CPU直接读取运行的机器码,运行速度最快,但是非常晦涩难懂,同时也比较难编写;机器码就是计算机可以直接执行,并且执行速度最快的代码;

用机器语言编写程序,编程人员要首先熟记所用计算机的全部指令代码和代码的涵义。手编程序时,程序员得自己处理每条指令和每一数据的存储分配和输入输出,还得记住编程过程中每步所使用的工作单元处在何种状态。这是一件十分繁琐的工作,编写程序花费的时间往往是实际运行时间的几十倍或几百倍。而且,编出的程序全是些0和1的指令代码,直观性差,还容易出错。现在,除了计算机生产厂家的专业人员外,绝大多数的程序员已经不再去学习机器语言了。
'''

# 字节码
'''
字节码是一种中间状态的(中间码)的二进制代码(文件),字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。需要直译器转译后才能成为机器码;字节码通常情况下它是已经经过编译,但与特定机器码无关。字节码通常不像源码一样可以让人阅读,而是编码后的数值常量,引用,指令等构成的序列。字节码与特定的硬件环境无关;字节码的实现方式是通过编译器和虚拟机器。编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译为可以直接执行的指令。字节码的典型应用为Java bytecode
'''

三. python语法入门

参考: 变量, 基本数据类型, 垃圾回收机制, 用户交互, 基本运算符, 可变不可变类型, 条件, 基本运算符之逻辑运算, 基本运算符之成员运算与身份运算, 流程控制之if判断, 深浅拷贝, 流程控制之while循环, 流程控制之for循环

1. 请用至少两种方式实现m与n值交换m=10,n=5

# 定义中间变量交换
swap = m
m = n
n = swap

# 使用交叉赋值
n, m = m, n

2. 简述python的深浅拷贝?

# 注意: 以下的深浅拷贝都是争对可变容器类型的拷贝, 要知道不可变类型赋值以后就会申请新的内存地址加以存放, 并没有所谓的深浅copy.
"""
不可变类型: int, float, str, tuple, bool
可变类型:   list, dict, set
"""

# 浅拷贝
"""
python中浅拷贝的2种实现方式:
    对于索引类型: 索引类型 [:]
        li = [1, 2, 3]
	    li[:]
    对于可变的容器类型(list,dict.set): 类型.copy() 或者 import copy + copy.copy(类型)
        import copy
        dic = {'name': 'egon', 'age': 18}
        dic1 = copy.copy(dict)
        print(dic is dic1)  # False

浅拷贝不区分可变容器类型中的可变不可变类型. 对于可变类型共用一份内存地址, 对于不可变类型在没有修改之前共用一份内存地址.
"""

# 深拷贝
"""
python中深拷贝的1种表现形式: 
    对于可变的容器类型(list,dict.set): 
        import copy
        copy.deepcopy(类型)
        
深拷贝对可变容器类型中的可变不可变类型. 对于可变类型创建一份新的内存地址, 对于不可变类型在没有修改之前任然共用一份内存地址.        
"""


# 深浅拷贝什么时候使用呢?
"""
使用浅copy:如果你想对容器类型进行修改操作时,想保留原来的数据和修改后的数据,这时只有容器类型的第一层全是不可变类型,这个时候就用浅copy。
使用深copy:如果你想对容器类型进行修改操作时,想保留原来的数据和修改后的数据,且你想让两个列表完完全全独立开,这个时候就用深copy。
"""

# 题目思考, 以下的输出结果, 为什么? 
li = [1, 2, 3, [4, 5, 6]]
li2 = li  # 赋值
print(li2 is li) 

from copy import copy
from copy import deepcopy

li3 = copy(li)
print(li)
print(li3)
print(li is li3)

li3[3][1] = 999
print(li)
print(li3)

li4 = deepcopy(li)
li4[3][1] = 888
print(li)
print(li4)


# 答案:
# 赋值
# 赋值操作列表与新列表都是指向同一内存地址,2个列表中,只要有一个人的列表中的索引所对应的值的内存地址改变,则都改变
li = [1, 2, 3, [4, 5, 6]]
li2 = li
print(li2 is li)     # True

from copy import copy
from copy import deepcopy

# 浅拷贝
# 对源列表copy以后,产生的新列表内存地址发生了改变,不再是同一个列表。而新列表与源列表中的可变不可变类型的值在没修改之前都是指向同一个值。
li3 = copy(li)
print(li)            # [1, 2, 3, [4, 5, 6]]
print(li3)           # [1, 2, 3, [4, 5, 6]]
print(li is li3)     # False

# 对源列表中可变类型的值进行修改以后,对于可变类型,我们可以改变类型中包含的值,但这个可变容器本身内存地址不变。即新列表的索引仍然指向原来的内存地址,于是新列表也跟着受影响。
li3[3][1] = 999
print(li)            # [1, 2, 3, [4, 999, 6]]
print(li3)           # [1, 2, 3, [4, 999, 6]]

# 深拷贝
# 把两个列表完完整整独立开,并且只争对该操作而不是读操作。
li4 = deepcopy(li)
li4[3][1] = 888
print(li)            # [1, 2, 3, [4, 999, 6]]
print(li4)           # [1, 2, 3, [4, 888, 6]]
print(li is li4)     # False

3. 什么是python的垃圾回收机制?

"""
1) 什么是垃圾回收机制?
垃圾回收机制简称GC, 是python解释器自带的一种机制, 专门用来回收不可用的变量值所占用的内存空间.

2) 为什么要用垃圾回收机制?
程序的运行过程中会申请大量的内存空间, 而对于一些无用的内存空间如果不及时清理的话会导致内存空间是用殆尽, 进而造成内存溢出, 最终导致程序奔溃. 但是管理内存是一件非常繁琐且复杂的事情, python则提供了垃圾回收机制来帮我们程序从复杂的内存管理中解放出来.

3) 垃圾回收机制的三大算法工作模式:
    1) 引用计数: 跟踪回收垃圾
        引用计数又分直接应用, 间接引用. 如果'值'引用计数为0, '值'占用的内存地址将会被垃圾回收机制回收.
        # 直接引用
        name = 'yang'
        
        # 间接引用
        li = [name, ]

    2) 标记/清除: 解决容器类型的循环引用问题
        执行前提: 当应用程序可用内存空间快被耗尽.
        标记: 有根之人当活, 无根之人当死. 根指的栈区, 也就是说可以通过栈区间接或者直接可以访问到堆区的对象的数据会被保留. 否则执行清除.
        清除: 遍历堆区中所有对象, 将堆区中与栈区无引用关系的的对象全部清除.

    3) 分代回收: 解决引用计数每次回收内存都需要遍历所有对象的效率问题.
        根据存活时间划分扫描频率. 刚来的数据权重最低, 扫描频率最高. 数据存活时间越长权重越高, 扫描频率越低.
"""

4. 求结果: or and

v1 = 1 or 3
v2 = 1 and 3
v3 = 0 and 2 and 1
v4 = 0 and 2 or 1
v5 = 0 and 2 or 1 or 4
v6 = 0 or False and 1

"""
>>> v1 = 1 or 3
>>> v2 = 1 and 3
>>> v3 = 0 and 2 and 1
>>> v4 = 0 and 2 or 1
>>> v5 = 0 and 2 or 1 or 4
>>> v6 = 0 or False and 1
>>> v1, v2, v3, v4, v5, v6
(1, 3, 0, 1, 1, False)
"""

四. 基本数据类型及内置方法

参考: 数字类型及其内置方法, 字符串类型及其内置方法, 列表类型及其内置方法, 元组类型及其内置方法, 字典类型及其内置方法, 集合类型及其内置方法

1. 列举字符串,列表,元组,字典每个常用的五个方法?

# 字符串
"""
需要掌握的操作:
    strip, lstrip, rstrip
    upper, lower
    format
    split, rsplit
    join
    replace
    startswith, endswith
    isdigit
    
is系列:
    islower, isupper
    istitle
    isalnum, isalpha
    isspace
    isidentifier
    isdigit, isnumeric, isdecimal
    
了解的操作:
    find, rfind, index, rindex 
    count
    center, ljust, rjust, zfill
    expandtabs
    capitalize, swapcase, title
"""

# 列表
"""
增: append, insert, expand

删: remove, pop, del

排序: sort

需要掌握的操作: count, index, copy, clear, reverse
"""

# 元组
"""
count, index
"""


# 字典
"""
删: del, pop, popitem

键: keys 值: values 键值对: items

需要掌握的操作:
    get, clear, setdefault, update, fromkeys
"""

2. 进制之间的转换

"""
其他进制转十进制: int(x, 进制数)
十进制转其他进制: bin(), oct(), hex()
"""

# 二进制转换成十进制:v = "0b1111011"
v = '0b1111011'
print(int(v, 2))

# 十进制转换成二进制:v = 18
v = 18
print(bin(v))

# 八进制转换成十进制:v = "011"
v = "011"
print(int(v, 8))

# 十进制转换成八进制:v = 30
v = 30
print(oct(v))

# 十六进制转换成十进制:v = "0x12"
v = "0x12"
print(int(v, 16))

# 十进制转换成十六进制:v = 87
v = 87
print(hex(v))  # 0x57

3. 有一个列表[3,4,1,2,5,6,6,5,4,3,3]请写出一个函数,找出该列表中没有重复的数的总和

list1 = [3, 4, 1, 2, 5, 6, 6, 5, 4, 3, 3]


# 方法一:
def distinct1(li:list):
    tmp_list = []
    sum_num = 0
    for num in li:
        if num not in tmp_list:
            tmp_list.append(num)
            sum_num += num
    return sum_num


print(distinct1(list1))  # 21


# 方法二:
def distinct2(li: list):
    return sum(set(li))


print(distinct2(list1))  # 21

4. 可变与不可变类型

参考: https://www.cnblogs.com/xiaoyuanqujing/articles/12008689.html

强调: 字典的key必须用可变类型, 可以hash.

# 关键: python3.5之前字典是无序的, python3.5之后字典是有序的

# 可变类型(不可哈希):   list, dict, set
print(hash([1, 2]))  # TypeError: unhashable type: 'list'
    
# 不可变类型(可哈希):   int, float, bool, str, tuple
print(hash('egon'))  # 8456701061454264266

5. int()long()

'''
python2:
  int()  # 整型
  long() # 长整型
  
python3中没有long类型: 只有int类型
'''

6. 哪些情况下: y! = x - (x-y)会成立?

x = {'x'}
y = {'y'}

res = x - y
print(res)  # {'x'}

res = x - res
print(res)  # set()

res = y != res
print(res)  # True

7. 现有字典dic = {'a': 24, 'g': 52, 'i': 12, 'k': 33}请按字典中的 value 值进行排序?

dic = {'a': 24, 'g': 52, 'i': 12, 'k': 33}
res = sorted(dic.items(), key=lambda item: item[1])
print(res)  # [('i', 12), ('a', 24), ('k', 33), ('g', 52)]

8. 什么是可变、不可变类型?

'''
# 可变不可变指的是内存中的值是否可以被改变
    不可变类型指的是对象所在内存块里面的值不可以改变,有数字、字符串、元组;
    可变类型则是可以改变,主要有列表、字典, 集合.
'''
s = {'a', 'b'}
s.add('c')
s.pop()

s |= {'d'}
print(s)  # {'a', 'd', 'c'}

8. 描述下dict的item()方法与iteritems()的不同

'''
字典的items方法作用:是可以将字典中的所有项,以列表方式返回。因为字典是无序的,所以用items方法返回字典的所有项,也是没有顺序的。
字典的iteritems方法作用:与items方法相比作用大致相同,只是它的返回值不是列表,而是一个迭代器。

在Python2.x中,iteritems() 用于返回本身字典列表操作后的迭代器【Returns an iterator on all items(key/value pairs) 】,不占用额外的内存。
在Python 3.x 里面,iteritems()方法已经废除了。在3.x里用 items()替换iteritems() ,可以用于 for 来循环遍历。
'''
dic = {'a': 24, 'g': 52, 'i': 12, 'k': 33}

# py3
'''
res = dic.items()
res.__iter__()
print(res)  # dict_items([('a', 24), ('g', 52), ('i', 12), ('k', 33)])
'''

# py2
'''
res = dic.items()
print(res)  # [('a', 24), ('i', 12), ('k', 33), ('g', 52)]

res = dic.iteritems()
print(res)  # <dictionary-itemiterator object at 0x0000000002EA34A8>
'''

10. 简述字符串驻留机制

参考: https://www.jianshu.com/p/9660f399ac98

'''
字符串驻留是一种在内存中仅保存一份相同且不可变字符串的方法
Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量。

采用Python驻留机制的时候有以下几种情况:
    1、字符串长度为0或1时,默认采用驻留机制。
    2、字符串长度大于1时,且字符串中只包含大小写字母、数字、下划线时,采用驻留机制。
    3、字符串只在编译时进行驻留,而非运行时。Python是解释型语言,但是事实上,它的解释器也可以是理解为是一种编译器,它负责将Python代码翻译成字节码,也就是.pyc文件。
    4、用乘法得到的字符串,如果结果长度 <=20且字符串只包含数字、字母大小写、下划线,支持驻留。长度>20,不支持驻留。这样的设计目的是为了保护.pcy文件不会被错误代码搞的过大。
    5、对于[-5,256]之间的整数数字,Python默认驻留
    6、Pyhton提供intern方法强制2个字符串指向同一个对象。
    
注意: pycharm会做处理, 放到交互式环境里面执行    
'''

1、字符串长度为0或1时,默认采用驻留机制。

img

2、字符串长度大于1时,且字符串中只包含大小写字母、数字、下划线时,采用驻留机制。

img

3、字符串只在编译时进行驻留,而非运行时。Python是解释型语言,但是事实上,它的解释器也可以是理解为是一种编译器,它负责将Python代码翻译成字节码,也就是.pyc文件。

img

c是几个字符串的拼装,字符串的 .join() 方法是在运行期间才知道结果。所以c不支持字符串驻留。

4、用乘法得到的字符串,如果结果长度 <=20且字符串只包含数字、字母大小写、下划线,支持驻留。长度>20,不支持驻留。这样的设计目的是为了保护.pcy文件不会被错误代码搞的过大。

参考的文章是这样说的,但是我实际操作之后发现这条不成立。见图如下:

img

5、对于[-5,256]之间的整数数字,Python默认驻留

img

6、Pyhton提供intern方法强制2个字符串指向同一个对象。

img

11. 给定两个列表,怎么找出他们相同的元素和不同的元素?

list1 = [1, 2, 3]
list2 = [3, 4, 5]
set1 = set(list1)
set2 = set(list2)
print(set1 & set2)  # {3}
print(set1 ^ set2)  # {1, 2, 4, 5}

12. 请写出一段Python代码实现删除一个list里面的重复元素?

li = ['b', 'c', 'd', 'b', 'c', 'a', 'a']

res = list(set(li))
print(res)  # ['a', 'c', 'b', 'd']

res.sort(key=li.index)
print(res)  # ['b', 'c', 'd', 'a']

res = sorted(set(li), key=li.index)
print(res)  # ['b', 'c', 'd', 'a']

res = []
for item in li:
    if item not in res:
        res.append(item)
print(res)  # ['b', 'c', 'd', 'a']

13. 下面这段代码的输出结果是什么?请解释?

def extendlist(val, li=[]):  # 注意: li=[]如果默认没有传值, 那么全局中等于声明了一个li = []
    li.append(val)
    return li


list1 = extendlist(10)
list2 = extendlist(123, [])
list3 = extendlist('a')
print("list1 = %s" % list1)  # list1 = [10, 'a']
print("list2 = %s" % list2)  # list2 = [123]
print("list3 = %s" % list3)  # list3 = [10, 'a']

14. 将以下3 个函数按照执行效率高低排序

def f1(lIn):
    l1 = sorted(lIn)
    l2 = [i for i in l1 if i < 0.5]
    return [i * i for i in l2]


def f2(lIn):
    l1 = [i for i in lIn if i < 0.5]
    l2 = sorted(l1)
    return [i * i for i in l2]


def f3(lIn):
    l1 = [i * i for i in lIn]
    l2 = sorted(l1)
    return [i for i in l1 if i < (0.5 * 0.5)]


import random
import cProfile

lIn = [random.random() for i in range(100000)]
cProfile.run('f1(lIn)')  # 7 function calls in 0.043 seconds
cProfile.run('f2(lIn)')  # 7 function calls in 0.025 seconds
cProfile.run('f3(lIn)')  # 7 function calls in 0.044 seconds

15. Python 中, 哪个语句能直接显示的释放内存资源

import gc

print(gc.collect())  # 28

五. 字符编码与文件处理

参考: 字符编码, 文件处理

1. ASCII, GBK, unicode, utf-8区别?

# ASCII, GBK, unicode, utf-8字符编码介绍
"""
ASCII:
在计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit),有0和1两种状态,因此,8个二进制位可以组合出256种状态,这被称为字节(byte)。上个世纪60年代,美国制定了一套字符编码,对英文字符与二进制之间做了联系,这被称为ASCII码,一直沿用至今。
ASCII码一共规定了128个字符,比如SPACE是32,A是65,这128个符号只用了一个字节的后面七位,最前面的一位统一规定为0。


gbk:
GBK编码是对GB2312的扩展,完全兼容GB2312。采用双字节编码方案,剔出xx7F码位,共23940个码位,共收录汉字和图形符号21886个,GBK编码方案于1995年12月15日发布。它几乎完美支持汉字,因此经常会遇见GBK与Unicode的转换。


unicode:
世界上有多种编码方法,同一个二进制数字可以被解释称不同的符号。因此,在打开一个文本文件时候,就必须知道它的编码方式,用错误的编码方式打开,就会出现乱码。
Unicode编码,这是一种所有符号的编码。
Unicode显然是一个巨大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如U+0041表示英语的大写字母A,U+4e25表示汉字严。
在Unicode庞大的字符集的优势下,还存在一个问题,比如一个汉字,“严”的Unicode是十六进制4e25,转成二进制足足有15位,也就是,这个符号需要2个字节,表示其他字符还存在3个字节或者更多。计算机怎么区别三个字节表示的是同一个符号而不是分开表示三个呢?如果Unicode统一规定,每个符号用3个字节表示,但是某些字母显然不需要3个,那么就浪费了空间,文本文件大小超出了很多,这显然是不合理的。直到UTF8字符编码出现了。


utf-8:
UTF8的最大特点是,它是一种变长编码,可以使用1-4个字节表示一个符号,根据不同的符号来变化字节长度。
UTF8编码规则只有两条:
1)对于单字节的符号,字节的第一位设为0,后面的7位为这个符号的Unicode码。因此,对于英文字母,UTF8编码和ASCII编码是相同的。
2)对于非单字节(假设字节长度为N)的符号,第一个字节的前N位都设为1,第N+1设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制,全部为这个符号的Unicode码。


1,各个编码之间的二进制,是不能互相识别的,会产生乱码。
2,文件的存储,传输,不能是unicode (只能是utf-8 utf-16 gbk gbk2312 ascii等)
"""

# ASCII, GBK, unicode, utf-8字符编码字符与字节的对应关系
"""
ASCII: 只采用1个字节对应一个英文字符
GBK: 采用1个字节对应一个英文字符,采用2个字节对应一个中文字符。
unicode: 采用2个字节对应一个字符,生僻字采用4个字节、8个字节。(注意:无论是英文还是中文,都是采用2个字符)
utf-8:采用1个字节对应一个英文字符,采用3个字节对应一个中文字符。
"""

# 目前编码使用的硬件范围? 
"""
目前内存使用的编码: unicode
    unicode兼容万国码,与万国字符都有对应关系。
    unicode有2个作用:
        1、兼容万国字符 
        2、兼容万国字符编码表对应关系(unicode妥协于此,也就是它目前存在的主要作用)
        
目前硬盘中使用的编码:utf-8、GBK、Shift-JIS

内存固定使用unicode,我们可以改变的是存入硬盘采用的格式如下样式:
    英文+汉字(文本编辑器) ---》 unicode(内存) ---》GBK(硬盘)
    英文+日文(文本编辑器) ---》 unicode(内存) ---》Shift-JIS(硬盘)
    万国字符(文本编辑器)  ---》 unicode(内存) ---》utf-8(硬盘)

注意: 字符编码之间不可以进行转换。例如:GBK不能转成ASCII,因为这两种字符表的对应关系不一样。但是字符编码之间可以使用unicode作为中间介质,可以进行读写操作。
"""

2. 文件操作时:xreadlines和readlines的区别?

'''
readlines()是把文件的全部内容读到内存: 并解析成一个list: 当文件的体积很大的时候: 需要占用很多内存
xreadlines()则直接返回一个iter(file)迭代器: 在Python 2.3之后已经不推荐这种表示方法了.直接使用for循环迭代文件对象
'''
with open('a.txt', 'r') as f:
    print(f.readlines())      # py3: ['123\n', '321\n', 'qwe\n', 'ewq']
    # print(f.xreadlines())   # py2: <open file 'a.txt', mode 'r' at 0x0000000003326030>
posted @ 2020-05-11 20:28  给你加马桶唱疏通  阅读(275)  评论(1编辑  收藏  举报