Python Terms

Python的使用

Posted by Hao on December 23, 2021

Python的包装在了哪里?Python是如何找包的?

你的 Python 包都装到哪了?

Python的安装包分为三个路径:

  • $path_prefix/lib(标准库路径)
  • $path_prefix/lib/pythonX.Y/site-packages(三方库路径,X.Y 是对应 Python 的主次版本号,如 3.7, 2.6)
  • 当前工作目录(pwd命令的返回结果)

使用python安装本地包时,使用命令pip install -e .,即从当前目录下进行安装,安装包下载到本地,使用-e模式,即e, –editable <path/url> Install a project in editable mode (i.e. setuptools “develop mode”) from a local project path or a VCS url.

该命令需要本地文件夹下配置setup.py文件,配置对应的本地包生成。

为什么要用setup.py? 一般的通用包,我们可以直接用pip install,但是如果是我们自己写的包呢?本地写好了如何发布到服务器端呢?这时可以采用setup.py去构建环境,将自己写的模块以及相应的依赖库一起打包,用setup去完成这个任务。 所以很多github代码都提供setup.py方便我们一键安装。

python项目中setup.py文件

通过setuo生成的xxx.egg-info文件,一般与 xxx文件夹同时存在,一起来表示完整模块。

当系统中有多个python版本的时候,寻找python库的优先级是什么样的?为什么很多时候在固定虚拟环境下,python却寻找了系统下安装的环境?

What is the Cython?

一种编译语言,使用python的语法加上部分受C语言启发的优化,实现类C语言的性能。

A superset of Python that compiles to C, Cython combines the ease of Python and the speed of native cod. Cython is a programming language that aims to be a superset of the Python programming language, designed to give C-like performance with code that is written mostly in Python with optional additional C-inspired syntax. Cython is a compiled language that is typically used to generate CPython extension modules.

pip与pip3和python与python3

如果当前系统有多个版本的python,pip3则表示python3下的环境,而pip则是python2下的环境。当系统里只有python3时,他们的功能相同;而当系统中只有python2时,则只能使用pip。

命令行启动pyhton:

  • python是所有版本的python都有的,输入Python,其实运行的是python安装目录的下的python.exe文件。而py是python3.3后才引入的python的启动器。在python3.3前,输入py是不能启动python的
  • 两者所在的路径不一样,python在python目录下面,比如 C:\Python36 ,而py代表的py.exe文件则在windows目录下面 , 也就是: C:\windows
  • py的功能是强于python的,在py后可以指定所要启动的python版本,比如py -2 会启动python2.X版本
  • 如果系统有多个python版本的话,py会启动新版本的python,但python则会根据系统的环境变量,选择最上面的一个版本运行

python的编码问题

Python2中是ASCII编码,需要更改字符集才能正常支持中文,所以在.py文件中会看到

1
# -*- coding: utf-8 -*- 

Python2代码:

1
2
3
4
5
6
>>> str='梦想还是要有的'
>>> str
'\xe6\xa2\xa6\xe6\x83\xb3\xe8\xbf\x98\xe6\x98\xaf\xe8\xa6\x81\xe6\x9c\x89\xe7\x9a\x84'
>>> str=u'梦想还是要有的'
>>> str
u'\u68a6\u60f3\u8fd8\u662f\u8981\u6709\u7684'

Python3中字符串是Unicode (utf-8)编码,支持中文做标识符

1
2
3
>>> str='梦想还是要有的' 
>>> str 
'梦想还是要有的' 

由于Python3源码文件默认使用utf-8编码,这就使得以下代码是合法的:

1
2
3
>>> 梦想='dream' 
>>> 梦想 
'dream' 

安装指定版本的库

pip install numpy==1.40.1

Python的list与array操作上的区别

list[:]取得值是本身,无法进行list[:, 0]的操作,而array[:, 0]可以提取出二维数组中的第一列数据。

Something about Numpy and Scipy

