python上下文操作linux

发布于 2022年 05月 19日 17:43

上下文管理

什么是上下文管理,在编程过程中,通常用来表示代码执行过程中的前后操作,例如open函数,在操作文件之前,需要打开文件,然后再对文件进行读写操作,操作结束后,需要关闭文件。

上下文管理的作用场景:文件操作、网络的连接与断开,数据库连接操作及断开等。

示例

我们在使用open函数对文件操作时,是这样实现的

#获取文件对象
fp = open('info','a+')

#对文件的操作

#操作接收后,关闭文件流
fp.close()

上面的方法,虽然可以实现文件的读写操作,但是如果文件的操作过程中,发生了异常,会导致fp.close()不会执行。

修改

#获取文件对象
try:
	fp = open('info','a+')

	#对文件的操作
except:
	print('这里发生了异常')
#操作接收后,关闭文件流
finally:
	fp.close()

通过这种方式,添加异常处理,使用finally老保证不管是否发生异常,都执行关闭文件操作,以确保文件的正常关闭。

上述方法虽然能解决这个问题,但是实现过程中,需要做出对应的异常处理,比较麻烦。

所以我们可以使用with语法来实现,with实际上就是上下文的管理。

with open('info','a+') as fp:
	#文件操作

with时如何实现上下文管理的,如何编写一个自己的上下文管理呢

在python中,如果一个类,实现了__enter__()方法和__exit__()方法,那么这个类就可以是一个上下文管理器。

__enter__() :用来表示上文管理,需要返回一个操作对象

__exit__() :执行结束后的方法,不管过程中是否发生异常,这里都会执行,也是with中执行结束后的操作

实例

class File:
    def __init__(self):
        print('执行构造方法')

    def __enter__(self):
        print('进入方法')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('执行结束方法')


with File() as f:
    print('执行操作')

执行结果

执行构造方法
进入方法
执行操作
执行结束方法

执行过程是先创建一个File类的对象,并命名为f,实例化时,调用了init方法,所以输出“执行构造方法”,然后再调用enter方法,输出“进入方法”。在执行with下的子句,即用户的操作方法。

通过上下文操作mysql数据库

# 封装的类是可以提供方法的,但是需要考虑异常处理问题
# 还要考虑如何确保链接的关闭
class Mysql(object):
    def __init__(self,**kwargs):
        self.conn = pymysql.connect(**kwargs)
        self.cursor = self.conn.cursor()

    def execsql(self,sql):
        self.cursor.execute(sql)
        return  self.cursor.fetchall()

    def fetch(self,n=1):
        return self.cursor.fetchmany(n)

    def close(self):
        self.cursor.close()
        self.conn.close()



class Mysql_with(object):
    # 通过构造方法实现数据库连接的创建
    def __init__(self,**kwargs):
        self.conn = pymysql.connect(**kwargs)
        # 获取游标对象
        self.cursor = self.conn.cursor()

    def __enter__(self):
        # 返回一个游标对象
        return self.cursor

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        self.conn.close()


with Mysql_with(host='192.168.2.99',port=3306,user='root',passwd='',db='mysql') as mysql:
    # mysql是什么,mysql接收的是__enter__方法返回的结果。所以mysql是cursor
    mysql.execute('select user,host from user;')
    print(mysql.fetchall())

上下文操作linux

class Linux:
    def __init__(self,host='',user='',password='',port=22):
        self.host = host
        self.user = user
        self.password = password
        self.port = port
        # 初始化ftp
        self.ftp = ''
        # 初始化ssh
        self.ssh = ''

class SSH_Linux(Linux):
    def __enter__(self):
        # self.__ssh()
        return self

    def command(self,comd):
        # 调用ssh连接,创建连接
        try:
            self.__ssh()
        except AuthenticationException:
            return '登录错误'
        except TimeoutError:
            return '连接失败,请检查服务器地址是否正确'
        stdin,stdout,stderr = self.ssh.exec_command(comd)
        # 处理命令的执行结果,并返回
        return str(stdout.read(),encoding='utf-8')


    def __ssh(self):
        #创建ssh连接
        self.ssh = paramiko.SSHClient()

        try:
            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh.connect(hostname=self.host,username=self.user,password=self.password,port=self.port)

        except AuthenticationException:
            raise AuthenticationException

        except TimeoutError:
            raise TimeoutError

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.ssh.close()

class FTP_Linux(Linux):

    def __enter__(self):
        return self

    def __ftp(self):
        # 创建ftp连接
        self.transport = paramiko.Transport((self.host,self.port))
        try:
            self.transport.connect(username=self.user,password=self.password)
        except AuthenticationException:
            raise AuthenticationException
        self.ftp = paramiko.SFTPClient.from_transport(self.transport)

    def get(self,source,dept):

        try:
            self.__ftp()
        except AuthenticationException:
            return '登录错误'

        # 处理没有找到要下载的文件问题
        try:
            # 判断dest是否是一个文件
            if os.path.isfile(dept):
                self.ftp.get(source,dept)

            elif os.path.isdir(dept):
                # 读取到要下载的文件的文件名
                file = os.path.basename(source)
                # 将文件名和下载路径拼接
                file_name = os.path.join(dept,file)
                self.get(source,file_name)

            elif not os.path.exists(dept):
                self.ftp.get(source,dept)
        except    FileNotFoundError:
            return '要下载的目标文件不存在'

    def put(self,source,dept):
        try:
            self.__ftp()
        except AuthenticationException:
            return '登录错误'
        # 检查要上传的文件是否存在
        if os.path.isfile(source):
            self.ftp.put(source,dept)
        else:
            return '上传必须是已存在的文件'

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.ftp.close()
        self.transport.close()



# ssh = Linux('192.168.2.16',user='root',password='123456')

# with SSH_Linux('192.168.2.16',user='root',password='123456') as ssh:
#     print(ssh.command('ls'))

with FTP_Linux('192.168.2.16',user='root',password='123456') as ftp:
    ftp.get('/home/test','.')

如果对于python访问linux系统不是很熟悉的话,可以参考下面的demo

linux ssh连接

# 需要先安装paramiko
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect('192.168.2.16',username='root',password='123456')

stoin,out,err = ssh.exec_command('ls')
# stoin标准输入,执行时,不关心。
# out:标准输出流。用来接收命令执行的结果的
# err:标准错误,用来接收命令执行失败的错误信息

# 标准输出流返回的是一个二进制对象,所以需要转成字符串对象,需要用utf8编码
print(str(out.read(),encoding='utf-8'))

ssh.close()

linux文件上传下载

#coding=utf-8
__author__ = 'jia'
import paramiko

#Transportj接收一个socker对象,也就是ip地址和端口,因为只有一个参数,所以将两个参数
# 以元组的形式传入
transport = paramiko.Transport(('192.168.2.16',22))

# 创建连接
transport.connect(username='root',password='123456')

# 创建ftp连接(通过socker创建ftp连接)
ftp = paramiko.SFTPClient.from_transport(transport)

# 上传文件
ftp.put('test.html','/home/test.html')

# 下载文件
ftp.get('/etc/passwd','D:\\password')

# 关闭ftp连接
ftp.close()
# 关闭socker连接
transport.close()

推荐文章