python学习生涯 day17-23

0 两个重要的函数

isinstance(obj,cls):检查obj是否是类 cls 的对象

class Foo(object):
    pass


obj = Foo()
print(isinstance(obj, Foo))

在这里插入图片描述

issubclass(sub, super):检查sub是否是类super的子类

class Foo(object):
    pass

class Bar(Foo):
    pass


print(issubclass(Bar, Foo))

在这里插入图片描述

1 反射

反射就是以字符串的形式来操作变量
反射一共提供了4个方法: hasattr();getattr();setattr();delattr()
eval函数就是实现list、dict、tuple与str之间的转化
str函数把list,dict,tuple转为为字符串
这两个函数与反射无关
Eval存在安全问题,而反射不存在安全问题

# 反射对象的属性
class A:
    def func(self):
        print('in func')


a = A()
a.name = 'lux'
a.age= 63
ret = getattr(a, 'name')
print(ret)

b = input('>>>>')
print(getattr(a, b))
print(a.__dict__['name'])

在这里插入图片描述
注意:上述的三种方法都能实现功能, input输入的内容就是字符串类型,因为是反射对象中的属性,所以也可以通过字典来实现

# 反射对象的方法
class A:
    def func(self):
        print('in func')


a = A()
a.name = 'lux'
a.age = 63
ret = getattr(a, 'func')
ret()

在这里插入图片描述

# 反射类的属性(这里的属性包括一般属性和静态属性)
class A:
    price = 20

    def func(self):
        print('in func')


print(getattr(A, 'price'))

在这里插入图片描述

# 反射类的方法 (这里的方法包括普通方法,类方法和静态方法)
class A:
    price = 20

    @classmethod
    def func(cls):
        print('in func')


ret = getattr(A, 'func')
ret()

在这里插入图片描述

class A:
    price = 20

    @staticmethod
    def func():
        print('in func')


ret = getattr(A, 'func')
ret()

在这里插入图片描述

# mymodule 是我自定义的一个模块


import mymodule
print(getattr(mymodule, 'my_packet'))

在这里插入图片描述

# 反射模块的方法
import mymodule
ret = getattr(mymodule, 'get_money')
ret()

在这里插入图片描述

# 反射自己模块的属性和方法

def qqxing():
    print('wahaha')


year = 2020
import sys

print(getattr(sys.modules[__name__], 'year'))
ret = getattr(sys.modules[__name__], 'qqxing')
ret()

在这里插入图片描述
hasattr()通常与getattr()配合使用:

import mymodule

if hasattr(mymodule, 'my_packet'):
    print(getattr(mymodule, 'my_packet'))
# setattr(): 修改一个变量


class A:
    pass


a = A()
setattr(a, 'name', 'alex')
setattr(A, 'name', 'lux')
print(a.name)
print(A.name)

在这里插入图片描述

# delattr():删除一个属性

class A:
    name = 'zoe'


a = A()
a.name = 'jax'
delattr(a, 'name')
print(a.name)
delattr(A, 'name')
print(A.name)

在这里插入图片描述
注意:当对象的方法和属性找不到时,就会在类里面找

2 一些魔法方法(双下划线方法):

#  __str__
class Teacher:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def __str__(self):
        return 'Tecaher is %s' % self.name

    def func(self):
        return 'wahaha'


dasi = Teacher('大司马', 3000)
print(dasi)

在这里插入图片描述
总结:当直接打印一个对象的时候,会自动执行__str__方法
当执行%s的时候,会自动执行__str__方法
当执行str()的时候,也会自动执行__str__方法

# __repr__
class Teacher:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def __str__(self):
        return 'Tecaher is %s' % self.name

    def __repr__(self):
        return '<<<Tecaher is %s' % self.name

    def func(self):
        return 'wahaha'


dasi = Teacher('大司马', 3000)
print(repr(dasi))
print('%s' % dasi)
print('%r' % dasi)

在这里插入图片描述
总结:当执行%r的时候,会自动执行__str__方法
当执行repr()的时候,也会自动执行__str__方法

小结:

__repr__是__str__的备胎,当需要__str__但是找不到__str__时候,就会找本类中的__repr__方法,(但是__str__不是__repr__的备胎),再找不到就在父类中找,直到object类,__repe__只会找__repe__方法,找不到就去父类找

class Teacher:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def __repr__(self):
        return '<<<Tecaher is %s' % self.name

    def func(self):
        return 'wahaha'


dasi = Teacher('大司马', 3000)
print(repr(dasi))
print('%s' % dasi)
print('%r' % dasi)

在这里插入图片描述

