2

Python-基础学习-第二轮 - ML李嘉图

 1 year ago
source link: https://www.cnblogs.com/zwtblog/p/16560143.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Python-基础学习-第二轮 - ML李嘉图 - 博客园

Python 默认拥有以下内置数据类型:

文本类型: str
数值类型: int, float, complex
序列类型: list, tuple, range
映射类型: dict
集合类型: set, frozenset
布尔类型: bool
二进制类型: bytes, bytearray, memoryview

在 Python 中,当您为变量赋值时,会设置数据类型:

示例 数据类型
x = "Hello World" str
x = 29 int
x = 29.5 float
x = 1j complex
x = ["apple", "banana", "cherry"] list
x = ("apple", "banana", "cherry") tuple
x = range(6) range
x = {"name" : "Bill", "age" : 63} dict
x = {"apple", "banana", "cherry"} set
x = frozenset({"apple", "banana", "cherry"}) frozenset
x = True bool
x = b"Hello" bytes
x = bytearray(5) bytearray
x = memoryview(bytes(5)) memoryview

如果希望指定数据类型,则您可以使用以下构造函数:

示例 数据类型
x = str("Hello World") str
x = int(29) int
x = float(29.5) float
x = complex(1j) complex
x = list(("apple", "banana", "cherry")) list
x = tuple(("apple", "banana", "cherry")) tuple
x = range(6) range
x = dict(name="Bill", age=36) dict
x = set(("apple", "banana", "cherry")) set
x = frozenset(("apple", "banana", "cherry")) frozenset
x = bool(5) bool
x = bytes(5) bytes
x = bytearray(5) bytearray
x = memoryview(bytes(5)) memoryview

open函数的参数

要读写文件,首先要通过内置函数open 打开文件,获得文件对象。

函数open的参数如下

open(
    file, 
    mode='r', 
    buffering=-1, 
    encoding=None, 
    errors=None, 
    newline=None, 
    closefd=True, 
    opener=None
    ) 

其中下面这3个参数是我们常用的。

  • 参数 file

    file参数指定了要打开文件的路径。

    可以是相对路径,比如 ‘log.txt’, 就是指当前工作目录下面的log.txt 文件, 
    也可以是绝对路径,比如 ’d:\project\log\log.txt',
    
  • 参数 mode

    mode参数指定了文件打开的 模式 ,打开文件的模式,决定了可以怎样操作文件。

    常用的打开模式有

    • r 只读文本模式打开,这是最常用的一种模式
    • w 只写文本模式打开
    • a 追加文本模式打开

    如果我们要 读取文本文件内容到字符串对象中 , 就应该使用 r 模式。

    我们可以发现mode参数的缺省值 就是 ‘r’ 。

    就是说,调用open函数时,如果没有指定参数mode的值,那么该参数就使用缺省值 ‘r’,表示只读打开。

    如果我们要 创建一个新文件写入内容,或者清空某个文本文件重新写入内容, 就应该使用 ‘w’ 模式。

    如果我们要 从某个文件末尾添加内容, 就应该使用 ‘a’ 模式。

  • 参数 encoding

    encoding 参数指定了读写文本文件时,使用的 字符编解码 方式。

    调用open函数时,如果传入了encoding参数值:

      后面调用write写入字符串到文件中,open函数会使用指定encoding编码为字节串;
        
      后面调用read从文件中读取内容,open函数会使用指定encoding解码为字符串对象
    

    如果调用的时候没有传入encoding参数值,open函数会使用系统缺省字符编码方式。 比如在中文的Windows系统上,就是使用cp936(就是gbk编码)。

    建议大家编写代码 读写文本文件时,都指定该参数的值。

if __name__ == '__main__':
    # 指定编码方式为 utf8
    f = open('D:/Code2022/Python/pythonProjectStudy/table_contents/tmp.txt', 'w', encoding='utf8')

    # write方法会将字符串编码为utf8字节串写入文件
    f.write('李嘉图:祝大家学有所成!')

    # 文件操作完毕后, 使用close 方法关闭该文件对象
    f.close()
    # 指定编码方式为utf8
    f = open('D:/Code2022/Python/pythonProjectStudy/table_contents/tmp.txt', 'r', encoding='utf8')

    # read 方法会在读取文件中的原始字节串后, 根据上面指定的gbk解码为字符串对象返回
    content = f.read()

    # 文件操作完毕后, 使用close 方法关闭该文件对象
    f.close()

    # 通过字符串的split方法获取其中用户名部分
    name = content.split(':')[0]

    print(name)

