碎言博客

PyKeyBoardFairy可以替代你游戏中的卡键盘和鼠标宏

J.sky 2021-05-21 15:54:50 站长源创

PyKeyBoardFairy

介绍

Python编写的简单版键盘精灵

可以替代你游戏中的卡键盘和鼠标宏。

软件架构

程序唯一依赖外部库: pynput 1.7.3

安装教程

  1. 下载程序, git clone https://gitee.com/J_Sky/py-key-board-fairy.git 或是下载压缩包也可以
  2. 确定系统安装Python,安装依赖: 'pip install pynput'
  3. 修改程序配置文件: main.py keyList 中的配置参数,使之符合模拟按键的需求。
  4. 终端下运行: python main.py ,然后按程序中的启动开关键,系统开始模拟按键。

使用说明

  1. 配置参数:

程序的所有参数都在集中在 main.py keyList ,修改这个列表的配置可以实现多重按键模拟。 按键配置说明: "key_type": "interval",

按键种类: interval:魔法辅助技能键,间隔一定时间按一次 combination:组合技能,一组按键按照一定顺序和间隔时间的模拟按下(每个技能键只按一次) always:一直按着不放开的键,中间可以有少量的时间暂停 当'key_type'=always 是 会多处一个时间参数"t1",具体看先边的解释

"key_switch": Key.ctrl,#开关控制键,负责控制模拟这个技能键的开关,按下ctrl才会启动按年模拟,再次按下ctrl模拟暂停 "key": 'b',#需要模拟按下的技能键 "is_start": 0,#开关,确定当前技能键在程序开启时,默认是关闭的,一般为0及可。 "t": 0.5,#当前按键模拟按下离开的间隔时间,以秒为单位 "t1": 5, #当'key_type'=always此属性有效,表示为按键一直按着不松开5秒。

  1. 参数示例:

需求1:假设有一组技能键:b,c,d 每个技能大约10几秒或几十秒需要按一次,因为时间不确定,所以设置为每0.5秒按一下,启动开关为:左'alt'键。 'keyList'配置如下:

keyList = [
    {
        "key_type": "interval",
        "key_switch": 'alt',
        "key": 'b',
        "is_start": 0,
        "t": 0.5,
    },
    {
        "key_type": "interval",
        "key_switch": 'alt',
        "key": 'c',
        "is_start": 0,
        "t": 0.5,
    },
    {
        "key_type": "interval",
        "key_switch": 'alt',
        "key": 'd',
        "is_start": 0,
        "t": 0.5,
    },
]

需求2:假设有一组技能键:b,c b技能大约10几秒或几十秒需要按一次,因为时间不确定,所以设置为每0.5秒按一下; c技能为需要一直按着5秒,中间停顿0.5秒,启动开关为:左'alt'键。 'keyList'配置如下:

keyList = [
    {
        "key_type": "interval",
        "key_switch": 'alt',
        "key": 'b',
        "is_start": 0,
        "t": 0.5,
    },
    {
        "key_type": "always",
        "key_switch": 'alt',
        "key": 'c',
        "is_start": 0,
        "t": 0.5,
        "t1":5
    },
]

需求3:假设有一组组合技能键:b,c,d 我想按下控制键z键后,先模拟按下b,0.5秒后按下c,1秒后按下d。 'keyList'配置如下:

keyList = [
    {
        "key_type": "combination",
        "key_switch": 'z',
        "key": 'b',
        "is_start": 0,
        "t": 0,
    },
    {
        "key_type": "combination",
        "key_switch": 'z',
        "key": 'c',
        "is_start": 0,
        "t": 0.5,
    },
    {
        "key_type": "combination",
        "key_switch": 'z',
        "key": 'd',
        "is_start": 0,
        "t": 1,
    },
]

以上为常见的一些组合,"key_type": "combination"时候,要注意同一控制键的技能键排列顺序和时间。

参与贡献

暂时没有考虑制作GUI界面,如果有大佬可以试试做个GUI界面来配置keyList,可能会更好些。

仓库地址:

码云仓库:PyKeyBoardFairy

github:PyKeyBoardFairy

Flask-SQLAlchemy 使用学习笔记(下):一对一、一对多、多对多关系

J.sky 2021-03-16 09:38:18 未分类

搭建Flask-SQLAlchemy运行的基本环境

import os
import sys
import click
from flask import Flask
from flask_sqlalchemy import SQLAlchemy  # 数据库依赖

basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
# SQLite URI compatible
WIN = sys.platform.startswith('win')
if WIN:
    prefix = 'sqlite:///'
else:
    prefix = 'sqlite:////'
# 数据库设置
dev_db = prefix + os.path.join(basedir, 'data.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# app.config['SQLALCHEMY_ECHO'] = True # 输出SQL语句到控制台
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URI', dev_db)
db = SQLAlchemy(app)

@app.route('/')
def hello():
u = User.query.get(1)
print(u)
return 'Welcome to hello Hi!'

然后运行 flask run 如果能正常打开,说明你的运行环境已经可以了,若是缺少 Flask-SQLAlchemy 依赖包,请自行安装。 代码编辑好后,我们使用 flask shell 命令来调试 例如 flask dbinit ,每次运行都会删除并创建新的数据库和表, @app.cli.command() 装饰器表明这是一个 flask shell 的命令行。

@app.cli.command()
def dbinit():
    '''删除并重新构建数据库'''
    click.echo('删除数据库和表')
    db.drop_all()
    click.echo("创建数据库!")
    db.create_all()
    click.echo("数据库创建成功!")

做好了以上的准备,就可以开始编写 Model 代码了。

一对一关系

关系使用 relationship() 函数表示。然而外键必须用类 sqlalchemy.schema.ForeignKey 来单独声明. 这里的一对一关系使用User(用户基本资料)和UserData(用户的拓展资料),如果需要给用户的基本资料添加一写拓展资料,这种关系必须是一对一的关系。这里我们假设需要为用户添加一个邮件的拓展资料,分别定义用户User和UserData模型,并使用关系方法定义他们之间的一对一关系:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)
    userdata = db.relationship(
        'UserData', uselist=False, back_populates='user')


class UserData(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(200))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    user = db.relationship('User', back_populates=('userdata'))

uselist=False 标志指示在关系的“多”端放置标量属性而不是集合。将一对多转换为一对一, back_populates() 显示表明双方的对应关系,这种方法比较简单。编写测试代码:

@app.cli.command()
def test1to1():
    '''一对一测试'''
    print("开始测试")
    user = User()
    user.name = 'baby'
    db.session.add(user)
    db.session.commit()
    userdata = UserData()
    userdata.email = 'bosi@qq.com'
    # userdata.user_id = user.id #建立关系方法1
    userdata.user = user  # 建立关系方法2
    db.session.add(userdata)
    db.session.commit()
    print("添加{}成功!".format(user.userdata.email))

添加数据的代码很简单就不解释了。 userdata.user_id = user.id userdata.user = user 是两种定义关系的添加数据的方法。

终端下运行: (base) ( ̄︶ ̄)↗ flask dbinit 删除数据库和表 创建数据库! 数据库创建成功! (base) ( ̄︶ ̄)↗ flask test1to1 开始测试 添加bosi@qq.com成功! (base) ( ̄︶ ̄)↗

我们可以看到上边的运行结果,在DBeaver中打开数据库,可以看到ER图如下:

一对多关系

一对多和一对一关系基本相似,去掉 uselist=False 就可以了,这里使用了作者和文章的一对多关系,一个作者可以发表多篇文章。先定义模型和关系:

class Author(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)
    articles = db.relationship(
        'Article', back_populates='author')

class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), unique=True)
    author_id = db.Column(db.Integer, db.ForeignKey('author.id'))
    author = db.relationship('Author', back_populates='articles')

back_populates ,这个属性非常好用哈,显示的定义了一对多关系。另外记得 db.ForeignKey 绑定主键。我们编写代码测试一下:

@app.cli.command()
def test1tomore():
    author = Author()
    author.name = 'J.sky'
    db.session.add(author)
    db.session.commit()

    ac1 = Article()
    ac1.title = '一对一关系'
    ac1.author_id = author.id  # 建立关系方法1
    ac2 = Article()
    ac2.title = '多对多关系'
    ac2.author = author  # 建立关系方法2
    ac3 = Article()
    ac3.title = '添加append测试'
    author.articles.append(ac3)  # 建立关系方法3
    db.session.add(ac1)
    db.session.add(ac2)
    db.session.commit()

    for ar in author.articles:
        print(ar.title)

运行代码测试:

(base) ( ̄︶ ̄)↗ flask dbinit
删除数据库和表
创建数据库!
数据库创建成功!
(base) ( ̄︶ ̄)↗ flask test1tomore
多对多关系
添加append测试
一对一关系