# __len__
class Teacher:
    def __init__(self, name):
        self.name = name
        self.student = []

    def __len__(self):
        return 10

     def __str__(self):
        return 'nmsl'


py_s9 = Teacher('九七')
py_s9.student.append('jinx')
print(len(py_s9))

在这里插入图片描述
注意:当执行len的时候就会执行__len__方法,单纯的直接打印才会执行__str__方法,print(len(py_s9))相当于先执行len(py_s9),将__len__返回的结果打印出来,这个结果不是对象,所以和__str__没有关系

#  __del__:析构方法,当对象在内存中被释放时,自动触发执行
class A:
    def __del__(self):
        print('执行了del方法')


a = A()
del a
print(a)

在这里插入图片描述
总结:当执行了del的时候,先执行该__del__方法,再删除对象
__del__的作用;在删除一个对象之前,做一些收尾工作

# __call__
class A:
    def __call__(self):
        print('执行了__call__方法')


a = A()
a()

在这里插入图片描述
注意:当一个对象加()后,执行__call__方法,在看源码的时候,我们可能会看到A()()这种

# item系列:与字典有关的方法
# Item系列一共有三种方法:__getitem__   __setitem__  __delitem__

class Foo:
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        print('del obj[key]时,我执行')
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print('del obj.key时,我执行')
        self.__dict__.pop(item)


f1 = Foo('sb')
f1['age'] = 18
f1['age1'] = 19
print(f1.__dict__)
del f1.age1 # 和__delattr__相关联
del f1['age']  # 和__delitem__想关联
f1['name'] = 'alex'
print(f1.__dict__)

在这里插入图片描述

# __new__
# 当对象在实例化的时候,先自动执行__new__,再执行__init__	
__new__一般用于设计模式,下面介绍一种常见的单例模式

class A:
    __instance = False

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

    def __new__(cls, *args, **kwargs):
        if cls.__instance:
            return cls.__instance
        cls.__instance = object.__new__(A)
        return cls.__instance


egon = A('二哥', 99)
alex = A('哪吒', 520)
egon.cloth = '羽绒服'
print(egon.name)
print(alex.name)
print(alex.__dict__)

在这里插入图片描述
注意:对于单例模式而言,新对象的属性会覆盖旧对象的属性,如果没有这个属性,则会增加上

class Teacher:
    def __init__(self):
        print('__init__执行了')

    def __new__(cls, *args, **kwargs):
        print('__new__执行了')
        return object.__new__(Teacher)

    def __call__(self):
        print('__call__执行了')


dasi = Teacher()
dasi()

在这里插入图片描述

#  __eq__
当出现==时,会自动执行__eq__
class A:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        if self.name == other.name:
            return True
        else:
            return False


a1 = A('lux')
a2 = A('lux')
print(a1 == a2)

在这里插入图片描述
注意:’==‘ 会自动调用__eq__函数,如果没有__eq__函数,就会比较内存地址,比如上述的代码,没有没有__eq__ 结果就是False(刚又验证了一次)

#  __hash__
class A:
    def __init__(self, name, sex):
        self.name = name
        self.sex = sex

    def __hash__(self):
        return hash(self.name + self.sex)


a1 = A('lux', '男')
a2 = A('lux', '男')
print(hash(a1))
print(hash(a2))

在这里插入图片描述

注意:没有__hash__的话,如果是可哈希的类型,会根据内存地址来哈希,如果有__hash__的话,就会根据hash函数来进行哈希

关于__del__; delattr; delitem__的区别:

0)del :用来删除一个对象
1)delattr:用来删除一个对象的属性
2)delitem: 与字典有关,用来删除一个字典的键

关于 init__和__new

class A:
    pass


class B(A):
    def __new__(cls):
        print("__new__方法被执行")
        return super().__new__(cls)

    def __init__(self):
        print("__init__方法被执行")


b = B()

在这里插入图片描述
小结:我们比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作,结合到代码,也就是__new__的返回值正是__init__中self。
经过测试,如果返回了一个不相关的变量,__init__也不会被执行。

3 内置函数的一些遗留问题

from random import choice
from collections import namedtuple
import json
from random import shuffle

Card = namedtuple('Card', ['rank', 'suit'])


class FranchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = ['红心', '方板', '梅花', '黑桃']

    def __init__(self):
        self._cards = [Card(rank, suit) for rank in FranchDeck.ranks
                                        for suit in FranchDeck.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

    def __str__(self):
        return json.dumps(self._cards, ensure_ascii=False)


deck = FranchDeck()
print(deck[0])
print(choice(deck))
print(len(deck))
print(deck)

在这里插入图片描述
小结:一定要学会使用namedtuple

4 hashlib模块

Hashlib模块是一个提供摘要算法的模块,比如md5,sha1等
摘要算法:
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

import hashlib
md = hashlib.md5()
md.update(b'alex')
print(md.hexdigest())

在这里插入图片描述

import hashlib
md = hashlib.md5()
md.update(b'how to use md5 in python hashlib?')
print(md.hexdigest())

在这里插入图片描述
小结: 对于同一个内容,使用同一个摘要算法,得到的内容是相同的
对于同一个内容,使用不同的摘要算法,得到的内容是不同的
算法的复杂度越高,造成的时间成本也越高

一个有关登录的代码

import hashlib
usr = input('请输入用户名:')
pwd = input('请输入密码:')
with open('userinfo.txt') as f:
    for line in f:
        (usrs, pwds, role) = line.split('|')
        md5 = hashlib.md5()
        md5.update(bytes(pwd, encoding='utf-8'))
        ret = md5.hexdigest()
        if usr == usrs and ret == pwds:
            print('登陆成功')
        else:
            print('登陆失败')

userinfo.txt文件的内容在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
为了使密码不容易被破解,可以使用‘加盐’来增加复杂度

import hashlib
md = hashlib.md5()
md = hashlib.md5(bytes('1', encoding='utf-8'))
md.update(b'blessing')
print(md.hexdigest())

在这里插入图片描述

小结:太简单的盐还是会被识别出来,而比较复杂的盐被识别出来的几率就小了很多
登陆的时候可以加盐,文件的一致性校验不需要加盐
对于一个文件而言,通常不一次性把所有的内容都转化为md5值,而是分多次,这种方式与前者得到的结果完全相同

5 一个改输出效果的小技巧

Python的print可以附带一些小花样,比如说前景色和背景色。在这里插入图片描述

print('\033[0;36m爆竹声中一岁除,')
print('春风送暖入屠苏。')
print('千门万户曈曈日,')
print('总把新桃换旧符。\033[0m')

在这里插入图片描述

6 configparser模块

# 利用py程序自动生成一个ini文件(配置文件)

import configparser

config = configparser.ConfigParser()

config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9',
                     'ForwardX11':'yes'
                     }

config['bitbucket.org'] = {'User':'hg'}

config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}

with open('example.ini', 'w') as configfile:

   config.write(configfile)

run后会得到一个ini文件(配置文件)
在这里插入图片描述
查找ini文件的内容

import configparser

config = configparser.ConfigParser()

#---------------------------查找文件内容,基于字典的形式

print(config.sections())        #  []

config.read('example.ini')

print(config.sections())        #   ['bitbucket.org', 'topsecret.server.com']

print('bytebong.com' in config) # False
print('bitbucket.org' in config) # True


print(config['bitbucket.org']["user"])  # hg

print(config['DEFAULT']['Compression']) #yes

print(config['topsecret.server.com']['ForwardX11'])  #no


print(config['bitbucket.org'])          #<Section: bitbucket.org>

for key in config['bitbucket.org']:     # 注意,有default会默认default的键
    print(key)

print(config.options('bitbucket.org'))  # 同for循环,找到'bitbucket.org'下所有键

print(config.items('bitbucket.org'))    #找到'bitbucket.org'下所有键值对

print(config.get('bitbucket.org','compression')) # yes       get方法Section下的key对应的value

在这里插入图片描述
更改ini文件的内容

import configparser

config = configparser.ConfigParser()

config.read('example.ini')

config.add_section('yuanyuan')



config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com', "forwardx11")


config.set('topsecret.server.com', 'k1', '11111')
config.set('yuanyuan', 'k2', '22222')
config.write(open('example.ini', "w"))

在这里插入图片描述

7 logging 模块

Logging模块用来记录一些重要的操作和错误(日志)

import logging  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message') 

默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。

在这里插入图片描述

import logging
logging.basicConfig(level=logging.ERROR,
                    format='%(asctime)s %(filename)s',
                    filename='test.log',
                    filemode='a')

logging.error('你好')

在这里插入图片描述
一张提供参考输出格式的表
在这里插入图片描述

日志是很有必要的,不会写日志就是睿智

basicConfig的两大缺点:
中文的乱码问题
不能同时往文件和屏幕上打印
为了解决问题,我们必须配置log对象

import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log', encoding='utf-8')

# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)

fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

在这里插入图片描述
在这里插入图片描述

使用上述对log配置的方法,可以解决这两大缺点

小结:
5种级别的日志记录模式
2种配置模式:basicConfig 和 log配置

8 网络知识

0) 架构
C/s架构和b/s架构