Scipy - 开源科学计算库,基于numpy的基础上,包括许多子模块,插值运算,优化算法

Python关于列表嵌套数组时,使用+=符号的问题

列表嵌套的数组,如果通过+=符号,则会对整体全部赋值,而通过A = A + b的形式,则不会存在此问题

关于python项目如何import文件的问题

在当前文件夹下,需要有__init.py__文件,使得该文件夹能被识别为python库,同时所调用的文件内应该有该类的初始化函数,__init__函数,确保python能识别该类。

如果当文件路径正确时,python的miport列表会在路径中查找,因此需要讲所需要的路径通过加入到其中:

1
2
import sys
sys.path.append("__PATH___")

关于python脚本的函数调用与main函数

Python调用函数的方法

1
2
3
4
5
6
def main():
    print('this message is from main function')
 
if __name__ == '__main__':
    main()
    print ('now __name__ is %s' %__name__)

当python运行脚本时,可以直接运行其中的函数名,main()函数不作为程序的唯一输入接口。

关于python的部分语法使用

python脚本换行的方法

  • 在该行代码末尾加上续行符“ \”(即空格+’')
  • 加上括号,() {} []中不需要特别加换行符

Python的类变量与实例变量

python for循环从大到小打印

1
2
for i in range(10,1,-1):
    print(i)

Python多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import threading
import time

def T1_job():
    print("T1 start\n")
    for i in range(10):
        time.sleep(0.1)
    print("T1 finish\n")

def T2_job():
    print("T2 start\n")
    print("T2 finish\n")

thread_1 = threading.Thread(target=T1_job, name='T1')
thread_2 = threading.Thread(target=T2_job, name='T2')
thread_1.start() # 开启T1
thread_2.start() # 开启T2
print("all done\n")

Python多线程下运行时,如果指定target为函数,则会直接调用该函数,后续的thread_1.start()便失去意义了

Python如何使用全局变量的问题

Python可以通过global语句来定义一个或多个变量为全局变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#coding=utf-8

def save_case_infos(case_urls):
    global succeeded_total_num, failed_total_num  # 多个变量用逗号分隔
    for case_url in case_urls:

        ok = False

        # some download code ...

        if ok:
            succeeded_total_num += 1
        else:
            failed_total_num += 1
        print("succeeded: " + str(succeeded_total_num) + 
            " failed: " + str(failed_total_num))


# 全局变量,下载成功和失败的视频个数
succeeded_total_num = 0
failed_total_num = 0

或者通过定义类变量来访问其成员,实现全局统一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#coding=utf-8

def save_case_infos(case_urls):
    for case_url in case_urls:

        ok = False

        # some download code ...

        if ok:
            G.succeeded_total_num += 1
        else:
            G.failed_total_num += 1
        print("succeeded: " + str(G.succeeded_total_num) + 
            " failed: " + str(G.failed_total_num))


# 将全局使用的变量定义在类中        
class G:
    succeeded_total_num = 0
    failed_total_num = 0

Python中的@运算符的作用是什么:1. 装饰器 Decorators

  • 作用:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短。
  • 核心思想:函数也是一个对象,且函数对象可以被复制给其他的变量,通过其他变量来调用函数
  • 使用条件:可以在模块或者类的定义层内对函数进行修饰。出现在函数定义的前一行,不允许和函数定义在同一行。

achromaticPixel = np.linalg.inv(ccm @ G_gt) @ achromaticPixel_target

1
2
3
4
5
6
@a_new_decorator
def a_function_requiring_decoration():
  xxx
  return 
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

Tensorflow中的常用实例:在tf2.0中,使用@tf.function来修饰函数,使用静态编译将函数内的代码转换成计算图,因此对函数内可使用的语句有一定限制(仅支持Python语言的一个子集),且需要函数内的操作本身能够被构建为计算图。函数参数只包括TensorFlow张量或NumPy数组,并最好是能够按照计算图的思想去构建函数。在被 @tf.function 修饰的函数之后再次被调用的时候,根据函数名和输入的函数参数的类型计算哈希值,检查哈希表中是否已经有了对应计算图的缓存。如果是,则直接使用已缓存的计算图,否则重新按上述步骤建立计算图。

Python中的@运算符的作用是什么:2. 矩阵乘法 A dedicated infix operator for matrix multiplication (> Python 3.5)

1
2
3
4
5
6
S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)