with

if __name__ == '__main__':
    f = open('D:/Code2022/Python/pythonProjectStudy/table_contents/tmp.txt', 'w', encoding='utf8')
    f.write('李嘉图:祝大家学有所成!')
    f.close()

    with open('D:/Code2022/Python/pythonProjectStudy/table_contents/tmp.txt', 'r', encoding='utf8') as f:
        linelist = f.readlines()
        for line in linelist:
            print(line)

附加:文件和目录

https://www.byhy.net/tut/py/extra/file_dir/

自调用其他程序

Python中调用外部程序主要是通过两个方法实现的, 一个是os库的 system 函数,另外一个是 subprocess 库。

os.system函数

使用os库的 system 函数 调用其它程序 是非常方便的。就把命令行内容 作为 system 函数的参数 即可

import os

if __name__ == '__main__':
    os.system('cd D:/test && mkdir test.txt')

os.system 函数调用外部程序的时候, 必须要等被调用程序执行结束, 才会接着往下执行代码。 否则就会一直等待

os.system 函数没法获取 被调用程序输出到终端窗口的内容。 如果需要对被调用程序的输出信息进行处理的话, 可以使用 subprocess 模块。

os.startfile 函数

如果我们想达到类似文件浏览器双击打开一个文件的效果可以使用 os.startfile 函数。

这个函数的参数可以是任何 非可执行程序 文件

os.startfile('d:\\统计数据.xlsx')

可以调用该xlsx对应的关联程序(Excel)来打开该文件。

subprocess 模块

Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。

线程和进程

创建新线程

# 从 threading 库中导入Thread类
from threading import Thread
from time import sleep


# 定义一个函数,作为新线程执行的入口函数
def threadFunc(arg1, arg2):
    print('子线程 开始')
    print(f'线程函数参数是:{arg1}, {arg2}')
    sleep(5)
    print('子线程 结束')


if __name__ == '__main__':
    print('主线程执行代码')

    # 创建 Thread 类的实例对象
    thread = Thread(
        # target 参数 指定 新线程要执行的函数
        # 注意,这里指定的函数对象只能写一个名字,不能后面加括号,
        # 如果加括号就是直接在当前线程调用执行,而不是在新线程中执行了
        target=threadFunc,

        # 如果 新线程函数需要参数,在 args里面填入参数
        # 注意参数是元组, 如果只有一个参数,后面要有逗号,像这样 args=('参数1',)
        args=('参数1', '参数2')
    )

    # 执行start 方法,就会创建新线程,
    # 并且新线程会去执行入口函数里面的代码。
    # 这时候 这个进程 有两个线程了。
    thread.start()

    # 主线程的代码执行 子线程对象的join方法,
    # 就会等待子线程结束,才继续执行下面的代码
    thread.join()
    print('主线程结束')

共享数据的访问控制

from threading import Thread, Lock
from time import sleep

bank = {
    'count': 0
}

bankLock = Lock()


# 定义一个函数,作为新线程执行的入口函数
def deposit(theadidx, amount):
    # 操作共享数据前,申请获取锁
    bankLock.acquire()

    balance = bank['count']
    # 执行一些任务,耗费了0.1秒
    sleep(0.1)
    bank['count'] = balance + amount
    print(f'子线程 {theadidx} 结束')

    # 操作完共享数据后,申请释放锁
    bankLock.release()


if __name__ == '__main__':
    theadlist = []
    for idx in range(10):
        thread = Thread(target=deposit,
                        args=(idx, 1)
                        )
        thread.start()
        # 把线程对象都存储到 threadlist中
        theadlist.append(thread)
    for thread in theadlist:
        thread.join()

    print('主线程结束')
    print(f'最后我们的账号余额为 {bank["count"]}')

deamon线程

from threading import Thread
from time import sleep


def threadFunc():
    sleep(1)
    print('子线程 结束')


if __name__ == '__main__':
    # thread = Thread(target=threadFunc)
    # thread.start()
    # print('主线程结束')
    thread = Thread(target=threadFunc,
                    daemon=True  # 设置新线程为daemon线程
                    )
    thread.start()
    print('daemon主线程结束')

