Python就好比编程界的瑞士军刀,开箱即用、无所不能。这得益于Python简洁易用的语法,以及丰富的第三方库,你想在电脑上做什么,总能找到事半功倍的第三方库。比如,在这新春佳节之际,用Python来写个春联能做到吗?用Python自带的turtle库便可以实现。

turtle写春联

一、turtle库简介

turtle中的绘图是控制一只“小海龟”来实现的,海龟移动的路径便能形成图形。这种程序绘图的方式具有很强的可计算性,也涉及到许多数学几何知识。

turtle的海龟绘图很适合用来引导孩子学习编程。 最初来自于 Wally Feurzeig, Seymour Papert 和 Cynthia Solomon 于 1967 年所创造的 Logo 编程语言。

二、画春联背景

春联背景的绘制比较简单,由于上下联、横批都是矩形,且颜色都是一致的。为了便于代码的复用,可以定义可以一个画背景的函数。如下所示:

def drawChunLianBg(startX=0, startY=0, lenX=100, lenY=100):
    # 设置边框色和背景填充色
    color('Yellow', 'OrangeRed')
    # 抬笔,定位起点
    pu()
    goto(startX, startY)
    # 落笔,绘制春联矩形框,并填充颜色
    pd()
    begin_fill()
    for i in range(2):
        fd(lenX)
        rt(90)
        fd(lenY)
        rt(90)
    end_fill()
    # 结束后抬笔
    pu()

三、写字

方法一:write()函数直接写字

关于写字,turtle提供了一个write()函数。

使用write()函数打印文字效果

优点:可以自定义汉字字体,写出漂亮的字体!

缺点:无法呈现书写字的动态效果。

turtle.write(arg, move=False, align='left', font=('Arial', 8, 'normal'))
  • arg -- 要书写到 TurtleScreen 的对象

  • move -- True/False。 move 为真值,画笔会移至文本的右下角

  • align -- 字符串 "left", "center" 或 "right"。写到当前海龟位置。

  • font -- 一个三元组 (fontname, fontsize, fonttype)

以下是实现关键代码:

def writeWord(target_word, startx, starty):
    # 基于坐标,打印单个汉字
    color("black", "black")
    # 抬笔定位
    pu()
    goto(startx,starty)
    pd()
    # 基于字体,打印汉字
    write(target_word, move=False,align='left',font=('汉仪程行简',24, 'normal')) def writeWords(target_words, startx, starty,lineNum=1):
    # 打印多个汉字,lineNum控制每行的汉字数,默认为1
    # 向右、向下的偏移量
    right_shift = 0
    down_shift = 0
    # 遍历打印汉字
    for word in target_words:
        writeWord(word, startx+right_shift*45, starty-down_shift*45)
        right_shift += 1
        # 判断是否要换行
        if right_shift % lineNum == 0:
            down_shift += 1
            right_shift = 0

main()函数里直接调用drawChunLianBgwriteWords()就可以画出春联和写字啦。

def main():
    initScreen()
    drawChunLianBg(-160, 215, 60, 500)
    writeWords(target_words="一往无前 奔赴星辰大海", startx=-145, starty=175)
    drawChunLianBg(90, 215, 60, 500)
    writeWords(target_words="保持热爱 静待春暖花开", startx=105, starty=175)
    drawChunLianBg(-110, 280, 210, 60)
    writeWords(target_words="虎虎生威", startx=-90, starty=230,lineNum=4)
    pu()
    goto(0, 0)
    done()

方法二:利用坐标“画”汉字

如果要实现本文一开始的书写效果,思路便是要将汉字当作图形画出来。即需要知道每个汉字笔画中的关键坐标,让海龟根据坐标来移动,画出汉字。比如“万”这个字,我们可以这样来绘制:

坐标画“万”字原理

也就是说,坐标越多,画出的汉字效果会越好。但可以想象这是一个非常繁琐、耗时的工作。本想放弃的我,在知乎发现了一位大神也做过类似的尝试,并且是利用Python爬虫实现了从网上获取中文字体笔画坐标。在本人感叹其精妙的代码后,本着没有必要重复造轮子的想法,本人最终决定copy核心代码试一试,没想到竟然成功了!

基本原理是这样的

爬虫+turtle画字

关键代码:

def drawWords(target_words, startx, starty, lineNum=1):
    params = (
        ('font', gen_url_encode_words(target_words)),
        ('shi_fou_zi_dong', '0'),
        ('cache_sjs1', '20031908'),
    )
     # 发起网页请求
    response = requests.get('https://bihua.51240.com/web_system/51240_com_www/system/file/bihua/get_0/',
                            headers=headers,
                            params=dict(params)
                            )     content = response.content.decode('utf-8')
      # 解析每个字的笔画坐标
    content = content.replace(
        'hzbh.main(', '').split(');document.getElementById')[0]
    content = content.split('{')[-1].split("}")[0]
    pattern = re.compile(r'\w:\[(.+?)\]')
    result1 = re.split(pattern, content)
    words_order_list = {}
    words_cnt = 0
    for r in result1:
        sec = re.findall(r'\'.+?\'', r)
        if len(sec):
            orders = sec[1].split('#')
            order_xy_routine = []
            for order in orders:
                order_str = re.findall(r'\(\d+,\d+\)', order)
                order_xy = [eval(xy) for xy in order_str]
                order_xy_routine.append(order_xy)
            words_order_list['{}_{}'.format(
                words_cnt, target_words[words_cnt])] = order_xy_routine
            words_cnt += 1
    setting()  # 画布、画笔设置
    right_shift = 0
    down_shift = 0
    for k, v in words_order_list.items():
        for lines in v:
            pu()
            for xy in lines:
                x, y = xy
                x, y = x * 0.05 + startx + right_shift * 50, -y * 0.05 + starty - down_shift * 50
                print(x, y)
                goto(x, y)
                pd()
        right_shift += 1
        if right_shift % lineNum == 0:
            down_shift += 1
            right_shift = 0