一对多有三种添加数据和定义关系的方法:

ac1.author_id = author.id  # 建立关系方法1
ac2.author = author  # 建立关系方法2
author.articles.append(ac3)  # 建立关系方法3

多对多关系

如果您想要用多对多关系,您需要定义一个用于关系的辅助表。对于这个辅助表, 强烈建议 不 使用模型,而是采用一个实际的表。这里使用了 Article Tag 之间的多对多关系,一个文章可以有多个标签,一个标签下也可以有多个文章。关系辅助表一定要在模型表之前定义,不然创建表的时候容易报错。先定义关系辅助表:

#关系表要放到表的前边建立
tags = db.Table('tags',
                db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
                db.Column('article_id', db.Integer,
                        db.ForeignKey('article.id'))

接着 Article 添加关系,定义 tag :

class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), unique=True)
    author_id = db.Column(db.Integer, db.ForeignKey('author.id'))
    author = db.relationship('Author', back_populates='articles')
    # 建立多对多关系
    tags = db.relationship('Tag', secondary=tags, back_populates='articles')

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), unique=True)
    articles = db.relationship(
        'Article', secondary=tags, back_populates='tags')

编写代码测试:

@app.cli.command()
def testmtom():
    art1 = Article(title='我是王大锤')
    art2 = Article(title='小狗露西很可爱')
    art3 = Article(title='快乐的写代码')

    tag1 = Tag(name='分类1')
    tag2 = Tag(name='分类2')

    tag1.articles.append(art1)
    tag1.articles.append(art2)
    tag2.articles.append(art2)
    tag2.articles.append(art3)

    db.session.add(art1)
    db.session.add(art2)
    db.session.add(art3)
    db.session.add(tag1)
    db.session.add(tag2)
    db.session.commit()

    for a in tag1.articles:
        print(a.title)

    for t in art2.tags:
        print(t.name)

运行代码:

(base) ( ̄︶ ̄)↗ flask dbinit
删除数据库和表
创建数据库!
数据库创建成功!
(base) ( ̄︶ ̄)↗ flask testmtom
我是王大锤
小狗露西很可爱
分类1
分类2

完整代码请参考仓库里:

github

国内码云镜像

Flask-SQLAlchemy 使用学习笔记(上):简单的配置及使用

J.sky 2021-02-23 15:50:27 Flask

安装和配置

pip install Flask-SQLAlchemy

Flask 中简单配置:

from flask import Flask from flask_sqlalchemy import SQLAlchemy #数据库依赖

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

如上就是官方提供的一个简单的案例。

Flask-SQLAlchemy 扩展能够识别的配置键常用的有:

SQLALCHEMY_DATABASE_URI 用于连接数据库

Postgres:

postgresql://scott:tiger@localhost/mydatabase

MySQL:

mysql://scott:tiger@localhost/mydatabase

Oracle:

oracle://scott:tiger@127.0.0.1:1521/sidname

SQLite (注意开头的四个斜线):

sqlite:////absolute/path/to/foo.db

SQLALCHEMY_ECHO 如果设置成 True SQLAlchemy 将会记录所有 发到标准输出(stderr)的语句,这对调试很有帮助。

Flask-SQLAlchemy 扩展能够识别的配置键的清单

声明模型

一个简单的例子:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

最常用的 Column 类型:

Integer 一个整数
String (size)   有长度限制的字符串
Text    一些较长的 unicode 文本
DateTime    表示为 Python datetime 对象的 时间和日期
Float   存储浮点值
Boolean 存储布尔值
PickleType  存储为一个持久化的 Python 对象
LargeBinary 存储一个任意大的二进制数据

数据的增删改查

插入记录:

