python3.x 学习杂记
※,miniconda 误删pip(pip uninstall pip)
python -m ensurepip
(这好像是重新安装pip)python -m pip install --upgrade pip
(这好像是更新pip)- 【实操】下载脚本,https://bootstrap.pypa.io/get-pip.py,然后
python get-pip.py
即可。
※,pip常用命令:
-
python -m pip install 与直接 pip install 命令的区别:
1 python -m pip 实际是 path/to/python.exe -m pip,即指定了python解释器的版本,如果系统里装了不同版本的python, 这个命令会明确指出为哪个版本的python安装这个包. 2 Windows系统中, 当您执行pip install --upgrade pip时,系统会认为pip.exe正在运行,因此,Windows是不会让您覆盖pip.exe的。但是,如果您执行python -m pip install --upgrade pip, 就可以避免这个问题,因为正在运行的是python.exe,不是pip.exe。 ※,win10下,python -m pip install 的包缓存的位置: C:\Users\用户名\AppData\Local\pip\cache ; 可以通过7zip软件打开文件查看里面是什么包! ※,Linux下,pip install安装位置:~/.local/lib/python3.8/site-packages //不同的账号位置不一样(家目录不一样),而且是独立的。
- pip config list //查看pip源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
//设置pip清华源pip config set global.index-url http://mirrors.aliyun.com/pypi/simple/
//设置pip阿里源- 【windows】Writing to C:\Users\tonghuangshan\AppData\Roaming\pip\pip.ini
- 【Linux】 Writing to /home/sungrower/.config/pip/pip.conf
- pip list // 查看已安装的package
- pip freeze // 获取全部版本依赖
- ·pip show numpy· // 显示关于numpy包的相关信息,包括包的下载位置。
- pip缓存
- pip cache dir //获取pip缓存的位置
- pip install --no-cache-dir <package> // 在不使用缓存的情况下安装软件包
- pip cache remove matplotlib:从 pip 的缓存中删除所有与 matplotlib 相关的车轮文件。
- pip cache purge:从 pip 的缓存中清除所有车轮文件
- 查看包的版本
- python -m pip install numpy== //通过报错信息来查看numpy包都有哪些版本,已过期,老版本pip可以使用!
- pip index versions <package-name> // 查看包的所有版本。
- 注意不同的python版本支持的包的版本也不一样,比如python3.8支持ray只到2.10版本,python3.10可以支持ray的2.23版本
- pip install numpy==1.19.0 #安装指定版本的包,不加版本则安装最新版本
- pip install -i https://mirrors.aliyun.com/pypi/simple/ numpy // 指定源。这种只对当前安装对命令有用,如果需要全局修改,则需要修改配置文件。
Linux/Mac os 环境中,配置文件位置在 ~/.config/pip/pip.conf(如果不存在创建该目录和文件,另外这个位置也可以~/.pip/pip.conf): mkdir ~/.config/pip/pip.conf 打开配置文件 ~/.config/pip/pip.conf,修改如下: cat > ~/.config/pip/pip.conf << EOF [global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-host = https://pypi.tuna.tsinghua.edu.cn EOF 国内python安装源(即pip使用的安装源): - 阿里云 https://mirrors.aliyun.com/pypi/simple/ - 豆瓣 https://pypi.douban.com/simple/ - 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ - 中国科学技术大学 https://pypi.mirrors.ustc.edu.cn/simple/ - 华中科技大学 https://pypi.hustunique.com/
- pip uninstall numpy // 卸载numpy包. (numpy 1.19.4包有bug)
- pip install -r requirements.txt //-r, --requirement <file> Install from the given requirements file. This option can be used multiple times.
※,查看某个包依赖的其他包版本:pipdeptree -p torch
※,miniconda的安装与卸载与升级
安装:
官方下载地址:点此。直接运行脚本安装即可。安装完后提示,If you'd prefer that conda's base environment not be activated on startup,set the auto_activate_base parameter to false: ·conda config --set auto_activate_base false·。
卸载:参考此文。
Linux卸载过程: 安装在~/miniconda3目录下
rm -rf ~/miniconda3
编辑~/.bash_profile,删除miniconda的相关配置
rm -rf ~/.condarc ~/.conda ~/.continuum
升级miniconda对应的python版本:可以通过miniconda安装更新的python:./Miniconda3-py310_24.4.0-0-Linux-x86_64.sh -u
即可。
※,记录一次在ubuntu20.04LTS上创建虚拟环境运行pytest代码的过程(python3.9)
- cd /root/tong/pytest1/enstellar-api-autotest
- python -m venv .venv //创建虚拟环境
[root@167 enstellar-api-autotest]$ll .venv 总用量 24 drwxr-xr-x 5 root root 4096 11月 23 11:07 ./ drwxr-xr-x 10 root root 4096 11月 23 11:07 ../ drwxr-xr-x 2 root root 4096 11月 23 11:07 bin/ drwxr-xr-x 2 root root 4096 11月 23 11:07 include/ drwxr-xr-x 3 root root 4096 11月 23 11:07 lib/ lrwxrwxrwx 1 root root 3 11月 23 11:07 lib64 -> lib/ -rw-r--r-- 1 root root 81 11月 23 11:07 pyvenv.cfg
- .venv/bin/pip install -r requirements.txt //安装本项目需要的依赖,安装后位于.venv/lib/python3.9/site-packages
- .venv/bin/python xxx.py //正常运行py启动脚本
※,python的类型注解
- https://mp.weixin.qq.com/s/0Qk3XWgdVnoYWS_EnVCqyw
- 官方文档
Annotation.py
# -*- coding: utf-8 -*- """ 类型注解的作用: def get_item(key: K, container: Dict[K, V]) -> V: # ... def get_item(key, container): # ... 上面两个函数功能完全相同,但是没有类型注解的那个,显然需要花更多的时间阅读函数内部的代码,去确认函数到底干了什么。 并且它也无法利用编辑器的类型检查,在早期帮助排除一些低级错误。 """ # 如果你用的是 Python 3.9+ 版本,甚至连 typing 模块都不需要了,内置的容器类型就支持了复合注解:如list[int]而不须List[int] from typing import Sequence, NewType, Tuple, Callable, Any, Protocol, Optional, Union, Literal, TypeVar, List, Dict # 类型别名 vector2d = Tuple[int, int] ''' 自定义类型。类似类型别名,但是有所区别: NewType创建的是原始类型(Tuple[int, int, int])的“子类”. 所以如果一个变量类型定义为vector3d,则必须是用此类型构建出来的对象实例才能通过类型检查, 而使用Tuple[int, int, int]类型的对象如(1,2,3)是不能通过类型检查的 ''' vector3d = NewType("v3d", Tuple[int, int, int]) def foo(bar: str) -> str: return f"a global fooTong function with parameter bar: {bar}" class Person(object): """ 编程习惯:成员变量统一放在前部 """ # 定义Person类的public属性(public成员变量) attr1 = "attr1Value" # 定义Person类的private属性 __attr2 = "attr2Value" '''不定义这些None也行,但是为了类的阅读,建议把成员变量完成的列出在类的前部''' __hobbies = None __age = None name = None # Literal 即字面量。它在定义简单的枚举值时非常好用,比如: __MODE = Literal['r', 'rb', 'w', 'wb'] # 类型别名 """ Person类的构造函数。也可以在构造函数中定义Person类的共有和私有属性 """ def __init__(self: 'Person', name: str, age: int): self.__age = age # Person类的private成员变量 self.name = name # Person类的public成员变量 """类实现了__call__接口,则其实例和普通的函数一样,也是可调用的(callable)""" def __call__(self, arg, *args, **kwargs): print("You are calling an instance of class Person. arg: {}, args:{};kwargs:{}".format(arg, args, kwargs)) # def __call__(self): # print("You are calling an instance of class Person. arg: {}, args:{};kwargs:{}") def getAttr2(self): return self.__attr2 def getAge(self: "Person") -> str: return f'My age is {self.__age}' """ Sequence:在某些情况下,不需要严格区分参数到底是列表还是元组(这种情况还蛮多的), 这时候就可以将它们的特征抽象为更泛化的类型(泛型),比如 Sequence(序列)。 """ def setHobbies(self: "Person", hobbies: Sequence[str]) -> None: self.__hobbies = hobbies def getHobbies(self: "Person") -> str: return f'My hobbies are(is) {self.__hobbies}' # Optional[str]表示str类型或None类型。 Optional[str] === Union[str, None] def optionalTest(self: "Person", a: int) -> Optional[str]: if a == 1: return "good" # union[str, int]表示str或int中的一种。如果输入是str,返回是int也能通过类型检查,可能不是我们需要的,所以需要泛型 def unionTest(self: "Person", param: Union[str, int]) -> Union[str, int]: return param def open_helper(self, file: str, mode: __MODE) -> str: pass def vector2dTest(self: 'Person', vector2d: vector2d): print(f'person.vector2dTest: {vector2d}') def vector3dTest(self: "Person", vector3d: vector3d) -> None: print(f'person.vector3dTest: {vector3d}') '''函数成功执行完毕,则默认会返回一个None,而不是NoReturn。注意区别。下面的函数是NoReturn''' # def foo1(self) -> NoReturn: # raise RuntimeWarning("Oh,no...") def call(self: "Person", callable: Callable, arg, *args, **kwargs) -> Any: return callable(arg, *args, **kwargs) """ Protocol:即协议。我们通常说一个对象遵守了某个”协议“,意思是这个对象实现了”协议“中规定的属性或者方法 """ # 一个类继承了Protocol(类型注解中的一个类),则只要实现了此类的方法都可视为此类的类型 class Proto(Protocol): def foo(self): pass class A: def foo(self): pass class B: def bar(self): pass def ProtocolTest(a: Proto): pass # 类型检查通过! A()实现了foo,所以A()可以视为Proto类型 ProtocolTest(A()) # 类型检查不通过! B()没有实现foo,所以B()不能视为Proto类型 ProtocolTest(B()) """END Protocol""" """START 泛型""" # 定义泛型 T: T必须是str 或 int 中的其中一种。两个T必须名称一致 T = TypeVar("T", str, int) def genericTest(a: T, b: T) -> List[T]: return [a, b] # 泛型类型检查不通过 print(genericTest(18, "晴雯")) # 泛型类型检查通过 print(genericTest("18", "晴雯")) '''泛型示例二''' """ 代码中定义了两个泛型 K 和 V,对它两的类型没有做任何限制,也就是说可以是任意类型。 函数 get_item() 接受两个参数。这个函数不关心参数 container 字典的键是什么类型,或者字典的值是什么类型; 但它的参数 container 必须是字典,参数 key 必须与字典的键为同类型,并且返回值和字典的值必须为同类型。 仅仅通过查看函数的类型注解,就可以获得所有这些信息。 """ K = TypeVar("K") V = TypeVar("V") def getItem(key: K, container: Dict[K, V]) -> V: return container[key] dict1 = {"age": 333} dict2 = {(1, 3): "Tonus"} # 字典键值须是不变的类型,如str, int, tuple等 # 例一: 类型检查通过 getItem("age", dict1) # 例二: 类型检查通过,但是运行时会报错,因为没有name键 try: # try语句话出现了异常之后,后面的语句不会再执行 print(getItem("name", dict1)) print("###### Test whether this line runs ########") # 上一行出错后,此行将不会被执行 except KeyError: print("No Such Key: %s" % "name") # 例三: 类型检查不通过,运行时也会报错 # print(getItem(333, dict1)) # 例四:类型检查通过 print(getItem((1, 3), dict2), end="##\n") """END 泛型""" if __name__ == "__main__": p: Person = Person("TOnus", 333) print("##%s##" % p.attr1) # print("##%s##" % p.__attr2()) # Person类外无法访问私有属性__attr2 print("##%s##" % p.getAttr2()) print("My name is {1}, my age is {0}".format(p.getAge(), p.name)) print(p.getHobbies()) p.setHobbies(["抽烟", '喝酒', '烫头']) print(p.getHobbies()) # 类型别名 p.vector2dTest((1, 3)) # p.vector2dTest(vector2d((1,2))) #报错 # 自定义类型v3d:必须是vector3d的实例才能通过类型检查,原始类型(Tuple[int, int, int])无法通过类型检查 p.vector3dTest((11, 22, 33)) # 无法通过类型检查,但是不影响运行 p.vector3dTest(vector3d((1, 2, 3))) # 调用类实例:类实现了__call__接口则和普通函数一样是可调用的。 # p(1, 2, 3, {8: "Tong"}, {(66, 88): "huangshan"}, age=33, hobbies=['smoke', 'drink wine', 'hairPerm']) p.call(p, 1, 88, c=3) print(p.call(foo, 33)) print(p.call(p.vector3dTest, 33))
※, anaconda
1. 安装完anaconda(安装目录D:\software)后,需要将如下路径添加进PATH中
+ D:\software\anaconda3
+ D:\software\anaconda3\Library\bin
+ D:\software\anaconda3\Scripts
2. 记录一个问题
pycharm中一个python工程,创建了venv并启用后,使用pip安装python包时报错:pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available。无法下载任何python包。
但是使用Anaconda Prompt的命令行窗口pip install可以成功安装python包。在两个环境下分别输入命令path查看环境变量,发现Anaconda Prompt窗口的环境变量多了 D:\software\anaconda3\Library\bin 和 D:\software\anaconda3\Scripts(其实还有这两个目录的一些子目录).
在win10系统的环境变量中添加了这两个路径,打开一个新的terminal,发现还是不行。重启pycharm,然后就可以了。
【总结】新增环境变量后,pycharm的只有重启后才能生效,重新打开新的terminal是不生效的。
※, vscode启用虚拟环境(虚拟环境避免了全局环境出现不同版本的包从而产生的混乱):
1. py -3 -m venv .venv // 初始化虚拟环境时使用,初始化之后便不再需要此命令
2. Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process --Scope CurrentUser
3. .venv\Scripts\activate
4. 在虚拟环境下直接输入 deactive 退出虚拟环境
※, python http server
- python -m CGIHTTPServer 8080 // python2
- python -m SimpleHTTPServer 9191 // python2
- python -m http/server 8080 --cgi //python3
- python -m http.server 8080 --cgi //python3 windows
※,vscode中的pylint安装路径
- vscode和pycharm的环境变量有些差异,可以通过打印sys.path来查看不同的环境变量。vscode的环境变量有一个是:C:\Users\Everest\AppData\Roaming\Python\Python39\site-packages;通过vscode的提示框安装的pylint的安装路径就在这个文件夹下。
※,★★★★★python中 import 的使用方法(包的引入):
- 首先,python查找模块需要搜索的路径为·sys.path·下所有的目录。sys.path是指定模块的搜索路径的字符串列表 。
- sys模块包含了与python解释器和它的环境有关的函数, 里面有个 sys.path属性。它是一个list.默然情况下python导入文件或者模块的话,他会先在sys.path里找模块的路径。如果没有的话,程序就会报错。
- sys.path下的路径包含如下:
- 脚本所在文件夹(当前文件夹),亦即sys.path[0],此列表的第一项,在程序启动时初始化,是包含用来调用Python解释器的脚本的目录。如果脚本目录不可用(例如,如果解释器被交互式地调用,或者脚本是从标准输入读取的),path[0]是空字符串,它引导Python首先在当前目录中搜索模块。
- 标准库:(自己用的是anaconda,标准库路径为:D:\software\anaconda\Lib)
- 第三方库:标准库Lib目录下的site-package目录。(D:\software\anaconda\Lib\site-packages)
- 修改sys.path的方法:
- 动态加入:sys.path.append("mypath")。即时生效的方法,在模块里面修改sys.path值,这种方法修改的sys.path作用域只是当前进程,进程结束后就失效了。
- 当出现ModuleNotFoundError的错误时,就是因为sys.path中没有包含进去包所在的目录。
- 添加的path可以使用sys.path.append(os.getcwd())。关于当前工作路径和当前文件路径的区别,参考此文。
- pycharm中os.getcwd()的返回结果是由配置Working directory确定的。
- 添加.pth文件:在site-packages/ 增加一个路径文件,如mypkgpath.pth,必须以.pth为后缀,将模块的路径写进去,一行一个路径,写上要加入的模块文件所在的目录名称。这种方法一劳永逸, 简单暴力。
- 设置系统环境变量·PYTHONPATH·,在这个环境变量中输入相关的路径,不同的路径之间用分号分开。路径会自动加入到sys.path中。(实测可以)。
- 动态加入:sys.path.append("mypath")。即时生效的方法,在模块里面修改sys.path值,这种方法修改的sys.path作用域只是当前进程,进程结束后就失效了。
- 文件夹下含有 ·__init__.py·文件的会被识别为python的包,又叫模块module。(另注:在python3.9 pycharm环境下测试,不使用__init__.py文件也能直接导入文件或变量)
- __init__.py 文件除了可以将文件夹标志为module以外,还可以在其中定义或者引入变量、类、函数等,这些属于module级别的变量、类、函数等。在此文件中定义或导入的变量可以直接使用module前缀被使用。
- 引入各层级模块(目录)的方法
- 从工作区根目录一级一级引入
- 使用sys.path进入某个目录,然后引入此目录下的各个包。比如引入上级目录中的某个包可以使用此种方式!
- 可以如下使用import:
- ·import module`:此时可以使用 属于module级别的变量myVar,使用方法:带着module前缀,print(module.myVar)
- `import ...`此种方式引入最深只能引入到文件级别,且使用时必须带着前缀。可以取别名(取别名后原名称不再可用)。
- `from module import myVar` // 引入module级别的变量myVar。使用方法:直接使用,print(myVar).
- `from ... import xxx` 此种方式引入最深可以引入到代码级别(文件中的变量、方法等都可以)。使用时直接用from ... import 后的名字即可。可以取别名(取别名后原名称不再可用)。
- `from module import myFile` // 引入module下的某个python文件,此时使用文件中的函数、变量、类等需要带着文件名,print(myFile.myVar)
- `from module.myFile import myVar` //引入module下myFile中的某个变量,使用方法:直接使用,print(myVar)
- ·import module`:此时可以使用 属于module级别的变量myVar,使用方法:带着module前缀,print(module.myVar)
- 如果从两个不同的地方引入了名称相同的变量,那么后引入的会覆盖前面引入的。
- 相对引入、绝对引入等其他知识点:参考此文章
※,
★,杂记: