orange学习开发
Python编程规范
包名命名为 aaa-bbb-ccc 例如 orange-widget-base
模块名命名 aaabbbccc 例如 orangewidget
utils
name_lookup 传入字符串 返回Python对象 字符串可以是 点 分的包路径
def name_lookup(qualified_name): # type: (str) -> Any """ Return the object referenced by a qualified name (dotted name). """ if "." not in qualified_name: qualified_name = "builtins." + qualified_name module_name, class_name = qualified_name.rsplit(".", 1) module = __import__(module_name, fromlist=[class_name]) return getattr(module, class_name) ret = name_lookup("print") print(ret) ret = name_lookup("orangewidget.zcb") print(ret) ret = name_lookup("orangewidget.zcb.ZCB") print(ret) """ <built-in function print> <module 'orangewidget.zcb' from 'C:\\software\\py_3_8_10\\lib\\site-packages\\orangewidget\\zcb.py'> <class 'orangewidget.zcb.ZCB'> """
Qt
QSettings 配置文件
设置组织域名和应用名字,就可以在不同的地方使用QSettings 的默认构造函数了
from PyQt5.QtCore import QCoreApplication,QSettings if __name__ == '__main__': QCoreApplication.setOrganizationDomain("lxrobot.com") QCoreApplication.setApplicationName("lxrobotics") QCoreApplication.setApplicationVersion("0.0.1") QSettings.setDefaultFormat(QSettings.IniFormat) s = QSettings() print(s.fileName()) # C:/Users/zcb/AppData/Roaming/lxrobot.com/lxrobotics.ini # set value s.beginGroup("application-style") s.setValue("style-name","Funsion") """ 文件中内容如下 [application-style] style-name=Funsion """ """ 关于在多处地方使用 QSettings,没必要使用单例正如官方文档所说: If you use QSettings from many places in your application, you might want to specify the organization name and the application name using QCoreApplication::setOrganizationName() and QCoreApplication::setApplicationName(), and then use the default QSettings constructor: """
QObject deleteLater
Qt由于是由事件来驱动的,所以在删除对象的时候,推荐使用deleteLater,而不是直接delete。
PyQt
自定义信号
import sys from PyQt5.QtCore import QUrl,QObject,pyqtSignal as Signal from PyQt5.QtWidgets import QApplication,QMainWindow,QPushButton from PyQt5.QtGui import QMouseEvent,QDesktopServices class Button(QPushButton): openExternalUrl = Signal(QUrl) def mousePressEvent(self, e: QMouseEvent) -> None: self.openExternalUrl.emit(QUrl("https://space.bilibili.com/441821181")) if __name__ == '__main__': app = QApplication(sys.argv) mw = QMainWindow() btn = Button("点我",mw) btn.openExternalUrl.connect(lambda url:QDesktopServices.openUrl(url)) mw.show() sys.exit(app.exec())
信号槽连接类型
import sys from PyQt5.QtCore import QUrl,QObject,pyqtSignal as Signal from PyQt5.QtWidgets import QApplication,QMainWindow,QPushButton from PyQt5.QtGui import QMouseEvent,QDesktopServices class Button(QPushButton): openExternalUrl = Signal(QUrl) def mousePressEvent(self, e: QMouseEvent) -> None: self.openExternalUrl.emit(QUrl("https://space.bilibili.com/441821181")) print("信号和槽的连接类型如果是直连,那么会立即执行槽函数,并且会阻塞主线程") print("默认类型是Auto,对于单线程来说,就是Direct,对于多线程将是Queued") input("槽函数执行中...(按下回车执行结束)") if __name__ == '__main__': app = QApplication(sys.argv) mw = QMainWindow() btn = Button("点我",mw) btn.openExternalUrl.connect(lambda url:QDesktopServices.openUrl(url)) mw.show() sys.exit(app.exec())
库
pkg_resources
pkg_resources.resource_filename
查找包,并拼接资源文件,输出一个绝对路径,只校验包存在与否,不管后面资源是否存在
查找包的顺序是:先当前工程目录,后库目录
import pkg_resources file1 = pkg_resources.resource_filename(__name__,"zcb1.html") file2 = pkg_resources.resource_filename("tests","zcb2.html") print(file1) print(file2) """ C:\Users\zcb\Envs\envOrange\Lib\site-packages\orangewidget\report\zcb1.html C:\Users\zcb\Envs\envOrange\Lib\site-packages\orangewidget\report\tests\zcb2.html """
pkg_resources.resource_string 读取指定包中的文件为字符串
import pkg_resources pkg_name = "orangecanvas.styles" resource = "darkorange.qss" ret = pkg_resources.resource_string(pkg_name, resource).decode("utf-8") print(ret) """ @canvas_icons: orange; CanvasToolDock QToolBar QToolButton:menu-indicator { height: 8px; width: 8px; } CollapsibleDockWidget QWidget#canvas-quick-dock QToolBar QToolButton:menu-indicator { height: 8px; width: 8px; } """
itertools 库
count
from itertools import count count_iter = count() for i in range(10): print(next(count_iter)) """ Equivalent to: def count(firstval=0, step=1): x = firstval while 1: yield x x += step """ """ output 0 1 2 3 4 5 6 7 8 9 """
argparse 命令行参数解析
从 argparse.NameSpace获取内容
import argparse parser = argparse.ArgumentParser() parser.add_argument("-z") parser.add_argument("c") ret = parser.parse_args() # ret 类型是 argparse.NameSpace # print(ret["z"]) # 错误 # print(ret["c"]) # 错误 print(ret.z) # 正确 print(ret.c) # 正确 print(ret.d) # 正确 但是ret 这个NameSpace没有d这个属性
argparse 真实例子 外加 logging 一起使用
import argparse import logging LOG_LEVEL = [ logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG ] def arg_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( usage="usage: %(prog)s [options] [workflow_file]", formatter_class=argparse.ArgumentDefaultsHelpFormatter # 加上它 当-h 的时候就会打印出默认值了!!! ) # bool no_discovery,default value is False parser.add_argument("--no-discovery", help="Don't run widget discovery(use full cache instead).", action="store_true" ) # bool force_discovery,default value is False parser.add_argument("--force-discovery", help="Force full widget discovery (invalidate cache).", action="store_true" ) # bool no_welcome,default value is False parser.add_argument("--no-welcome", help="Don't show welcome dialog.", action="store_true" ) # bool no_splash,default value is False parser.add_argument("--no-splash", help="Don't show splash scree.", action="store_true" ) # str stylesheet,default value is None parser.add_argument("--stylesheet", help="Application level QSS style sheet to use" ) # str config,default value is None parser.add_argument("--config", help="Configuration namespace" ) # 自定义 参数类型 # log_level log_level,defautl is def log_level(value): if value in ["0","1","2","3","4"]: return LOG_LEVEL[int(value)] elif hasattr(logging,value.upper()): return getattr(logging,value.upper()) else: raise ValueError("Invalid log level dfsdfadfa") parser.add_argument("-l","--log-level", help="Log Level(0,1,2,3,4)", type=log_level, default=logging.ERROR ) return parser if __name__ == "__main__": parser = arg_parser() parser.parse_args() """ python __init__.py -h ------------------------------------------- usage: usage: __init__.py [options] [workflow_file] optional arguments: -h, --help show this help message and exit --no-discovery Don't run widget discovery(use full cache instead). (default: False) --force-discovery Force full widget discovery (invalidate cache). (default: False) --no-welcome Don't show welcome dialog. (default: False) --no-splash Don't show splash scree. (default: False) --stylesheet STYLESHEET Application level QSS style sheet to use (default: None) --config CONFIG Configuration namespace (default: None) -l LOG_LEVEL, --log-level LOG_LEVEL Log Level(0,1,2,3,4) (default: 40) """
argparse.parse_known_args的使用
import argparse import logging LOG_LEVEL = [ logging.CRITICAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG ] def arg_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( usage="usage: %(prog)s [options] [workflow_file]", formatter_class=argparse.ArgumentDefaultsHelpFormatter # 加上它 当-h 的时候就会打印出默认值了!!! ) # bool no_discovery,default value is False parser.add_argument("--no-discovery", help="Don't run widget discovery(use full cache instead).", action="store_true" ) # bool force_discovery,default value is False parser.add_argument("--force-discovery", help="Force full widget discovery (invalidate cache).", action="store_true" ) # bool no_welcome,default value is False parser.add_argument("--no-welcome", help="Don't show welcome dialog.", action="store_true" ) # bool no_splash,default value is False parser.add_argument("--no-splash", help="Don't show splash scree.", action="store_true" ) # str stylesheet,default value is None parser.add_argument("--stylesheet", help="Application level QSS style sheet to use" ) # str config,default value is None parser.add_argument("--config", help="Configuration namespace" ) # 自定义 参数类型 # log_level log_level,defautl is def log_level(value): if value in ["0","1","2","3","4"]: return LOG_LEVEL[int(value)] elif hasattr(logging,value.upper()): return getattr(logging,value.upper()) else: raise ValueError("Invalid log level dfsdfadfa") parser.add_argument("-l","--log-level", help="Log Level(0,1,2,3,4)", type=log_level, default=logging.ERROR ) return parser if __name__ == "__main__": parser = arg_parser() options,argv_rest = parser.parse_known_args("--no-discovery -l 1 -zcb".split()) print(options) print(argv_rest) """ 上面代码中 parser.parse_known_args() 要一个 [str,]的参数 str.split() 默认以 空格进行分割 返回值 第一个是parser.NameSpace,可以理解为一个字典,取值直接通过点 第二个是个列表,是剩余的未解析出的参数 """ """ Namespace(config=None, force_discovery=False, log_level=40, no_discovery=True, no_splash=False, no_welcome=False, stylesheet=None) ['-zcb'] """
bisect模块之 bisect_right
它的一个应用是 用于目录优先级的排序
import bisect # bisect 模块用于维护有序列表 priority = 5 priorities = [p for p in [1,2,7]] insertion_i = bisect.bisect_right(priorities, priority) print(insertion_i) # 返回要插入的索引位置
os
import os def processQssFileName(fileName): print(os.path.splitext(fileName)) if not os.path.splitext(fileName)[1]: # no extension return os.path.extsep.join([fileName, "qss"]) return fileName if __name__ == "__main__": print(processQssFileName("orange")) print(processQssFileName("darkorange.qss")) """ output ('orange', '') orange.qss ('darkorange', '.qss') darkorange.qss """
sys
默认sys.argv 是当前文件
import sys print(sys.argv) """ ['c:/software/py_3_8_10/Lib/site-packages/orangewidget/__init__.py'] """
__import__的fromlist 参数
它的作用是,当fromlist不为空列表时,导入的是最右侧的对象
为空列表时,导入的是最左侧的对象
ret = __import__("zcb.sub") print(ret) ret = __import__("zcb.sub",fromlist=[""]) print(ret) """ <module 'zcb' from 'c:\\software\\py_3_8_10\\Lib\\site-packages\\orangecanvas\\zcb\\__init__.py'> <module 'zcb.sub' from 'c:\\software\\py_3_8_10\\Lib\\site-packages\\orangecanvas\\zcb\\sub.py'> """
ret = __import__("zcb",fromlist=[""]) # 一般写法,比较符号人的认知 print(ret) print(ret.__file__) import os # 获取文件夹名字 fileName = ret.__file__ fileDir = os.path.dirname(fileName) print(fileDir) """ <module 'zcb' from 'c:\\software\\py_3_8_10\\Lib\\site-packages\\orangecanvas\\zcb\\__init__.py'> c:\software\py_3_8_10\Lib\site-packages\orangecanvas\zcb\__init__.py c:\software\py_3_8_10\Lib\site-packages\orangecanvas\zcb """
contextlib ExitStack callback 延迟调用
import contextlib def print1(): print("我是第一个回调") def print2(x): print("我是第二个回调 ",x) with contextlib.ExitStack() as stack: stack.callback(print1) stack.callback(print2,"tom") print("end") print("main logic") """ end 我是第二个回调 tom 我是第一个回调 main logic """
import contextlib def print1(): print("我是第一个回调") def print2(x): print("我是第二个回调 ",x) def print3(*args): print("我是第3个回调 ",args) class Print4: def __exit__(self,*args): print("我是class print4",args) with contextlib.ExitStack() as stack: stack.callback(print1) stack.push(print3) stack.callback(print2,"tom") stack.push(Print4()) # push 类似于回调 如果传入的对象的类有__exit__ 方法则执行它,反之认为是回调 # 1 + "2" print("end") print("main logic") """ end 我是class print4 (None, None, None) 我是第二个回调 tom 我是第3个回调 (None, None, None) 我是第一个回调 main logic """
__getstate__和__setstate__ 序列化与反序列化
配合pickle 一起使用
其他
字符串格式化 %(key)s
通过字典格式化字符串
values = {'city': 'San Francisco', 'state': 'California'} s = "I live in %(city)s, %(state)s" % values print(s) """ I live in San Francisco, California """
Python语法
self.var 并不会覆盖掉 类的var
class Demo: stack = "ttt" def __init__(self) -> None: self.stack = "aaa" d = Demo() print(d.stack) print(Demo.stack) """ aaa ttt """
__path__ 的使用-用来区分package 和 file 它们都是module
import zcb from zcb import sub print(hasattr(zcb, "__path__")) # package --> a directory with __init__.py print(hasattr(sub, "__path__")) # file --> a .py file """ True False """