Python 官方解释器 的每个线程要获得执行权限,必须获取一个叫 GIL (全局解释器锁) 的东西。

这就导致了 Python 的多个线程 其实 并不能同时使用 多个CPU核心。

所以如果是计算密集型的任务,不能采用多线程的方式。

from threading import Thread

def f():
    while True:
        b = 53*53

if __name__ == '__main__':
    plist = []
    # 启动10个线程
    for i in range(10):
        p = Thread(target=f)
        p.start()
        plist.append(p)

    for p in plist:
        p.join()

多个CPU核心的运算能力,可以使用Python的多进程库。

from multiprocessing import Process

def f():
    while True:
        b = 53*53

if __name__ == '__main__':
    plist = []
    for i in range(2):
        p = Process(target=f)
        p.start()
        plist.append(p)

    for p in plist:
        p.join()
from multiprocessing import Process, Manager
from time import sleep


def f(taskno, return_dict):
    sleep(1)
    # 存放计算结果到共享对象中
    return_dict[taskno] = taskno


if __name__ == '__main__':
    manager = Manager()
    # 创建 类似字典的 跨进程 共享对象
    return_dict = manager.dict()
    plist = []
    for i in range(10):
        p = Process(target=f, args=(i, return_dict))
        p.start()
        plist.append(p)
    for p in plist:
        p.join()
    print('get result...')
    # 从共享对象中取出其他进程的计算结果
    for k, v in return_dict.items():
        print(k, v)

序列化和反序列化

Python中内置了json这个库,可以 方便的把内置的数据对象 序列化为json格式文本的字符串。

import json

historyTransactions = [

    {
        'time': '20300101070311',  # 交易时间
        'amount': '3088',  # 交易金额
        'productid': '45454455555',  # 货号
        'productname': 'iphone30'  # 货名
    },
    {
        'time': '20300101050311',  # 交易时间
        'amount': '18',  # 交易金额
        'productid': '453455772955',  # 货号
        'productname': '饼干'  # 货名
    }

]

if __name__ == '__main__':
    # dumps 方法将数据对象序列化为 json格式的字符串
    jsonstr = json.dumps(historyTransactions)
    print(jsonstr)

import json

historyTransactions = [

    {
        'time': '20300101070311',  # 交易时间
        'amount': '3088',  # 交易金额
        'productid': '45454455555',  # 货号
        'productname': 'iphone30'  # 货名
    },
    {
        'time': '20300101050311',  # 交易时间
        'amount': '18',  # 交易金额
        'productid': '453455772955',  # 货号
        'productname': '饼干'  # 货名
    }

]

if __name__ == '__main__':
    # dumps 方法将数据对象序列化为 json格式的字符串
    jsonstr = json.dumps(historyTransactions)
    print(jsonstr)
    print('================')
    print(json.dumps(historyTransactions, ensure_ascii=False, indent=4))
    print('================')
    jsonstr = '[{"time": "20300101070311", "amount": "3088", "productid": "45454455555", "productname": "iphone7"}, {"time": "20300101070311", "amount": "18", "productid": "453455772955", "productname": "\u5999\u5999\u5999"}]'
    translist = json.loads(jsonstr)
    print(translist)
    print(type(translist))

Python中装饰器通常用来装饰函数、或者类的方法。

通常被装饰后的函数, 会在原有的函数基础上,增加一点功能。

装饰器经常被用在库和框架中, 给别的开发者使用。

这些库的开发者预料到 使用者 开发的函数可能需要 一些增强的功能。

但是 这些库的开发者 没法去改使用者的代码, 就可以把这些增强的部分做在 装饰器函数中。

这样使用者,只需要在他们的函数前面上@xxx 就使用了这些增强的功能了。

基础示例:

import time


# 定义一个装饰器函数
def sayLocal(func):
    def wrapper():
        curTime = func()
        return f'当地时间: {curTime}'

    return wrapper


@sayLocal
def getXXXTime():
    print()
    return time.strftime('%Y_%m_%d %H:%M:%S', time.localtime())


if __name__ == '__main__':
    # 装饰 getXXXTime
    # getXXXTime = sayLocal(getXXXTime)
    print(getXXXTime())

进阶示例-被装饰的函数有参数:

import time