1)一些网络知识
每台电脑都有唯一的一个mac地址(物理地址)通常由12位十六进制组成,其中每两位隔开
在这里插入图片描述
其中前三组是厂商号,后三组是流水号

由于mac地址太过抽象且不好记忆,所以我们引入了ip地址的方式,每台电脑对应着唯一一个ip地址
Ip地址由4个八位的二进制组成(ipv4),或者最新推出的(ipv6)
在这里插入图片描述
Arp协议:可以通过ip地址找到对应的mac地址。

网关:处于不同局域网的电脑想要通信,必须通过网关

怎么判断两台电脑处于同一个局域网呢?

方法:ip地址与子网掩码按位与
在这里插入图片描述
如果两台电脑得到的结果的前三组一样,就说明两台电脑处于同一个局域网

Ip协议主要有两个功能:
为每一台电脑分配一个ip地址, 确定哪些地址在同一个网络

保留字段 192.168.—.---
本地的回环地址 127.0.0.1

Ip:找到唯一的一台电脑
端口:找到唯一的一个程序 端口的范围是0——65535 一般情况下使用8000后的 端口,之前的端口都是系统端口
Ip➕端口:找到唯一的一台电脑上的唯一的一个程序

9 Tcp协议和udp协议

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议

Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。

tcp的三次握手和四次挥手
在这里插入图片描述
在这里插入图片描述
详情查看:添加链接描述
Tcp和udp的对比:
Tcp安全可靠 需要建立连接才能通信,耗时长
Udp不需要建立连接就能通信,所以它不是安全可靠的,效率高

互联网协议按照功能不同分为osi七层和osi五层,以下是对五层的一些理解

在这里插入图片描述
换句话说,通信就是包快递和拆快递的过程
在这里插入图片描述
在这里插入图片描述
一个基于tcp的socket模块:可以实现自身的自收自发

# server.py

import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8090))

sk.listen()

conn, add = sk.accept()
# print(add)
while True:
    ret = conn.recv(1024).decode('utf-8')
    print(ret)
    if ret == 'bye':
        break
    info = input()
    conn.send(bytes(info, encoding='utf-8'))

conn.close()
sk.close()
#  client.py

import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))

while True:
    info = input()
    if info == 'bye':
        sk.send(bytes(info, encoding='utf-8'))
        break
    sk.send(bytes(info, encoding='utf-8'))
    ret = sk.recv(1024).decode('utf-8')
    print(ret)

sk.close()

一个基于udp的socket模块:可以实现自身的自收自发

# server.py

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 8080))

while True:
    msg, addr = sk.recvfrom(1024)
    ret = msg.decode('utf-8')
    print(ret)
    if ret == 'bye':
        break
    info = input('>>>')
    sk.sendto(bytes(info, encoding='utf-8'), addr)

sk.close()
# client.py

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ('127.0.0.1', 8080)

while True:
    info = input('<<<')
    sk.sendto(bytes(info, encoding='utf-8'), ip_port)
    if info == 'bye':
        break
    msg, addr = sk.recvfrom(1024)
    print(msg.decode('utf-8'))




sk.close()

10 黏包

Tcp会出现黏包现象,但不会出现丢包现象,如果没接收完的包会在下一次接收的时候接收到
而udp不会出现黏包现象,但是会出现丢包现象,没有接收完的包会直接丢弃掉
这里插播一个有关编码和解码的知识点:

解码和编码
举个例子,这里我们不妨将人类可以很容易理解的字符作为“明文”,将人类的明文加密成不易懂但是更易于存储和传输的消息字节作为“密文”。那么编码和解码的关系如下: 明文就是人类可以直接一眼就看得懂的字符,密文就是明文被加密后一般人无法立马看懂的字节。

UTF-8,是对Unicode编码的压缩和优化,它不再要求最少使用2个字节,而是将所有的字符和符号进行分类:ASCII码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存。
当计算机在工作时,内存中的数据一直是以Unicode的编码方式表示的,当数据要保存到磁盘或者网络传输时,才会使用utf-8编码进行操作。

Tcp协议的拆包机制:
当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。
MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。
解决黏包问题的方法:
0)在传输大文件的时候,提前发生文件的长度
1) struct模块:是一个可以将任意大小的数字转换成一个固定长度编码的模块

# server端
import socket
import struct
sk = socket.socket()
sk.bind(('127.0.0.1', 8090))
sk.listen()
conn, addr = sk.accept()
while True:
    cmd = input(">>>")
    if cmd == 'q':
        conn.send(b'q')
        break
    conn.send(cmd.encode('gbk'))
    num = conn.recv(4)
    num = struct.unpack('i', num)[0]
    # print(num)
    res = conn.recv(int(num)).decode('gbk')
    print(res)