user = User('jack',''jack@qq.com')
db.session.add(user)
db.session.commit()

删除记录:

db.session.delete(user)
db.session.commit()

查询记录:

user = User.query.filter_by('jack').first()
user.email # 输出 jack@qq.com

主键查询 get() ,返回所有数据 all()

更新记录和添加记录类似:

user = User.query.get(1)
user.email = 'haha@qq.com'
db.session.delete(user)
db.session.commit()

更多请参考 官方文档

Flask项目配置(config)经验

J.sky 2021-02-22 08:47:45 Flask

Flask项目配置在程序中的配置及读取:

app.config['SECRET_KEY'] = 'secret string'

项目的配置类似字典,但是每次都如上边的方法配置可能有些麻烦,可以创建单独配置文件通过导入:

app.config.from_pyfile('settings.py')

配置文件里的配置项可以写成如下格式:

UPLOAD_PATH = os.path.join(app.root_path, 'uploads')
ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif']

参考文献 Flask项目配置(Configuration)

pipenv 简化的虚拟环境、项目依赖管理工具

J.sky 2021-02-20 15:38:15 Flask

最近学习flask,由于flask框架本身非常极简,功能上需要很多的扩展包,所以项目需要在Python的虚拟环境下来安装管理这些扩展,这样才会方便项目在其他地方进行扩展包的安装。这里推荐 pipenv 来管理虚拟环境和扩展。

## 安装并激活虚拟环境

pip install pipenv

终端进入项目目录, pipenv shell 激活并初始化虚拟环境,

(base) ( ̄︶ ̄)↗ pipenv shell
Launching subshell in virtual environment...
bash-3.2$  . /Users/mac/.local/share/virtualenvs/Flask-BabyLog-cH2fMiTs/bin/activate
(Flask-BabyLog) bash-3.2$

我们可以看到环境配置文件的目录,以及终端的提示符的变化。

使用 exit 退出虚拟环境。

安装项目依赖

把平时的 pip 换成 pipenv

pipenv install requests

打开项目目录中的 Pipfile

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"

[dev-packages]

[requires]
python_version = "3.8"

url 那里可以修改pip的镜像地址,如果下载太慢,可以换成国内的镜像地址。 [packages] 是虚拟环境中安装过的扩展包

假设换了一台机器,我们从GitHub上clone下来项目,当然项目中的包含 Pipfile Pipfile.lock 二个文件。

终端运行:

pipenv install

即可安装项目的所有依赖。

以上为 pipenv 的一些简单操作,更多请参考官方文档。

pipenv官方文档

写在最后

如果讨厌 lock 的生成速度,可以在安装依赖的时候使用 pip ,然后生成依赖列表:

pip freeze > requirements.txt

这样在其他地方创建虚拟环境开荒的时候,可以使用下边的命令安装所有依赖。

pip install -r requirements.txt

虽然这用法有点另类,我只是喜欢 pipenv 的创建、启用和退出的命令,很方便。哈哈哈,实在不行咱就用回 venv 吧,可以参考下文

创建python 虚拟环境 venv

Anaconda常用终端命令

J.sky 2021-02-12 00:20:01 Python

## conda 常用的命令。

1) conda list 查看安装了哪些包。

2) conda env list 或 conda info -e 查看当前存在哪些虚拟环境

3) conda update conda 检查更新当前conda

4) conda --version 查询conda版本

5) conda -h 查询conda的命令使用

activate // 切换到base环境

conda deactivate //退出虚拟环境

activate learn // 切换到learn环境

conda create -n learn python=3 // 创建一个名为learn的环境并指定python版本为3(的最新版本)

conda env list // 列出conda管理的所有环境

conda list // 列出当前环境的所有包

conda install requests 安装requests包

conda remove requests 卸载requets包

conda remove -n learn --all // 删除learn环境及下属所有包

conda update requests 更新requests包

conda env export > environment.yaml // 导出当前环境的包信息

conda env create -f environment.yaml // 用配置文件创建新的虚拟环境

如何打包上传Python程序或模块包到PyPi供其他人使用pip下载?

J.sky 2020-12-07 20:30:45 Python

在学习和编写Python代码的过程中我们经常会用到 pip 来安装一些其他包,用 pip 下载很方便的,那么如果我们自己写了Python的代码包,如何能让别人也试用 pip 来进行安装呢?真巧,我这几天就打包了一个自己写的程序发布到了 pypi.org ,写个上传记录供大家参考。

安装依赖包

whell 用来打包, twine 用来上传包到 pypi.org

pip install whell
pip install twine

如果无法下载,请尝试更换下载源,也可能会遇到pip版本太低需要升级的情况,升级后在试试安装。

pip install wheel

改为:

pip install wheel -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

打包项目配置

需要打包的项目结构图如下:

PrimarySchoolMath 目录就是我们要打包的项目目录(这个名称和setup.py里的项目名称要一致,也是pip install XXXX 的名字是一样的)。 LICENSE 是软件的开源协议,如果不知道怎么选可以到https://choosealicense.com 这里选择一下。 readme.md 是软件或包的说明,可以写一些仓库地址简要说明。 setup.py 打包的配以文件,后边详细说明。

setup.py打包配置文件说明

setup.py :