def sayLocal(func):
    def wrapper(*args, **kargs):
        curTime = func(*args, **kargs)
        return f'当地时间: {curTime}'

    return wrapper


@sayLocal
def getXXXTimeFormat1(name):
    curTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
    return f'{curTime} ,数据采集者:{name} '


@sayLocal
def getXXXTimeFormat2(name, place):
    curTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
    return f'{curTime} ,数据采集者:{name} , 采集地:{place}'


if __name__ == '__main__':
    print(getXXXTimeFormat1('张三'))
    print(getXXXTimeFormat2('张三', place='北京'))

进阶示例-装饰器函数自身有参数:

# 添加输出日志的功能
def logging(flag):
    def decorator(fn):
        def inner(num1, num2):
            if flag == "+":
                print("--正在努力加法计算--")
            elif flag == "-":
                print("--正在努力减法计算--")
            result = fn(num1, num2)
            return result

        return inner

    # 返回装饰器
    return decorator


# 使用装饰器装饰函数
@logging("+")
def add(a, b):
    result = a + b
    return result


@logging("-")
def sub(a, b):
    result = a - b
    return result


if __name__ == '__main__':
    result = add(1, 2)
    print(result)

    result = sub(1, 2)
    print(result)

算法 计算结果长度
MD5 16字节
SHA1 20字节
SHA224 28字节
SHA256 32字节
SHA384 48字节
SHA512 64字节

典型应用场景:

校验拷贝下载文件

校验信息有效性

使用 Python 内置库 hashlib 创建hash值。

import hashlib

if __name__ == '__main__':
    # 使用 md5 算法
    # m = hashlib.md5()
    # 如果你想使用别的哈希算法,比如, sha256 算法,只需要修改为对应的函数 sha256()即可
    m = hashlib.sha256()

    # 要计算的源数据必须是字节串格式
    # 字符串对象需要encode转化为字节串对象
    m.update("ML李嘉图|mllijaitu".encode())

    # 产生哈希值对应的bytes对象
    resultBytes = m.digest()
    # 产生哈希值的十六进制表示
    resultHex = m.hexdigest()
    print(resultHex)

SSH远程操作

Python第三方库 Paramiko 就是作为ssh客户端远程控制Linux主机 的。

exec_command 是每次执行都是 新打开一个channel的东西执行,

每个channel都是命令执行的环境,每执行命令都是一个新的执行环境,不在上次执行的环境里面,

相当于 每次都在各自的执行环境里面,和前面的执行环境没有关系。

多个命令一起执行,用分号隔开,像这样:

stdin, stdout, stderr = ssh.exec_command("cd testdir;pwd")

操作单台主机:

# 单台主机操作
import paramiko

#############################配置信息#####################################
# 登陆参数设置
hostname = ""
host_port = 22
username = "root"
password = ""


########################################################################

def ssh_client_con():
    """创建ssh连接,并执行shell指令"""
    # 1 创建ssh_client实例
    ssh_client = paramiko.SSHClient()
    # 自动处理第一次连接的yes或者no的问题
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
    # 2 连接服务器
    ssh_client.connect(
        port=host_port,
        hostname=hostname,
        username=username,
        password=password
    )
    # 3 执行shell命令
    # 构造shell指令
    shell_command = "ls"
    stdin, stdout, stderr = ssh_client.exec_command(shell_command)
    # 输出返回信息
    stdout_info = stdout.read().decode('utf8')
    print(stdout_info)
    # 输出返回的错误信息
    stderr_info = stderr.read().decode('utf8')
    print(stderr_info)


def sftp_client_con():
    # 1 创建transport通道
    tran = paramiko.Transport((hostname, host_port))
    tran.connect(username=username, password=password)
    # 2 创建sftp实例
    sftp = paramiko.SFTPClient.from_transport(tran)
    # 3 执行上传功能
    local_path = ""  # 本地路径
    remote_path = ""  # 远程路径
    put_info = sftp.put(local_path, remote_path, confirm=True)
    print(put_info)
    print(f"上传{local_path}完成")
    # 4 执行下载功能
    save_path = ""  # 本地保存文件路径
    sftp.get(remotepath=remote_path, localpath=save_path)
    print(f'下载{save_path}完成')
    # 5 关闭通道
    tran.close()


if __name__ == '__main__':
    # 调用函数执行功能
    ssh_client_con()
    # sftp_client_con()