instead of:

S = dot((dot(H, beta) - r).T,
        dot(inv(dot(dot(H, V), H.T)), dot(H, beta) - r))

Python的输入分隔算法

  1. 默认方法按照空格分隔:str_list = str.split()
  2. 指定分隔符,但只分隔每一个空格:str_list = str.split(“ “)

Python如何指定输出的小数位数

1
print("{:.6f}".format(variable_name))

Python读取文本行的方法

Python的文本读取有三个方法可以调用:

通过open(file_name, privileges)打开文件

  • read():读取全部文本内容,最终存储在str中
  • readaline():逐行读取
  • readlines():逐行全部读取,最终是一个list
  • for line in opened_file: 手动提取每行信息,每行以’\n’结尾

Python深拷贝与浅拷贝的问题

在Python中,对对象有一种很通俗的说法,万物皆对象。

Python的赋值操作属于浅拷贝,通过赋值引用,a 和 b 都指向同一个对象,尤其是当对列表等占用大额内存的值进行拷贝时,浅拷贝的形式,导致变量会同时发生变动。深度拷贝需要引入 copy 模块:

  • 浅拷贝:copy.copy() 或者对象的copy函数等
  • 深拷贝:copy.deepcopy()

拷贝的不同方式:

  1. 赋值: 只是复制了新对象的引用,不会开辟新的内存空间。该对象在内存中所在位置的地址被称为引用。在开发程序时,所定义的变量名实际就对象的地址引用。我们可以通过id的形式来打印其地址引用。
  2. 浅拷贝: 创建新对象,其内容是原对象的引用。即将指定对象中的所有引用拷贝了一份。即,浅拷贝只拷贝了顶层的引用。
  3. 深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。具有单独的内存地址。

Python更新值时,分为可变对象与不可变对象。

  • 可变对象: 列表、字典、集合。所谓可变是指可变对象的值可变,身份是不变的。对于可变对象,赋值: 值相等,地址相等;copy浅拷贝:值相等,地址不相等;deepcopy深拷贝:值相等,地址不相等。
  • 不可变对象:数字、字符串、元组。不可变对象就是对象的身份和值都不可变。新创建的对象被关联到原来的变量名,旧对象被丢弃,垃圾回收器会在适当的时机回收这些对象。对于不可变对象,深浅拷贝均等同于赋值。

对于可变对象深浅拷贝(外层改变元素)

1
2
3
4
5
6
7
8
9
10
11
12
import copy
l=[1,2,3,[4, 5]]

l1=l #赋值
l2=copy.copy(l) #浅拷贝
l3=copy.deepcopy(l) #深拷贝
l.append(6)

print(l)  
print(l1)
print(l2)
print(l3)

结果:

1
2
3
4
[1, 2, 3, [4, 5], 6]     #l添加一个元素6
[1, 2, 3, [4, 5], 6]     #l1跟着添加一个元素6
[1, 2, 3, [4, 5]]        #l2保持不变
[1, 2, 3, [4, 5]]        #l3保持不变

对于可变对象深浅拷贝(内层改变元素)

1
2
3
4
5
6
7
8
9
10
11
12
import copy
l=[1,2,3,[4, 5]]

l1=l #赋值
l2=copy.copy(l) #浅拷贝
l3=copy.deepcopy(l) #深拷贝
l[3].append(6) 

print(l) 
print(l1)
print(l2)
print(l3)

结果:

