比尔盖子 博客

Category: Python

为什么 os.path 可以被直接导入

今天在微博上,@julyclyde 发现了一个看似简单但很有意思的问题,import os.path 的行为很奇怪。

Continue reading

一个不好的冒泡排序算法实现

最近在研究在研究Python,先是做了一个凯撒加密,现在则实现了冒泡排序算法。在实现这个算法时,坚决没有看现成的例子,完全是冒泡排序的文字叙述实现的。

因此,这个算法实现有很多没用的循环和判断,只是练习,在产品中使用肯定是不行的。另外代码中还包括性能统计swapwhiletime,分别计算的是数字的交换次数和循环的进入次数,通过此统计可以看出这个实现多么低效。

#!/usr/bin/python3
times=0
times2=0
swap=0
whiletime=0
list=[858282,4252,5825725,8752,-2825245,8725,-82257465]

while times2 < len(list) -1:
        whiletime+=1
        while times < len(list)-1:
                whiletime+=1
                times+=1
                if list[times-1] > list[times]:
                        swap+=1
                        a=list[times-1]
                        b=list[times]
                        list[times-1]=b
                        list[times]=a
        times2+=1
        times=0

print(list)
print('Swap times:',swap)
print('While times:',whiletime)

Python实现移位密码(凯撒密码)加密

实现移位密码,就是将字母从字母表中向左移动或向右移动。比尔盖子首先想到了ANSI码,但由于不知道怎么处理出界,因此又用列表解决问题。等修改完列表,突然又想到ANSI的解决方案。因此,才写了两个版本。大家根据需求用吧。如果有bug务必提出!

这里有两段代码可以实现,一个是用ANSI码实现;另一个是用列表实现。
但是这些代码一点都不“美”,还需修改。经过修改,已经有些完美了。

更新1:列表版的代码不但不美,而且还有bug,比尔盖子已经做了修改!
更新2:ANSI版的代码虽然实现简单,但是没有注释,而且有两个严重bug,比尔盖子也已经修改!
更新3:使用取余数来代替while循环减去26,在明文、密钥超长的情况下提速至少100倍;化简了ANSI版出界对折的公式。
更新4:重新实现了list版本的加密算法,性能又至少提升2倍。

注:无论代码里是否有声明, 这里的声明将覆盖掉其中的声明。
代码使用GPL v3或更高版本发布。

ANSI版:

这里的代码已经修改了,有了详细注释,而且修正了bug。
很抱歉,代码太多了,因此请去我的Github:https://github.com/biergaizi/caesar-encrypt/tree/查看各个版本,ANSI版的文件名叫”ansi.py”。

列表版:

这里的代码已经修改了,更加美,而且修正了bug。

新版

很抱歉,代码太多了,因此请去我的Github:https://github.com/biergaizi/caesar-encrypt/tree/查看各个版本,列表版的文件名叫”list.py”。

用Python3模拟《侏罗纪公园》中的黑客入侵情节

在《侏罗纪公园》中,有这样一段情节:一位黑客打开一个终端机,试图猜测管理员的密码。失败三次以后,终端上就出现死循环,不停输出:”You didn’t said the magic word!”。而更给力的是,在Youtube上,这段情节视频有一段留言,支持率很高:“The magic word is sudo!”。

而比尔盖子想到,最近刚刚开始学习Python3,是否可以写一段代码来模拟其中的情节?

逻辑设计:
给用户三次输入密码的机会,如果在这三次中用户输入错误,则让用户再次输入并显示错误信息。用户输入了sudo,则显示成功的信息。
如果用户连续三次密码输入错误,则进入死循环,不停显示“You didn’t said the magic word!”。

经过苦思冥想,比尔盖子写出这样一段代码:

#Copyright: Biergaizi | GPL V3
#Developer: Biergaizi, 2011
error = 0
#声明error这个变量,表示用户输入错误的次数

hack = input("Auth_Username:")
#提示用户输入验证用户名,并传入hack这个变量

once = 1
#声明once这个变量是1,表示这是第一次运行程序

while hack != ("sudo"):
#当用户输入的内容不等于sudo时,将程序置于一个循环中

 if once == 1:
  error = error + 1
  print("Permission denied!")
  once = 0
#如果用户是第一次运行程序,则将错误次数增加1,
#显示错误信息,并将once声明为0,表示这已不是第一次运行。并重新执行while块

#因为这是一个循环,因此当用户再次输入错误时,还会进入其中。但是once已经为0,
#因此程序会跳过上面的if块,执行下面的部分:
 hack = input("Auth_Username:")
 error = error + 1
 print("Permission denied")
#再次让用户输入,如果仍输入错误,则再次将错误次数增加1,显示错误信息。并重新执行while块

 if error == 3:
   while hack != ("sudo"):
    print("You didn't said the magic word!")
#如果错误次数以达到3次,则进入死循环,不停输出"You didn't said the magic word"

print("Dear Administrator, welcome!")
exit()
#这也许是这段程序中比较巧妙的部分,只要用户有一次输入"sudo",
#则会被跳出循环,显示这里的成功信息。

但这段代码逻辑还是有些混乱,而且之前的一个版本还存在一个Bug,不画流程图居然都看不出来。
因此,比尔盖子换一种思路:把验证用户名与增加错误次数的这段代码单独提出,写成一个函数,有点类似Linux里的PAM模块。

最终,比尔盖子想方设法精简代码,还是避免不了多了几行代码的事实:

#Copyright: Biergaizi | GPL V3
#Developer: Biergaizi, 2011
error=0
restart=1
#声明两个变量:restart和error,restart为1,error为0

def auth():
  global success,error
#将success,error声明为全局变量,使模块中对这两个变量可以赋值

  if hack == ("sudo"):
   success=1
  if hack != ("sudo"):
   success=0
   error=error+1
#这个模块很好理解,不解释

while restart==1:
#如果restart为1就进入循环,目的是故意构造死循环,
#重复判断,需要跳出死循环时可用break

 hack=input("Auth_Username:")
 auth()
#要求输入用户名,并调用auth模块判断

 if success==1:
  break
#如果用户输入了正确的内容,则用break跳出循环

 if error==3:
  while restart==1:
   print("You didn't said the magic word!")
#如果错误次数等于3,则restart为1进入循环,
#目的同样是构造死循环,并不停输出"You didn't said the magic word!"

 print("Permission denid!")
#这个print是写在这两个if判断之后的,也就是当用户既没有输入正确的内容,
#也没有累计错误三次(即第一、二次输入错误)时,显示错误信息并重复执行while块

print("Dear administrator, welcome!")
exit()
#在第28行,当用户输入正确的内容时,会break跳出循环,则会执行以下内容
#输出成功信息,并退出程序

最近,比尔盖子再次优化该程序:

error=0
import time

def auth(username):
  global error
  if username == ("sudo"):
   return 1
  if username != ("sudo"):
   error=error+1
   return 0

while True:
 hack=input("Auth_Username:")

 if auth(username=hack)==1:
  break
#如果用户输入了正确的内容,则用break跳出循环

 if error==3:
  while True:
   print("You didn't said the magic word!")
   time.sleep(0.5)
#如果错误次数等于3,则进入死循环,并不停输出"You didn't said the magic word!"

 print("Permission denid!")
#这个print是写在这两个if判断之后的,也就是当用户既没有输入正确的内容,
#也没有累计错误三次(即第一、二次输入错误)时,显示错误信息并重复执行while块

print("Dear administrator, welcome!")
exit()
#在第28行,当用户输入正确的内容时,会break跳出循环,则会执行以下内容
#输出成功信息,并退出程序

这样,一个用Python3模拟《侏罗纪公园》中的黑客入侵情节的程序就基本完成了,如果改进建议(比尔盖子最希望再精简代码)和批评意见(代码极不规范,但比尔盖子不知道怎样才规范),欢迎留言指出!

根据过路网友的建议,又修改了一下。在这段时间,比尔盖子的编程风格有了明显变化,第一是自加自减,第二是完全遵守了PEP8的标准,语法检查器没有任何形式的Warning。最不爽的就是那个全局变量了,回头想办法避免,其实很简单。

#!/usr/bin/python3
import time
error = 0

def auth(username):
    global error
    if username == ("sudo"):
        return 1
    else:
        error += 1
        return 0

while True:
    #如果错误次数等于3,则进入死循环,并不停输出"You didn't said the magic word!",否则重复执行while块,继续验证。
    if error == 3:
        print("You didn't said the magic word!")
        time.sleep(0.5)
    else:
        hack = input("Auth_Username:")
        #如果用户输入了正确的内容,则用break跳出循环
        if auth(hack) == 1:
            break

        print("Permission denid!")
#这个print是写在这两个if判断之后的,也就是当用户既没有输入正确的内容,
#也没有累计错误三次(即第一、二次输入错误)时,显示错误信息并重复执行while块

print("Dear administrator, welcome!")
#在第16行,当用户输入正确的内容时,会break跳出循环,则会执行以上内容
#输出成功信息,并退出程序。

做了点小修改,全局变量被拿掉了!

#!/usr/bin/python3
import time

def auth(username):
    if username == ("sudo"):
        return 1
    else:
        return 0

error = 0
while True:
    #如果错误次数等于3,则进入死循环,并不停输出"You didn't said the magic word!",否则重复执行while块,继续验证。
    if error == 3:
        print("You didn't said the magic word!")
        time.sleep(0.5)
    else:
        hack = input("Auth_Username: ")
        #如果用户输入了正确的内容,则用break跳出循环
        if auth(hack) == 1:
            break

        error += 1
        print("Permission denid!")
#这个print是写在这两个if判断之后的,也就是当用户既没有输入正确的内容,
#也没有累计错误三次(即第一、二次输入错误)时,显示错误信息并重复执行while块

print("Dear administrator, welcome!")
#在第16行,当用户输入正确的内容时,会break跳出循环,则会执行以上内容
#输出成功信息,并退出程序。

在 2013 年写了更多面向对象程序后,再次重写此段代码。

#!/usr/bin/env python3
from time import sleep


class UsernameAuthenticator():

    def __init__(self):
        self.__error_count = 0

    @property
    def error_count(self):
        return self.__error_count

    def auth(self, username):
        if username == "sudo":
            return True
        elif username != "sudo" or self.__error_count > 3:
            self.__error_count += 1
            return False


if __name__ == "__main__":
    auth = UsernameAuthenticator()
    while True:
        if auth.error_count >= 3:
            print("You didn't said the magic word!")
            sleep(0.5)
        elif auth.auth(input("Auth_Username: ")):
            print("Dear administrator, welcome!")
            break
        elif auth.error_count < 3:
            print("Permission denid!")

Copyright © 2023 比尔盖子 博客

Theme by Anders NorenUp ↑