conn.close()
sk.close()
# client端
import socket
import subprocess
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
while True:
    cmd = sk.recv(1024).decode('gbk')
    if cmd == 'q':
        break
    res = subprocess.Popen(cmd, shell=True,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE)
    std_out = res.stdout.read()
    std_err = res.stderr.read()
    len_sum = len(std_out) + len(std_err)
    num_by = struct.pack('i', len_sum)
    sk.send(num_by)
    sk.send(std_out)
    sk.send(std_err)
sk.close()

struct模块
常用的两个方法: pack和unpack
模式 “i”
pack之后的长度:4个字节
unpack之后拿到的数据是一个元组,元组的第一个内容才是pack的值
subprocess模块
subprocess这个模块可以用来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值。

11ftp:文件传输协议(和自定义报头)

# server端

import socket
import struct
import json
sk = socket.socket()
sk.bind(('127.0.0.1', 8090))
sk.listen()
buffer = 4096
conn, addr = sk.accept()
# 接收
head_len = conn.recv(4)
head_len = struct.unpack('i', head_len)[0]
json_head = conn.recv(head_len).decode('utf-8')
# 字符串转字典
head = json.loads(json_head)
filesize = head['filesize']
with open(head['filename'], 'wb') as f:
    while filesize:
        if filesize >= buffer:
            content = conn.recv(buffer)
            f.write(content)
            filesize -= buffer
        else:
            content = conn.recv(filesize)
            f.write(content)
            break
conn.close()
sk.close()
# client端
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
buffer = 4096

head = {'filepath': '/Users/gaoye/Desktop',
        'filename': 'test1.mov',
        'filesize': None}
# 拼接,将路径和名字拼接在一起
file_path = os.path.join(head['filepath'], head['filename'])
# 得到文件字节大小
filesize = os.path.getsize(file_path)
head['filesize'] = filesize
# 字典转字符串
json_head = json.dumps(head)
# 字符串转字节
bytes_head = json_head.encode('utf-8')
# 计算head的长度
head_len = len(bytes_head)
pack_len = struct.pack('i', head_len)
# 先发送报头的长度
sk.send(pack_len)
# 再发送bytes类型的报头
sk.send(bytes_head)
with open(file_path, 'rb') as f:
    while filesize:
        if filesize >= buffer:
            content = f.read(buffer)
            sk.send(content)
            filesize -= buffer
        else:
            content = f.read(filesize)
            sk.send(content)
            break
sk.close()

12 hamc模块

hamc模块
hashlib : 不可逆加密
hmac : 不可逆键值对方式加密
base64: 可逆加密

一个验证客户端的合法性的例子:

# server端
import socket
import hmac
import os
import hashlib
secret_key = b'egg'
sk = socket.socket()
sk.bind(('127.0.0.1', 8090))
sk.listen()


def check_conn(conn):
    # os.urandom得到的本身就是字节,所以不用encode
    msg = os.urandom(32)
    conn.send(msg)
    h = hmac.new(secret_key, msg, digestmod=hashlib.sha1)
    digest = h.digest()
    client_digest = conn.recv(1024)
    return hmac.compare_digest(digest, client_digest)


conn, addr = sk.accept()
res = check_conn(conn)
if res:
    print('合法的客户端')
else:
    print('不合法的客户端')
conn.close()
sk.close()
# client端
import socket
import hmac
import hashlib
secret_key = b'egg'
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
msg = sk.recv(1024)
h = hmac.new(secret_key, msg, digestmod=hashlib.sha1)
digest = h.digest()
sk.send(digest)

sk.close()

注意:
Hmac.new()一定要有digestmod参数 之前没有设置这个变量,所以一直报错

再遇继承:

__author__ = 'Eva_J'


class Base(object):
    def __init__(self, name):
        self.name = name
        self.Testfunc()

    def Testfunc(self):
        print('do Base Testfunc')


class Son(Base):
    def Testfunc(self):
        print('do Son Testfunc')

class Base2(object):
    def Testfunc(self):
        print('do Base2 Testfunc')


class GrandSon(Base2, Son):
    pass


sonobj = Son('sonobj')

总结:即使调用了父类的__init__,但是在执行别的方法时,还是首先考虑自身,没有再考虑父类

小技巧:
pycharm把.py文件识别成.text文件,代码提示没有了,改掉文件名才能出现提示。
可能是因为创造文件的时候不小心把这个文件名与text关联了。

解决方案:
File->Settings->Editor->File Types 里面找到text,然后在text里找到这个文件名,删除就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值