快速入手Python小册

    科技2023-09-25  77

    前言

    本博客主要是为了记录入门python的基础知识点,并作为个人的学习框架备忘。(需要一定的编程基础,其中过于基础的内容不做赘述。)

    基础

    python解析器: python使用最广泛的解析器就是用 C语言编写的,有些语言发明者搞出一些生硬的语言符号,这种语言一般完全不用理,没必要去进行学习,浪费生命,毕竟全世界有 七百种编程语言。

    1.utf编码:utf码快速查询网站: https://unicode-table.com/en/4E1C/。 encode编码就是各种字符组编成utf协议下映射的数据码文,decode解码就是将utf码文解析成易读的字符。 C语言中常见的就是ASCII码, python中utf-8能够兼容ascii码, utf-16不行,并且由于utf-16将数据码映射成十六进制为最小单位来存储,因此存在大小端的问题,这点在解码的时候要特别注意。几个常用函数如ord()函数将字符转化为对应的十六进制映射值。chr()函数将存储的数字映射值转化为字符数据。len()函数 将字符的长度输出。 utf-8在兼容性会比utf-16来得优秀, 用单字节存储映射数据,每个字节即可得到有效的映射所要表达的信息,因而不存在大小端的问题,utf-16主要是因为使用了双字节存储一个有效含义的数值,因此一个有效信息点被拆分成两部分来表达,因此,在decode的时候, 要区分大小端的问题。

    Unicode符号范围UTF-8编码方式0000 0000-0000 007F0xxxxxxx0000 0080-0000 07FF110xxxxx 10xxxxxx0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 字符普通二进制UTF-16二进制UTF-16UTF-16BEUTF-16LE$U+00240000 0000 0010 01000000 0000 0010 0100002400 24

    utf-8, utf-16和ord()函数其实差不多,都是很直白地按顺序映射成数值,( 但是utf-16要注意到一个大小端的问题,), 相比之下, utf-8的映射显得更有考究一点,很多网页基本都是用 utf-8 来进行编码, 这样网页数据在传输,解码的时候,通用性更高。 2. 变量的产生: 和c/c++不同地方在于, python 中不需要对变量进行数据类型声明,在python中, 一旦有赋值的行为发生时,就会产生一个新的变量作用域,但是有可能变量的id是一样的, 比如变量的相互赋值a=b, 对于内存来说, 该过程就是产生一个变量的引用,而如果需要完全拷贝数据到一新的内存id上,则需要使用 copy模块, 进行浅拷贝以及深拷贝操作。 3. 在python中, __**__ 表示特殊内置变量 ,比如__name__变量会在每个脚本被执行的时候,会被赋值为__main__, 而如果只是作为包被调用, 则不会被赋值,所以,当我们要兼容二者的时候,会添加判断__name__是不是等于__main__的代码判断, _*** 表示非公开,私有变量。 4. 变量作用域: 变量一旦有赋值操作,即产生一个新的变量作用域, 函数内部的局部变量在想要使用全局变量, 需要使用 global关键字 来声明并引用变量名。python的命名空间主要遵循 LEGB的原则, 作用域范围由小到大分别是local(函数局部变量),enclosing(闭包,嵌套函数中变量), globals(全局变量), builtins(python解析器内置的变量). 如下例子, 对于解析器来说, 在闭包函数中做赋值操作时候,x 即被声明为局部变量(就不会找到上一层的范围中的变量,即使上一层有一个x变量可以引用), 引用的操作必须在赋值之后, 因为只有先赋值才能产生这个变量的作用域。

    def enclosure(): x=0 def embed(): x=x+9 print(x) return x return embed fun_p=enclosure() fun_p()

    File “trail.py”, line 40, in embed x=x+9 UnboundLocalError: local variable ‘x’ referenced before assignment

    5.从变量存储情况区分变量类型:可变类型,表示变量的值可被改变,地址id不变,常见的类型比如 list(列表, 立刀旁很像中括号吧,哈哈哈)。 不可变类型,表示变量的数值一旦变,地址也要变,原有地址存储的数据不能变。, 常见的是 tuple(元组, 一元硬币很像元括号吧), 当tuple只有一个元素的时候, 必须要编程为 tuple= (1,),也就是圆括号内必须带有,进行分割, 这样表述免得和数学公式中括号的作用产生歧义,而需要声明字典变量的时候, 则通过使用花括号{ }来进行声明,( 字典的字的宝盖头刚好很像花括号,d1={“a”:1, “b”:2},哈哈哈), 字典通过pickle/json来转换为json 的字节流很方便. 4.1 数据如何索引, 列表,元组,字典 均用中括号,来写入索引,通过索引来引用其中的元素,字典传入key的字符串,则通过key来索引取得value值, dict.get("key") 获取字典元素, dict.pop("key")删除某个字典元素。 4.2 python中集合的妙用, set(list[]) 可以声明得到一个无序和无重复元素的集合, 在我们需要获取两个数据集合之间的交集以及并集的时候, 该数据类型特别方便。 6. 生成器:如果想使用海量数据存储空间, 又想节省空间, 即使用generator生成器,基本思想就是一边循环一边计算。, 借助for关键字内置的next函数进行遍历。当在函数内部使用yield(产出)关键字时, 我们可以将一个普通函数转换为generator函数, 每当函数执行到yield即返回一个迭代对象,下一次迭代的时候, 函数从 yield的下一个语句开始执行,以此得到一个可以实现迭代的函数对象。 7. 列表生成式,一种特别棒的语法: list=[expression for i in range(1, 10)] 如何理解:语法中从 range()中得到的i的值,然后带入前面的表达式, 表达式计算的结果赋值给list 列表或者元组。 8. bytes关键字: bytes关键字将字符数据通过指定的encode编码形式如utf-8, 转化为的十六进制表达的转义字符表述, 转换后的数据如: b’C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x918\xe5\xb2\x81\xe4\xba\x86’, 转换后的数据通过bytes自带的decode方法,然后,指定转换编码形式(如utf-8),从而转换成可读形式字符。 注意: 转换后的结果头部以b字母开头, 其中的数据能用ascii码表示的,则继续使用ascii表示, 不能表示的则用转义字符表示。 6. 包的安装 : 包的安装没什么可讨论的, 主要是pip install keras==可以得到当前解析器可支持,可安装的版本,以及通过官方工具包的网站为 https://pypi.org, 通过下载whl文件,使用wheel安装工具进行安装. 7. 包的导入与创建: 模块包的目录下存在 init.py 文件,该文件用于控制包在import时的一些导入行为,确保导入的范围。init.py 中还有⼀个重要的变量,叫做 all,通过该变量来限制导入的元素范围。python中模块的导入, 如果把函数保存在 module.py, 则外部调用需要通过from module import function导入 ,module是文件名, function是函数方法名或者类名, (print(help(module_name))# 获取a_module的帮助文档。)。

    模块基础: Python中每⼀个文件都是⼀个模块, 文件名为模块名,使用import module 来导入模块,from xx import class 表示从xx文件中导入class类(函数,变量), 使用这种方法的话, 在python脚本中调用类的时候, 就可以避免去重复写模块名进行代码书写, module.class.a – > class.a, from xx import * 从xx模块文件引入所有公开的元素, reload 模块, 重载模块。 模块搜索路径: • 程序所在路径 • 标准库安装路径 • 操作系统环境变量PYTHONPATH指向的路径 8.python中通过统一缩进来区别类,函数, 代码块的作用域,这点在编程中尤为方便, 顺便说一下, python中不支持 swtich语法。 9.python定义函数和makefile语法很像. 挺简洁。

    #python空函数模板 def nop(): pass # 表示空占符,空语句,避免报错。 return None # makefile函数定义 define fun @echo "makefile function" endef 变量类型与变量地址: 通过id()函数查看变量的地址值,通过type()方法查看变量的类型。self 参数 : python类声明中的self参数,目的主要是为了 在函数方法中调用类内部声明的变量, 一般类内部的方法函数的第一个参数就是 self, 这点和C++中的this 指针的功能是一样的, 只是python这边都要求显式写出来。嵌套类的使用: 无论是嵌套类还是非嵌套类, 类中的方法和元素一定要通过实例化之后,才能够进行调用, 如果要使用嵌套在内部的类的话,通过obj= out.inside() 先去实例化,再通过obj去调用insiden内部的方法函数, (通过@staticmethod修饰器来修饰,就可以不经过实例化 直接调用, 该修饰函数表示本身与对象无太多联系,不需要 self, cls等参数,只是放在类的内部进行管理. @classmethod修饰器修饰的时候, 表示只需要该方法只需要 cls参数, 不需要实例化,即可实现调用)函数修饰器: python函数包含三种内置的函数装饰器, 如@classmethod,@staticmethod, @property, 当然我们也可以自己创造修饰器。 使用装饰器语法: • 语法糖的写法 @function_name def function(): pass

    @classmethod 修饰符对应的函数不需要实例化即可调用, 通过class_name.method()进行调用,不需要 self 参数,但第一个参数需要 cls 参数. @staticmethod 不调用类内部的成员变量,和类本身无过多联系,只是为了便于管理, 只是放在类的声明中。 @property 将函数转换为属性变量,直接进行赋值操作。

    便利的技巧

    ''' aaaa ''' 表示可以将多行字符包括在其中, 并包括换行符, 省得输入 /r 的转义字符,非常方便编写习惯,用于多行内容编写。 这点很像shell脚本中的语法.类似下面所示 << EOF input something.... EOF print(“value:%f”%(x**x)代码中 ** 表示指数幂计算。 print字符串格式化, python中通过%(),将一个含有多个变量值的tuple传递给模板进行格式化输出, 除了该方法,python还提供了format()方法进行格式化输出。 print("name %s %d"%("aaa"12)) 方法/函数返回多个值的时候,如 return x,y时,其实,他返回的是一个 tuple 对象。注意以下例子, 列表b和列表a的地址是一样的, 都指向最开始初始化那个对象,修改b就等于修改a, 而如果要完全拷贝,应该使用copy函数复制. a=[1] 初始化列表 b=a print(a, b, id(a), id(b)) python函数编程,支持可变参数,也就是说传入参数个数可变。 def function(*element), 即等价于传入一个tuple/list对象到函数内部,可理解为C语言中一级指针的用法, 函数内使用的话, 则通过对element 进行for 取值实现调用。 **kw 关键字参数 :支持传入 字典对象, 键值对参数, *argv 可变参数, 传入一个tuple, C/C++中, 指针数组的数组名赋值给 char **p 二级指针, 数组名则赋值给 char *p一级指针。(而二维数组的数组名 相当于数组指针数据类型)python slice功能,非常方便我们遍历列表 比如 L[0:3], 从第0个开始取元素到第2个元素前停止。 神奇的在于,支持取倒数的元素 L[-3:-1], 倒数第三个到倒数第一个。 通过strim函数实现递归,真的美观, 易错: slice功能中,[x:y]第二个值y表示停止值, 只包含除了y索引指向的值。 递归的核心思想, 就在于在一个基础上进行下一步类似的动作 strim(s) if s[1]=" ", 等价于第零个。 return strim(s[1]) elif s[-1]==" " 等价于倒数第一个, return trim s[-1], 除了最后一个为止, python中的for 可迭代的对象, 包括 字符串, 列表,元组, range(),dict默认迭代key, 如果要迭代 value, 要通过dict.value()去调用, 还支持一次性 遍历两个值。 isinstance(a,Iterable), 判断是否可迭代。在python中,Flase, 0, (), [],{}, 都会被视为假。逻辑运算包含 and ,or ,not,最便利的是成员运算符, in和 not in, 可以很快判断一个元素是否被包含。'中文'.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) 含有中文的str无法用ASCII编码,因为中文编码的范围超过了ASCII编码的范围.得到十六进制的整数值的表达形式 print("str:", hex(ord('东'))) str: 0x4e1c 得到中文字符在 utf-8下,即通过一定的编码规则,得到编码值。 print("str:", '东'.encode('utf-8')) str: b’\xe4\xb8\x9c‘ 得到中文字符在 utf-16下的存储形式, print("str:", '东'.encode('utf-16')) str: b’\xff\xfe\x1cN’ 其实等于第一种ord()方法得到的值,是将值进行十六进制存储进行展开,而此处utf-16由于芯片大小端问题,变成 \1c4e. 注意: 输出中\xff\xfe 用来指示大小端的信息(UTF-16LE以FF FE代表,UTF-16BE以FE FF代表)python中很多内置函数随着解释器的运行便会创建起来, 可以进行直接调用。 os.system 用来执行cmd 命令或者linux命令, 会开启一个cmd或者是shell进程作为执行命令的环境。 python中的eval和exec,compile是十分有趣的函数。 eval用来运行单个表达式, 并且返回表达式的计算值。 exec可以用来执行代码段,通过""" 囊括整段代码。 compile就是将将一个字符串编译为字节代码,然后通过eval或者exec来执行编译后的字节代码(目前很少使用,仅作文案记录。) code_block = """ x = 1 y = 2 z = 3 sum = x + y + z print(sum) """ exec(code_block) expr = "9+6" val=eval(expr) print(val)

    lambda [arg1 [,arg2,.....argn]]:expression 帮助函数更为简洁,但是, 并不会提高效率。 lambda构建之后,lambda表达式会构建出一个以arg*为传入参数, expression计算得到的值为返回值的函数。 注意 : expression是单表达式,不是代码块。

    python 中高阶函数技巧:python可以把函数对象名赋值给其他的变量,然后通过该变量进行函数调用, 类似C语言中的函数指针。 Python 中内置的⾼阶函数:

    map 它接收⼀个函数 f 和⼀个 list 并通过把函数 f 依次作⽤在 list 的每个元素上,得到⼀个新的 list 并返回。filter filter()函数接收⼀个函数 f 和⼀个list 这个函数 f 的作⽤是对每个元素进⾏判断,返回 True或 False 根据判断结果过滤掉不符合条件的元素,返回由符合条件元素组成的新list。reduce ⼀个函数 f,⼀个list,但⾏为和 map()不同 reduce()传⼊的函数 f 必须接收两个参数 reduce()对list的每个元素反复调⽤函数f,并返回最终结果值。

    python中的序列化&反序列化,分别是为了便于传输与存储,和跨平台进行数据交互。 一般使用json 模块以及pickle模块,二者不存在什么较大的区别。 序列化: • 变量从内存中变成可存储或传输的过程称之为序列化。 • 在Python中叫pickling。 • 在其他语⾔中也被称之为serialization, marshalling, flattening等等 反序列化: • 把变量内容从序列化的对象重新读到内存⾥称之为反序列化, 即unpickling。

    import pickle dic={"k1":"v1", "k2":"v2"} pickle_dic=pickle.dumps(dic) print(pickle_dic) # 序列化获得十六进制码。 print(pickle.loads(pickle_dic)) # 反序列化得到数据。 python下的多线程是鸡肋, 推荐使用多进程, 有线程的需要的话,还是使用c++来编写代码比较合适。 使用multiprocessing模块,可以模块自带的队列和管道的方式进行进程间通信。正则表达式 :用于处理字符串的强大工具, 拥有独特的语法以及独立的处理引擎。 re模块中 包含search, findAll, sub等方法。 正则表达式使用贪婪与非贪婪匹配原则。 贪婪原则会尽可能多地匹配地匹配字符, 非贪婪原则就是匹配到结果即结束。 str=r'<html><body><h1>hello world<h1></body></html>'中的r表示该字符数据是rawdata(即原生数据),不进行任何转义, backslash表示转义作用(即反斜线字符)。

    '*'表示匹配前一个字符重复 0 次到无限次, '+'表示匹配前一个字符重复 1次到无限次, '?'表示匹配前一个字符重复 0 次到1次。 *? 添加了?之后表示惰性匹配。 元字符比如 \d 表示数字字符匹配。

    关于字符提取的正则表达式的示例代码如下:

    import re rd_str=r'<html><body><h1>hello world</h1></body></html>' pattern=r'(?<=<h1>).+(?=</h1>)' # 匹配获取<h1>和</h1>之间的字符。 #(?<=[string]), 表示 得到在【string】之后的字符, #(?=[string]) 表示得到string 之前的字符串。 # . 表示匹配任意一个字符. # ..表示匹配任意两个字符. # + 表示匹配+符号的前面字符串,并且至少匹配到一个字符。 matcher=re.search(pattern, rd_str) print(matcher.group()) # 提取到hello world
    Processed: 0.025, SQL: 8