turtle写春联

写字与画字

利用write()写字注重生成的结果,效果更好;而利用坐标“画”字注重过程,是爬虫技术海龟画图的完美合作,更有意思,让人不禁再次感叹Python的NB,每每这时总会想起那句至理名言——“人生苦短,我用Python!”

写在最后

本文是围绕turtle库来构思写春联这件事的,其实用Python写春联远不止这一种方式。比如下面这副春联也是利用Python写的,简直太酷了。

图片库生成的春联

立个小小的flag,明年就来写这样的春联吧。(望不打脸)

最重要的话留在最后,祝大家虎年万事顺遂,保持热爱,奔赴星海!

字节杂谈

关注公众号,回复“春联”,即可获取源代码

Python写春联(turtle版)的更多相关文章

  1. Python写的简陋版一对一聊天工具,全双工

    好该睡觉了,明天还要上班~~~直接上代码,后面再总结 import threading import os import socket def RecvProcess ( UDP_Socket, Lo ...

  2. Python写地铁的到站的原理简易版

    Python地铁的到站流程及原理(个人理解) 今天坐地铁看着站牌就莫名的想如果用Python写其工作原理 是不是很简单就小试牛刀了下大佬们勿喷纯属小弟个人理解 首先来看看地铁上显示的站牌如下: 就想这 ...

  3. 用Python写网络爬虫 第二版

    书籍介绍 书名:用 Python 写网络爬虫(第2版) 内容简介:本书包括网络爬虫的定义以及如何爬取网站,如何使用几种库从网页中抽取数据,如何通过缓存结果避免重复下载的问题,如何通过并行下载来加速数据 ...

  4. Python之路,Day4 - Python基础4 (new版)

    Python之路,Day4 - Python基础4 (new版)   本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...

  5. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

  6. Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)

    我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...

  7. [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source …

    [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source - [Pyth ...

  8. 如何用Python写一个计算器软件 附带效果图

    该计算器使用Python  tkinter模块开发 效果如下图 import tkinter #导入tkinter模块 root = tkinter.Tk() root.minsize(280,500 ...

  9. 【Python】如何基于Python写一个TCP反向连接后门

    首发安全客 如何基于Python写一个TCP反向连接后门 https://www.anquanke.com/post/id/92401 0x0 介绍 在Linux系统做未授权测试,我们须准备一个安全的 ...

随机推荐

  1. 【LeetCode】395. Longest Substring with At Least K Repeating Characters 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/longest- ...

  2. TGAN

    目录 概 主要内容 Saito M., Matsumoto E. & Saito S. Temporal Generative Adversarial Nets with Singular V ...

  3. 使用并行Foreach优化SqlSugarMapper

    最近在迁移公司导入导出项目时,发现导出速度特别慢,大概2K数据需要导出近半个小时,通过在程序各个地方埋点,最终定位到了Sqlsugar的Mapper中,随后通过并行Foreach单独抽出Mapper中 ...

  4. SpringBoot集成MyBatis-Plus自定义SQL

    1.说明 本文介绍Spring Boot集成MyBatis-Plus框架后, 基于已经创建好的Spring Boot工程, 添加自定义的SQL实现复杂查询等操作. 自定义SQL主要有两种方式, 一种是 ...

  5. Oracle数据库导入csv文件(sqlldr命令行)

    1.说明 Oracle数据库导入csv文件, 当csv文件较小时, 可以使用数据库管理工具, 比如DBevaer导入到数据库, 当csv文件很大时, 可以使用Oracle提供的sqlldr命令行工具, ...

  6. mongdb集群

    一.mongodb的集群 mongodb有两种架构: 第一种架构:和mysql的结构类似,也有主从结构,但是他不能实现故障自动切换 于是有了第二种架构.官方不推荐使用这种架构. 第二种:mongodb ...

  7. NoSQL是什么(一)

    最常见的数据库可以分为下面的两种类型: RDBMS(关系型数据库):常见的关系型数据库有 Oracle.DB2.Microsoft SQL Server.Microsoft Access.MySQL: ...

  8. Python_闭包

    闭包并不只是一个python中的概念,在函数式编程语言中应用较为广泛.理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想. 1.概念介绍 首先看一下维基上对闭 ...

  9. dnspython模块报错 AttributeError: 'CNAME' object has no attribute 'address'

    有时候用到这个模块的时候会报错 AttributeError: 'CNAME' object has no attribute 'address' 如下所示 [root@ansible ch01]# ...

  10. 微信小程序组建通信

    子组件传递父组件需要用到triggerEvent方法,当子组件(自定义组件)点击button的时候调用triggerEvent方法传递一些数据,首先第一个属性为自定义名称(myevent)对应父组件( ...