Python面向对象编程

类变量与实例变量

# 创建一个学生类
class Student:
    # number属于类变量,不属于某个具体的学生实例
    number = 0
    
    # 定义学生属性,初始化方法
    # name和score属于实例变量
    def __init__(self, name, score):
        self.name = name
        self.score = score
        Student.number = Student.number + 1
    
    # 定义打印学生信息的方法
    def show(self):
        print("Name: {}. Score: {}".format(self.name, self.score))

# 实例化,创建对象
student1 = Student("John", 100)
student2 = Student("Lucy", 99)

print(Student.number)  # 打印2
print(student1.__class__.number) # 打印2

有些变量只属于类,有些方法也只属于类,不属于具体的对象。

你有没有注意到属于对象的方法里面都有一个self参数, 比如__init__(self), show(self)?

self是指对象本身。

属于类的方法不使用self参数, 而使用参数cls,代表类本身。

另外习惯上对类方法我们会加上@classmethod的修饰符做说明。

class Student:
    # number属于类变量,不属于某个具体的学生实例
    number = 0

    # 定义学生属性,初始化方法
    # name和score属于实例变量
    def __init__(self, name, score):
        self.name = name
        self.score = score
        Student.number = Student.number + 1

    # 定义打印学生信息的方法
    def show(self):
        print("Name: {}. Score: {}".format(self.name, self.score))

    # 定义类方法,打印学生的数量
    @classmethod
    def total(cls):
        print("Total: {0}".format(cls.number))


if __name__ == '__main__':
    # 实例化,创建对象
    student1 = Student("John", 100)
    student2 = Student("Lucy", 99)

    Student.total()  # 打印 Total: 2

类的私有属性和私有方法

类里面的私有属性和私有方法以双下划线__开头。私有属性或方法不能在类的外部被使用或直接访问。

# 创建一个学生类
class Student:

    # 定义学生属性,初始化方法
    # name和score属于实例变量, 其中__score属于私有变量
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    
    # 定义打印学生信息的方法
    def show(self):
        print("Name: {}. Score: {}".format(self.name, self.__score))

# 实例化,创建对象
student1 = Student("John", 100)

student1.show()  # 打印 Name: John, Score: 100
student1.__score  # 打印出错,该属性不能从外部访问。

@property

# 创建一个学生类
class Student:

    # 定义学生属性,初始化方法
    # name和score属于实例变量, 其中score属于私有变量
    def __init__(self, name, score):
        self.name = name
        self.__score = score

    # 利用property装饰器把函数伪装成属性
    @property
    def score(self):
        print("Name: {}. Score: {}".format(self.name, self.__score))


if __name__ == '__main__':
    # 实例化,创建对象

    student1 = Student("John", 100)

    student1.score  # 打印 Name: John. Score: 100

# 创建父类学校成员SchoolMember
class SchoolMember:

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

    def tell(self):
        # 打印个人信息
        print('Name:"{}" Age:"{}"'.format(self.name, self.age), end=" ")


# 创建子类老师 Teacher
class Teacher(SchoolMember):

    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)  # 利用父类进行初始化
        self.salary = salary

    # 方法重写
    def tell(self):
        SchoolMember.tell(self)
        print('Salary: {}'.format(self.salary))


# 创建子类学生Student
class Student(SchoolMember):

    def __init__(self, name, age, score):
        SchoolMember.__init__(self, name, age)
        self.score = score

    def tell(self):
        SchoolMember.tell(self)
        print('score: {}'.format(self.score))


if __name__ == '__main__':
    teacher1 = Teacher("John", 44, "$60000")
    student1 = Student("Mary", 12, 99)
    teacher1.tell()
    student1.tell()

静态变量和静态方法

# 创建一个学生类
class Student:
    # number属于类变量,定义在方法外,不属于具体实例
    number = 0

    # 定义学生属性,初始化方法
    # name和score属于实例变量,定义在方法里
    def __init__(self, name, score):
        self.name = name
        self.score = score
        Student.number = self.number + 1

    # 定义打印学生信息的方法
    def show(self):
        print("Name: {}. Score: {}".format(self.name, self.score))

    # 静态方法无法使用cls和self参数访问类或实例的变量
    @staticmethod
    def func1():
        print("this is static function!")

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK