Article Summary
GPT 4

os

os.getcwd()

查看当前路径。

os.listdir(path)

返回指定目录下包含的文件和目录名列表。

os.path.abspath(path)

返回路径 path 的绝对路径。

os.path.split(path)

将路径 path 拆分为目录和文件两部分,返回结果为元组类型。

os.path.join(path, *paths)

将一个或多个 path(文件或目录) 进行拼接。

os.path.getctime(path)

返回 path(文件或目录) 在系统中的创建时间。

os.path.getmtime(path)

返回 path(文件或目录)的最后修改时间。

os.makedirs()

创建多级目录。

time

struct_time

代表一个时间对象,可以通过索引以及属性名来访问。


索引	属性	值
0	tm_year(年)	如:1945
1	tm_mon(月)	1 ~ 12
2	tm_mday(日)	1 ~ 31
3	tm_hour(时)	0 ~ 23
4	tm_min(分)	0 ~ 59
5	tm_sec(秒)	0 ~ 61
6	tm_wday(周)	0 ~ 6
7	tm_yday(一年内第几天)	1 ~ 366
8	tm_isdst(夏时令)	-101

localtime()表示当前时间,返回类型为 struct_time对象

常用函数


函数(常量)	说明
time()	返回当前时间的时间戳
gmtime([secs])	将时间戳转换为格林威治天文时间下的 struct_time,可选参数 secs 表示从 epoch 到现在的秒数,默认为当前时间
localtime([secs])	与 gmtime() 相似,返回当地时间下的 struct_time
mktime(t)	localtime() 的反函数
asctime([t])	接收一个 struct_time 表示的时间,返回形式为:Mon Dec  2 08:53:47 2019 的字符串
ctime([secs])	ctime(secs) 相当于 asctime(localtime(secs))
strftime(format[, t])	格式化日期,接收一个 struct_time 表示的时间,并返回以可读字符串表示的当地时间
sleep(secs)	暂停执行调用线程指定的秒数
altzone	本地 DST 时区的偏移量,以 UTC 为单位的秒数
timezone	本地(非 DST)时区的偏移量,UTC 以西的秒数(西欧大部分地区为负,美国为正,英国为零)
tzname	两个字符串的元组:第一个是本地非 DST 时区的名称,第二个是本地 DST 时区的名称

多线程

线程是CPU分配资源的基本单位。当一程序开始运行,这个程序就变成了一个进程,而一个进程相当于一个或者多个线程。当没有多线程编程时,一个进程相当于一个主线程;当有多线程编程时,一个进程包含多个线程(含主线程)。使用线程可以实现程序大的开发。

创建多线程
  1. threading.Thread()创建

语法形式:

threading.Thread(group=nore,target=none,args=(),kwargs={},*,daemon=None)

~group:必须为None,于ThreadGroup类相关,一般不使用。

~target:线程调用的对象,就是目标函数。

~name:为线程起这个名字。默认是Tread-x,x是序号,由1开始,第一个创建的线程名字就是Tread-1。

~args:为目标函数传递关键字参数,字典。

~daemon:用来设置线程是否随主线程退出而退出。

import threading
def test(x,y):
   for i in range(x,y):
       print(i)
t1 = threadingTthread(name='t1',target= test,args= (1,10))
t2 = threading.Thread(name='t2',target= test,args= (11,20))
t1.start()
t2.start()

两个程序是并发运行,所以顺序可能不

  1. treading.Thread类的继承

    import threading
    class mythread(threading.Thread):
       def run(self):
         for i in range(1,10):
           print(i)
    t1=mythread();
    t2=mythread();
    t1.start()
    t2.start()
    
    
    

主线程

第一个启动的线程就是主线程

父线程: 启动A线程中启动了线程B,A就是B的父线程

子线程:B就是A的子线程。

创建线程时有一个damon属性,用它来判断主线程。当daemon设置False时,线程不会随主线程退出而退出,主线程会一直等着子线程执行完;。当daemon设置True时,线程会随主线程退出而退出,主线程结束其他的子线程会强制退出。

阻塞线程

在一个线程中调用另一个线程的join方法,调用者被阻塞,知道调用线程被终止。

语法形式:

join(timeout -= None)

不设置时,就一直等待被调用线程结束。

import time
import threading
class mythread(threading.Thread):
   def run(self):
     for i in range(1,10):
       print(i)
t1=mythread()
t1.start()
t1.join()
print("hello")
hello将会在输出玩0-9后再输出

判断主线程是否活动

run() :表示线程活动的方法

start() :启动线程

join() :等待线程终止

isAlive() :返回线程是否活动

getAame() :返回线程名称

setName() :设置线程名称

线程同步

python的锁就解决这一问题,锁住线程,只允许一个线程操作,其他线程排队等待,待当前线程操作完毕后,再按顺序一个一个来运行。
python中的锁:

python的threading模块提供了RLock锁解决方法。在某一时间只能让一个线程操作的语句放到RLock的acquire方法和release方法之间,即acquire相当于给RLack上锁,而release相当于解锁

import threading
class mythread(threading.Thread):
 def run(self):
  global x                   #声明一个全局变量
  lock.acquire()             #上锁
  x +=10
  print('%s:%d'%(self.name,x))
  lock.release()             #解锁
x = 0                        #设置全局变量初始值
lock = threading.RLock()     #创建可重入锁
list1 = []                   
for i in range(5):   
 list1.append(mythread())    #创建五个线程,放到同一列表中
for i in list1:
 i.start()                   #开启列表线程
python中的条件锁
threading.Condition(lock=None)

实现条件对象的类。它具有如下方法:

  • acquire(*args):请求底层锁。
  • release():释放底层锁。
  • wait(timeout=None):等待直到被通知或发生超时。
  • wait_for(predicate, timeout=None):等待直到条件计算为 True,predicate 是一个可调用对象且它的返回值可被解释为一个布尔值。
  • notify(n=1):默认唤醒一个等待该条件的线程。

面向对象编程

将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便,代码如下所示

class Person(object):

    def __init__(self, name, age):
        self._name = name
        self._age = age

    # 访问器 - getter方法
    @property
    def name(self):
        return self._name

    # 访问器 - getter方法
    @property
    def age(self):
        return self._age

    # 修改器 - setter方法
    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 16:
            print('%s正在玩飞行棋.' % self._name)
        else:
            print('%s正在玩斗地主.' % self._name)


def main():
    person = Person('王大锤', 12)
    person.play()
    person.age = 22
    person.play()
    # person.name = '白元芳'  # AttributeError: can't set attribute


if __name__ == '__main__':
    main()

__slots__魔法

定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。

slots = (‘_name’, ‘_age’, ‘_gender’)

静态方法与类方法

静态方法与类方法都是通过装饰器来定义的,区别在于静态方法不需要self参数,而类方法需要一个cls参数,并且可以通过cls调用类属性。
例如我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。我们可以使用静态方法来解决这类问题,代码如下所示。

from math import sqrt


class Triangle(object):

    def __init__(self, a, b, c):
        self._a = a
        self._b = b
        self._c = c

    @staticmethod
    def is_valid(a, b, c):
        return a + b > c and b + c > a and a + c > b

    def perimeter(self):
        return self._a + self._b + self._c

    def area(self):
        half = self.perimeter() / 2
        return sqrt(half * (half - self._a) *
                    (half - self._b) * (half - self._c))


def main():
    a, b, c = 3, 4, 5
    # 静态方法和类方法都是通过给类发消息来调用的
    if Triangle.is_valid(a, b, c):
        t = Triangle(a, b, c)
        print(t.perimeter())
        # 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数
        # print(Triangle.perimeter(t))
        print(t.area())
        # print(Triangle.area(t))
    else:
        print('无法构成三角形.')


if __name__ == '__main__':
    main()

类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象,代码如下所示。

from time import time, localtime, sleep


class Clock(object):
    """数字时钟"""

    def __init__(self, hour=0, minute=0, second=0):
        self._hour = hour
        self._minute = minute
        self._second = second

    @classmethod
    def now(cls):
        ctime = localtime(time())
        return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def show(self):
        """显示时间"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    # 通过类方法创建对象并获取系统时间
    clock = Clock.now()
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。

图形用户界面和游戏开发

python默认的UGI是Tkinter,但Tkinter不支持跨平台,所以需要使用Pygame来完成游戏开发。
基本上使用tkinter来开发GUI应用需要以下5个步骤:

导入tkinter模块中我们需要的东西。
创建一个顶层窗口对象并用它来承载整个GUI应用。
在顶层窗口对象上添加GUI组件。
通过代码将这些GUI组件的功能组织起来。
进入主事件循环(main loop)。

pygame