返回顶部

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'>
"""
View Code

 

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:
    """
View Code

 

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())
View Code

 

信号槽连接类型

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())
View Code

 

 

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
"""
View Code

 

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;
}
"""
pkg_resources.resource_string

 

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
"""
View Code

 

 

 

 

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)
"""
View Code

 

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']
    """
View Code

 

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)  # 返回要插入的索引位置
View Code

 

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
"""
os.path.splitext判断文件是否有扩展名

 

 

 

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'>
"""
View Code
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
"""
View Code

 

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
"""
stack callback vs push

 

__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
"""
View Code

 

posted @ 2022-10-03 17:48  Zcb0812  阅读(72)  评论(0编辑  收藏  举报