import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="PrimarySchoolMath",# 项目名称,保证它的唯一性,不要跟已存在的包名冲突即可
    version="1.0.4",#程序版本
    author="J.sky", # 项目作者
    author_email="bosichong@qq.com",#作者邮件
    description="小学生口算题的小应用", # 项目的一句话描述
    long_description=long_description,#加长版描述?
    long_description_content_type="text/markdown",#描述使用Markdown
    url="https://github.com/bosichong/PrimarySchoolMathematics",# 项目地址
    packages=setuptools.find_packages(),#无需修改
    classifiers=[
        "Programming Language :: Python :: 3",#使用Python3
        "License :: OSI Approved :: Apache Software License",#开源协议
        "Operating System :: OS Independent",
    ],
)

至此,所有打包的准备工作都已经准备好了,接下来就是利用命令来打包上传了。

打包

项目目录下打开终端:

python3 setup.py sdist bdist_wheel

打包完毕,此时的项目目录如下:

dist 下就是要上传的打包文件了。

上传到pypi.org

这里的上传可以使用测试上传或是直接上传。

测试上传会将包传到 https://test.pypi.org/ ,所以你需要在这个地址下注册一个测试账号,然后使用一下命令进行上传,这里不再介绍了。

python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*

直接上传到 pypi.org ,使用命令:

python3 -m twine upload dist/*

然后输入在 pypi.org 注册的账号密码就可以上传了。

python3 -m twine upload dist/*
Uploading distributions to https://upload.pypi.org/legacy/
Enter your username: bosichong
Enter your password:

如果没有什么错误就可以上传成功了!登录网站就可以看到刚刚上传的软件包了

然后使用 pip install XXXX 安装测试吧。

其他注意事项

如果需要更新软件包,修改完代码后记得修改 setup.py 中的软件版本,这样才能正常上传。

至此,一次Python软件包的上传就搞定了,简单吧?

聊聊Python中的装饰器

J.sky 2020-10-05 20:34:04 Python

Python装饰器是什么?

在Django中曾经使用过 @fun 这种格式的语法,用在了定义视图的函数上,类似一种拦截器用来控制当前视图的访问权限。

装饰器(decorator)是干嘛的?对于受到封装的原函数来说,装饰器能够在那个函数执行前或者执行后分别运行一些代码,使得可以再装饰器里面访问并修改原函数的参数以及返回值,以实现约束定义、调试程序、注册函数等目标。装饰器一般返回一个包装器(wrapper),而functools.wraps就是装饰包装器的装饰器。

定义一个Python的装饰器

我们定义一个计算Python程序运行时间的装饰器,在定义一个需要运行的韩式,代码如下:

    import time
    import functools

    def t(fun):
    '''定义一个程序运行时间计算函数'''
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
            start = time.time()  # 起始时间
            fun(*args, **kwargs)  # 要执行的函数
            end = time.time()  # 结束时间
            print(fun.__name__, '程序运行时间:{:.2f}ms'.format((end - start) * 1000))
    return wrapper

    @t
    def myfunc(x, y):
    '''打印从x到y的数值'''
    for i in range(x, y):
            print(i)

    myfunc(0, 9)

运行结果:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    myfunc 程序运行时间:0.03ms
    这样的话,我们就可以在不破坏原函数代码的情况下为函数添加了计算当前函数运行时间的功能。

定义一个可以传参的装饰器

如果我们的装饰器需要传入参数该怎么写呢?只需要在 wrapper 外加一层包装即可。代码如下:

    import time
    import functools

    def t(str):
    '''定义一个程序运行时间计算函数'''
    def decorator(fun):
            @functools.wraps(fun)
            def wrapper(*args, **kwargs):
            start = time.time()  # 起始时间
            fun(*args, **kwargs)  # 要执行的函数
            end = time.time()  # 结束时间
            print('传入的字符串是:', str)
            print(fun.__name__, '程序运行时间:{:.2f}ms'.format((end - start) * 1000))
            return wrapper
    return decorator

    @t('hello world')
    def myfunc(x, y):
    '''打印从x到y的数值'''
    for i in range(x, y):
            print(i)

    myfunc(0, 9)

运行结果:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    传入的字符串是: hello world
    myfunc 程序运行时间:0.11ms
    functools.wraps是什么?

functools.wraps 是为了保留原函数的属性不被装饰器破坏,这个时候就可以使用 functools.wraps

functools这个库里有很多关于函数的功能模块,后续我们在继续研究。