1
2
3
4
[1, 2, 3, [4, 5, 6]]      #l[3]添加一个元素6
[1, 2, 3, [4, 5, 6]]      #l1跟着添加一个元素6
[1, 2, 3, [4, 5, 6]]      #l2跟着添加一个元素6
[1, 2, 3, [4, 5]]         #l3保持不变

Pathlib

Python的单双引号版本

单双引号均能用来表示字符串,但当用此标识时,字符串内的同样内容则需要被转义符标识。如’I'm fine.’ 双引号同理,但双引号下不需要,”I’m fine.”

三个引号的特殊作用,加注释,对应内容会被python进行解析。

Others

Python正则表达式

在 Python 中,我们可以使用内置的 re 模块来使用正则表达式。

有一点需要特别注意的是,正则表达式使用 对特殊字符进行转义,所以如果我们要使用原始字符串,只需加一个 r 前缀,示例:

1
r'chuanzhiboke\t\.\tpython'

关于.pnc文件,即_pycache_格式?

Python程序运行时不需要编译成二进制代码,而直接从源码运行程序,简单来说是,Python解释器将源码转换为字节码,然后再由解释器来执行这些字节码。

解释器的具体工作:

  1. 完成模块的加载和链接;
  2. 将源代码编译为PyCodeObject对象(即字节码),写入内存中,供CPU读取;
  3. 从内存中读取并执行,结束后将PyCodeObject写回硬盘当中,也就是复制到.pyc或.pyo文件中,以保存当前目录下所有脚本的字节码文件;
  4. 之后若再次执行该脚本,它先检查【本地是否有上述字节码文件】和【该字节码文件的修改时间是否与其脚本一致】,即如解释器发现这个*.py脚本没有修改过,就会跳过编译这一步,直接运行以前生成的保存在 __pycache__文件夹里的 *.pyc文件。这样工程较大时就可以大大缩短项目运行前的准备时间,否则重复上述步骤。

python函数参数中的/和*是什么意思?

在python3.8之后函数参数中允许出现/*号,/用来指明某些函数形参必须使用位置参数而非关键字参数的形式,*出现在函数参数中第一种含义可以表示为可变参数,一般写作*args;对于单独出现在参数中的*参数,则表示,*后面的参数必须为关键字参数的形式。

  1. /参数的用法 如果你想要函数的调用者在某个参数位置只能使用位置参数而不能使用关键字参数传参,那么你只需要在所需位置后面放置一个/
    1
    2
    
      def f1(a, b, /):
     return a + b
    

    对于上面这个函数而言,调用f1时参数a,b只能是特定的值,而不能以关键字传参,即f1(2, 3)执行正确而f1(a=2, 3)和f1(2, b=3)将执行错误。

  2. *参数的用法对于*的第一种用法比较常见,这里不再详述,这里主要详细解释*的第二种用法。如果你希望强迫调用者使用某些参数,且必须以关键字参数的形式传参,那么你只需要在所需位置的前一个位置放置一个*
    1
    2
    
      def f1(a, *, b, c):  
     return a + b + c
    

    对于上面这个函数而言,调用时参数a可以任意值, 但b,c参数一定要以关键字参数的形式传参,如f1(1, b=4, c=5),否则将会报错。

    1
    2
    
      def f2(a, *, b, c=5):
     return a + b + c
    

    如果是这种情况下调用函数,参数a可以任意值,但参数b一定要以关键字参数的形式传参,如f2(2, b=3),但是如果想传入c参数,那么c参数的要求和b参数一样都为关键字参数形式,如f2(2,b=3,c=4)。

python tuple

1
2
tuple = (32,32) + (3,)
tuple.shape = (32, 32, 3)

get the item by space

matrix[start:end:step]

«< array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], [70, 71, 72, 73, 74, 75, 76, 77, 78, 79], [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

new_matrix = matrix[0:6:2, 0:6:2]

«< array([[ 0, 2, 4], [20, 22, 24], [40, 42, 44]])

python的lambda函数

Reference