美文网首页
Python3 快速使用笔记

Python3 快速使用笔记

作者: Mr_Michael | 来源:发表于2019-04-12 11:15 被阅读0次

一、基础使用

python脚本解析器声明

#!/usr/bin/python3
# -*- coding: utf-8 -*-

数据类型

1.整型、浮点型、字符串、布尔类型

  • 数据类型是在被调用的时候定义的
a = 12
b = 0x12
c = 3.14
d = 'hello world'
e = True

print('%s' % a) #数据类型是在被调用的时候定义的
print('0x%x' % b)
print('%s' % d)
print('I\'m \"OK\"!')   #字符串内含有特性字符可以使用转义字符
print('''michael
jack
tony''')    #打印多行的其中一种方法
print('你好', 'python3')  #组合打印

2.列表list

  • 列表元素可以是不同数据类型,用中括号[]表示
classmates = ['michael', 'jack', 'tony']
classmates.append('gavin')  #追加元素
classmates.insert(1, 'tom') #插入元素
classmates.pop()    #删除末尾元素
classmates.pop(2)   #删除指定位置元素
classmates[1] = 'lily'  #修改元素

3.元组tuple

  • 元素可以是不同数据类型,一旦初始化就不能修改,用小括号()表示
fruit = ('apple', 'banana', 'orange', 123)
fruit = ('apple', classmates, 'orange') #变量可以被重定义
fruit[1][0] = 'ming'    #如果元组中含有可变元素,则可变元素的内容是可修改的

4.字典dict

  • 字典是无序的对象集合,字典的元素的值通过键来取,用大括号{}表示
dict = {'name':'join', 'code':1234, 'dept':'sales', 5:'ok'}
print(dict)
print(dict['name']) #通过键搜索值
print(dict[5])      #通过键搜索值
dict['age'] = 22    #添加元素
if dict.get('age'):
    print('%s is in dict' % 'age')
else:
    print('%s is not in dict' % 'age')
dict.pop(5)     #删除键值
print(dict.keys())  #打印所有键
print(dict.values())    #打印所有值

5.集合set

  • 集合是一组键的集合,但不包含值,而且键不能重复
  • 创建一个set,需要提供一个list作为输入
s = set([1,2,3])    #创建一个set,需要提供一个list作为输入集合
print(s)
s.add(4)    #添加元素
s.add(3)    #添加元素,元素重复,只保留一个
print(s)
s.remove(2) #删除元素
print(s)
s1 = set([1,2,3])
s2 = set([2,3,4])
print(s1 & s2)  #set可以看成数学意义上的无序和无重复元素的集合

6.数据类型转换

f = int('123')      #字符串转整型
g = int(123.456)    #浮点型转整型
h = float('123.4')  #字符串转浮点型
i = str(123)        #整型转字符串
j = tuple([1,2,3,4])        #列表转元组
k = tuple(set([1,2,3,4]))   #集合转元组
l = list((1,2,3))       #元组转列表
m = list(set([1,2,3]))  #集合转列表

流程控制

1.if-else

age = input("birth:")   #input输出的是字符串
age = int(age)  #字符串转整型
if age >= 18:
    print('adult')
elif age >= 6:
    print('teenager')
else:
    print('kid')

2.for循环

i = [1,2,3]
for value in i:     #通过迭代器循环
    print(value)

for value in list(range(2,5)):  #range生成从2开始小于5的数
    print(value)
    
for value in range(2,5):    #range生成从2开始小于5的数
    print(value)
    
l = [1,2,3,4,5,6]
for var in l[2:4]:  #分段循环
    print(var)

people = {'name':'jony', 'age':22, 'adpt':'sale'}
for item, value in people.items():  #多变量
    print(item,'\t:',value)

3.while循环

n = 0
while n < 5:
    print(n)
    n += 1
    
#break
n = 0
while n < 10:
    if n > 5:
        break
    print(n)
    n += 1
    
    
#continue
n = 0
while n < 10:
    n += 1
    if n == 5:
        continue
    print(n)

4.列表生成式

  • 对迭代器的元素进行修改,产生新的列表
num1 = [x*x for x in range(1,5)] #x是迭代器的元素,x*x是组合而成的新的列表元素

num2 = [x*y for x in range(1,5) for y in range(2,5)]    #两重循环

P = [str(item) + '=' + str(value) for item, value in people.items()]

5.生成器 generator

  • 在循环的过程中不断推算出后续的元素,不必创建完整的list,从而节省大量的空间
g = (x*x for x in range(1,5))   #通过生成器产生的对象与元组是不同的
k = (1,2,3,4)
print(g)    
print(k)

for n in g: #生成器和元组、列表都能迭代,但是生成器占用空间很少
    print(n)

for n in k:
    print(n)

def odd():
    print('step1')
    yield(1)    #函数中有yield,那么函数就会变为生成器
    print('step2')
    yield(3)
    print('step3')
    yield(5)
    return 
o = odd()   #通过生成器生成一个实例
next(o)     #每次调用next(),开始执行,遇到yield返回参数,再次执行next从上次返回yield的地方执行
next(o)
next(o)

for var in odd():
    print(var)

函数

1.函数定义与调用

def printstd( str ):        #函数的参数类型在实际调用中决定
    '打印传入的字符串到标准输出'
    print(str)
    return

printstd(123)

f = printstd    #变量可以指向函数和调用函数
f('function f')

2.默认参数

def printinfo(name = 'jack', age = 22):
    '打印传入的信息'
    print('name:', name)
    print('age:', age)
    return
    
printinfo()

3.不定长度参数

  • 加了星号(*)的变量名会存放所有未命名的变量参数
def printinfo2( argc, *argv ):
    "打印任何传入的参数"
    print(argc)
    print('argv len:', len(argv))
    for var in argv:
        print(var)
    return

printinfo2(5,['a','b'],2,3,4)

4.递归函数

def fact(n):
    '递归处理参数'
    if n==1:
        return 1
    return n*fact(n-1)

5.高阶函数

  • 一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
def add(a,b):
    return a+b

def fun1(x,y,f):
    return f(x,y)*y

print(fun1(1,2,add))

1)高阶函数map

  • map()函数接收两个参数,一个函数,一个序列
  • map()将传入的函数依次作用到序列的每一个元素,把结果作为新的序列返回
def f(x):
    return x*x;

r = map(f, range(5))
print(list(r))

2)高阶函数reduce (积累)

  • reduce()函数接收两个参数,一个函数,一个序列
  • reduce()将函数作用在序列上,这个函数必须接收两个参数,reduce将结果与序列下一元素作累积计算
  • reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
from functools import reduce    #插入reduce函数 only python3

s = reduce(add, [1,2,3,4,5])
print(s)

#定义字符串转整型函数
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
    def fn(x,y):
        return x*10+y
    def char2num(s):
        return DIGITS[s]
    return reduce(fn, map(char2num, s))

print('sum:', str2int('1245'))

3)高阶函数filter (过滤)

  • filter()函数接收两个参数,一个函数,一个序列
  • filter将传入的函数依次作用到序列的每一个元素,然后根据返回值为真的元素
def is_odd(n):
    return n % 2 == 1

m = filter(is_odd, range(10))

4)高阶函数sort (排序)

  • sorted()函数接收两个参数,一个函数(通过key指定),一个序列
  • sorted通过参数key指定的函数依次作用到序列的每一个元素,并根据函数返回的结果对原来的元素进行排序(并非使用结果生成新的序列)
  • ascii值越小的元素排在前面
n = sorted([10,-5,3,-20,8], key=abs)    #序列按绝对值结果排序
print(n)

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
    return t[0] #字典元素的第一个对象
def by_score(t):
    return -t[1]    #字典元素的第二个对象
    
m = sorted(L, key=by_name)
print(m)
m = sorted(L, key=by_score) #分数从高到低
print(m)

6.返回函数

  • 把函数作为结果值返回
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f = lazy_sum(1,2,3,4,5)
print(f())  #当调用函数时,才真正计算求和结果

1)外部作用域

  • 如果内部函数有其外部变量,每当返回一个函数时,都有自己的外部变量,从初始值开始;调用函数,外部变量就保持改变。
def createcounter():
    x = [0,]    #外部作用域 对内部函数counter而言,x就是外部变量
                #每调用createcounter返回一个函数,都有自己的外部变量,从初始值开始,调用函数,外部变量就保持改变
    def counter():
        x[0] += 1   #对序列操作不是对变量赋值,而是对指向的对象赋值,不受局部作用域影响
        return x[0]
    return counter

counterA = createcounter()
counterB = createcounter()
print(counterA(),counterA(),counterA())     #1,2,3
print(counterB(),counterB(),counterB())     #1,2,3

2)全局变量、外部作用域、内部作用域区别

  • global k 声明为全局变量
  • nonlocal n 声明为非局部变量
  • 调用外层函数,其变量重新初始化
k = 0
def outside():
    #外部作用域
    m = 1       
    n = 1
    global k    #声明为全局变量,不会重复定义一个变量
    k += 1
    def inside():
        m = 2   #局部作用域      两个m是不一样的变量
        nonlocal n  #声明为非局部变量,不会重复定义一个变量
        n += 1
        global k    #声明为全局变量,不会重复定义一个变量
        k += 1
        print(m,n,k)
        return
    inside()
    print(m,n,k)
    return

outside()   #2,2,2   1,2,2
outside()   #2,2,4   1,2,4

7.匿名函数

  • 关键字lambda表示匿名函数,冒号前面的表示函数参数,冒号后面的表示返回值。
  • 用最简单方式定义函数
m = map(lambda x: x * x, [1,2,3,4,5])
print(list(m))

f = filter(lambda n: n%2==1, range(10))
print(list(f))

8.装饰器 decorator

  • 装饰器是一个函数,其输入参数是函数,并返回一个函数,即对输入函数进行装饰。

1)自定义装饰器

def log(func):
    def wrapper(*args, **kv):   #参数定义为(*args, **kv),可以接受任意参数的调用
        print('call %s()'% func.__name__)   #额外添加的代码
        return func(*args, **kv)    #运行函数原来的代码
    return wrapper

def now():
    print('2019-01-24')
    return

f = log(now)
f()

2)使用python内置函数定义装饰器

import functools

def log(func):
    @functools.wraps(func)  #表明是使用装饰器
    def wrapper(*args, **kv):
        print('call %s()'% func.__name__)
        return func(*args, **kv)
    return wrapper

g = log(now)
g()

3)带输入参数的装饰器

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kv):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kv)
        return wrapper
    return decorator
        
h = log("hello")(now)
h()

9.偏函数

  • 通过functools.partial函数,把一个函数的某些参数设置默认值,返回一个新函数
import functools

def info(x = 10, y = 5):
    print(x,y)
    return

info2 = functools.partial(info, y=2)    #y从默认的5改为2
info2()

二、模块使用

  • 在Python中,一个.py文件就称之为一个模块(Module)
  • 模块提高代码的可维护性,其包括Python内置的模块和第三方模块
  • 相同名字的函数和变量完全可以分别存在不同的模块中,但尽量不要与内置函数名字冲突

自定义模块

模块命名:module.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

'a test module' #任何模块的第一行字符串被视为模块的文档注释

__author__ = 'Michael Lee'  #作者署名

import sys  #导入sys模块

def test():
    args = sys.argv     #sys.argv指向命令行的所有参数
    if len(args) == 1:
        print('hello world')
    elif len(args) == 2:
        print('hello, %s' % args[1])
    else:
        print('Too many arguments')
        
#_xxx和__xxx这样的函数或变量表示私有的,不应该被外部引用
def _private_1(name):
    return 'Hello, %s' % name
        
def _private_2(name):
    return 'Hi, %s' % name      
        
def greeting(name):
    if len(name) > 3:
        return _private_1(name)
    else:
        return _private_2(name)
        
    
#如果运行模块,解析器会将特殊变量__name__置为__main__
#所以如果是运行模块,就调用模块函数;只是导入模块,则不会运行
if __name__=='__main__':    
    test()

调用模块

import module

module.test()
print(module.greeting('michael'))

内建模块

1.time模块

import time #引入时间模块

#获取UTC时间,单位s
ticks = time.time() 
print('Current UTC', ticks, 's')

#获取当地时间     格林时间,元组格式
localtime = time.localtime()    
print('local time:', localtime)

#获取格式化的时间       当地时间转换为简单的可读时间模式
formattime = time.asctime(localtime) 
print('format time:', formattime)

#获取格式化日期            定制输出格式
formatdate = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print('format date:', formatdate)
formatdate2 = time.strftime('%a %b %d %H:%M:%S %Y', time.localtime())
print('format date2:', formatdate2)

#获取某月日历
import calendar
cal = calendar.month(2019, 1)
print(cal)

2.datetime模块

from datetime import datetime

now = datetime.now()
print(now)

#指定某个日期和时间
dt = datetime(2019,1,29,12,20)
print(dt)

#datetime转换为timestamp
#timestamp是相对于epoch time(1970年1月1日 00:00:00 UTC+00:00时区)的秒数
tstamp = now.timestamp()
print(tstamp)

#timestamp转换为datetime
dt = datetime.fromtimestamp(tstamp)
print(dt)

#datetime加减
from datetime import datetime, timedelta
now = now + timedelta(hours=8)
print(now)
now = now - timedelta(days=2,hours=8)
print(now)

三、面向对象编程

  • 采用面向对象的程序设计思想,首选思考的不是程序的执行流程,而是如Student这种数据类型应该被视为一个对象,这个对象拥有namescore这两个属性(Property)。给对象发消息实际上就是调用对象对应的关联函数,我们称之为对象的方法(Method)。
  • Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student

类与实例

  • class定义一个类,类是一个抽象的概念,类的内部有属性和方法
  • 类名通常是大写开头的单词
class Student(object):

    #__init__方法定义初始化实例时要创建的属性
    #类的方法的第一个参数永远是self,表示创建的实例本身
    def __init__(self, name, score):
        self.__name = name  #属性名称前面加上两个下划线就变为私有属性,外部不能访问
        self.__score = score
    
    #自定义方法
    #类的方法的第一个参数永远是self,调用时不用传递该参数,其他与函数一致
    def get_name(self):
        return self.__name
        
    def get_score(self):
        return self.__score
        
    def set_score(self, score):
        if score >= 0 and score <=100:
            self.__score = score
            return True
        else:
            return False

    def get_grade(self):
        if self.__score >= 90:
            return 'A'
        elif self.__score >= 60:
            return 'B'
        else:
            return 'C'
  • 通过类创建的变量就是实例object
michael = Student('michael', 100)   #传入创建实例需要的属性的参数
lisa = Student('lisa', 98)
michael.set_score(99)

print(michael.get_name(), michael.get_score(), michael.get_grade())
print(lisa.get_name(), lisa.get_score(), lisa.get_grade())
  • python中所有的对

  • 象(包括整数、字符串、函数和类等)都是从一个类中创建出来的

  • str是用来创建字符串对象的类,int是用来创建整数对象的类。type就是创建类对象的类

继承与子类

  • 当我们定义一个class的时候,可以从某个现有的class继承
  • 新的class称为子类(Subclass),而被继承的class称为父类(Base class)
  • 其实所有的类都是从object这个父类继承
class Animal(object):
    def __init__(self, type):
        self.type = type
    
    def get_type(self):
        print('type is %s' % self.type)
    
    def run(self):
        print('Animal is running')
        
    def eat(self):
        print('Animal is eating')
        
#子类获得了父类的全部功能
class Dog(Animal):
    def watch(self):    #子类可以添加自己的属性和方法
        print('Dog is watching')
    def eat(self):  #当子类与父类存在相同的方法,子类方法会覆盖父类,即多态
        print('Dog is eating beef') 
    
mammal = Animal('mammal')
jim = Dog('dog')
jim.get_type()
jim.run()
jim.eat()
jim.watch()

def eat_food(animal):
    animal.eat()
    
eat_food(jim)
eat_food(mammal)    #多态的好处是可以根据不同实例对相同方法有不同处理

动态绑定属性和方法

给实例绑定属性

class Student(object):
    pass
    
s = Student()
s.name = 'Jack' #动态给实例绑定一个属性,只对当前实例有效
print(s.name)

给实例绑定方法

def set_age(self, age):
    self.age = age  #调用时动态给实例绑定一个属性
    
from types import MethodType
s.set_age = MethodType(set_age, s) #给实例绑定一个方法
s.set_age(23)
print(s.age)

给类动态绑定属性和方法

Student.name = ''   #直接给类动态绑定属性
Student.set_age = set_age   #直接给类动态绑定方法, 这样所有实例都可以调用
Tom = Student()
Tom.set_age(25)

限制类的属性__slots__

类和实例不能绑定限制属性之外的属性

class People(object):
    __slots__ = ('name', 'age') # 用元组tuple定义允许绑定的属性名称

Worker = People()
Worker.name = 'Mike'
Worker.age = 26
#Worker.height = 180
print(Worker.name, Worker.age)

类的装饰器@property

  • 在方法前一行加上@property,可以把一个类方法转换为类属性
  • 用属性的方式操作方法,使调用更简单,也可以很好保护内部参数,避免乱设置
class Animal(object):

    #初始化时的实例属性
    def __init__(self, skill, age):
        self.__skill = skill
        self.__age = age

    @property   #装饰器@property把一个getter方法变为属性,可读功能
    def skill(self):
        return self.__skill

    @skill.setter   #装饰器@skill.setter把一个setter方法变为属性,可写功能
    def skill(self, skill):
        self.__skill  = skill
        
    @property   #装饰器@property把一个getter方法变为属性,可读功能
    def age(self):
        return self.__age

    @age.setter #装饰器@skill.setter把一个setter方法变为属性,可写功能
    def age(self, age):
        self.__age  = age

cat = Animal('run', 2)
print(cat.skill, cat.age)   #方法变为了可读属性
#print(cat.skill(), cat.age())  #当作方法调用会出错
cat.skill = 'eat'   #方法变为了可写属性
cat.age = 3

动态地创建类

  • type函数可以动态地创建类
  • type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
MyClass = type('MyClass', (), {})   #类的父类是object,类的属性为空

def set_age(self, age):
    self.age = age
    return

def get_age(self):
    print('get_age:', self.age)
    return

#通过字典定义类的属性或方法
MySubClass = type('MySubClass', (MyClass,), {'age':12, 'set_age':set_age, 'get_age':get_age,})
print(MySubClass)
mysubclass = MySubClass()   #类需要创建实例才能调用方法
mysubclass.set_age(10)
mysubclass.get_age()

多重继承

  • 一个子类可以从多个父类中继承
class Runable(object):
    def run(self):
        print('Running')

class Flyable(object):
    def fly(self):
        print('Flying')

class Mammal(Animal, Runable):  #子类同时继承了多个父类
    pass

class Bird(Animal, Flyable):
    pass
    
dog = Mammal('run', 2)
parrot = Bird('fly', 3)
print(dog.skill, dog.age)
dog.run()
print(parrot.skill, parrot.age)
parrot.fly()

枚举类

  • 从父类Enum中继承的子类是枚举类
  • 提供互不冲突的属性
from enum import Enum, unique

@unique #@unique装饰器可以帮助我们检查保证没有重复值
class Weekday(Enum):    #从父类Enum中继承
    Sun = 0 # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

day = Weekday.Sun
print(Weekday.Sun)
print(Weekday.Sun.value)
print(day == Weekday.Sun)

@unique
class Gender(Enum):
    Male = 0
    Female = 1
    
class Student(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

bart = Student('Bart', Gender.Male)
if bart.gender == Gender.Male:
    print('Test Pass')
else:
    print('Test Fail')

四、文件操作

读文件操作

1.不限长度读取

  • UTF-8编码的文本文件
PATH = '/home/michael/Python3_Program/5_IO/'

try:
    f = open(PATH+'test.txt', 'r')  #打开文件
    #调用read()方法可以一次读取文件的全部内容,用一个str对象表示
    print(f.read())
finally:
    if f:
        f.close()   #关闭文件

2.使用with语句自动关闭文件

with open(PATH+'test.txt', 'r') as f:
    print(f.read())

3.限制长度读取:read(size)

with open(PATH+'test.txt', 'r') as f:
    str = f.read(10)
    while str!='':  #限定一次读10bytes
        print(str)
        str = f.read(10)

4.按行读取:readline()

with open(PATH+'test.txt', 'r') as f:
    str = f.readline()
    while str!='':
        print(str.strip())  # 把末尾的'\n'删掉
        str = f.readline()

5.读二进制文件 比如图片、视频等

with open(PATH+'file.bin', 'rb') as f:
    str = f.readline()
    print(str)

写文件操作

1.以覆盖形式写入

with open(PATH+'test.txt', 'w') as f:
    f.write('hello file2\n')    #当调用close时,系统才能保证数据已经写入文件

2.以追加形式写入

with open(PATH+'test.txt', 'a') as f:
    f.write('hello file3\n')

内存读写操作

1.从内存中读写str:通过StringIO模块

from io import StringIO

f = StringIO()  #创建StringIO后就可以像普通文件那样读写
f.write('hello stringio')
print(f.getvalue()) #getvalue()方法用于获得写入后的str

2.从内存中读写二进制数据:通过BytesIO模块

from io import BytesIO

f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.tell()) #返回当前读写位置
f.write('hello'.encode('utf-8'))
print(f.tell()) #返回当前读写位置
print(f.getvalue())

序列化

  • 把变量从内存中变成可存储或传输的过程称之为序列化,序列化后的内容可以写入磁盘或通过网络传输。
  • 把变量内容从序列化的对象重新读到内存里称之为反序列化

1.对象序列化成bytes类型:通过pickle模块

  • pickle.dumps()方法把可序列化对象编码成bytes
  • pickle.loads()方法将bytes反序列化出对象
import pickle

d = dict(name='Bob', age=20, score=88)
bytes = pickle.dumps(d) #pickle.dumps()方法把可序列化对象编码成bytes
print(bytes)    
e = pickle.loads(bytes) #pickle.loads()方法将bytes反序列化出对象
print(e)

with open(PATH+'dump.txt', 'wb') as f:
    pickle.dump(d, f)   #pickle.dump()把对象序列化后写入一个file-like Object(文件描述符)

with open(PATH+'dump.txt', 'rb') as f:
    g = pickle.load(f)  #pickle.load()方法从一个file-like Object(文件描述符)中直接反序列化出对象
    print(g)

2.对象序列化成json类型:通过json模块

  • JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输
import json

d = dict(name='Tom', age=20, score=88)  # 不一定要字典,可序列化为JSON的对象都可以
jsonstr = json.dumps(d) #json.dumps 用于将 Python 对象编码成 JSON 字符串。
print(jsonstr)
e = json.loads(jsonstr) #json.loads 用于解码 JSON 数据。该函数返回 Python 字段的数据类型。
print(e)

with open(PATH+'json.txt', 'w') as f:
    json.dump(d, f) #json.dump()直接把对象序列化后写入一个file-like Object(文件描述符)
    pass
    
with open(PATH+'json.txt', 'r') as f:
    g = json.load(f)    #json.load()方法从一个file-like Object(文件描述符)中直接反序列化出对象
    print(g)

3.将类序列化成json类型

class Student(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

#输入一个实例,返回一个字典对象
def student2dict(std):  
    return {
        'name':std.name,
        'age':std.age,
        'score':std.score
    }

#输入一个字典对象,返回一个实例
def dict2student(d):    
    return Student(d['name'], d['age'], d['score'])

s = Student('Jack', 20, 88)
#方法1
#jsonstr = json.dumps(s, default=student2dict)  #需要传入将类转换为字典的函数
#方法2
jsonstr = json.dumps(s, default=lambda obj: obj.__dict__) #class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。
print(jsonstr)
s1 = json.loads(jsonstr, object_hook=dict2student)
print(s1)

五、进程

  • 多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响。

进程基础使用

import os   #插入系统调用模块

# Only works on Unix/Linux/Mac, Windows没有fork调用,
pid = os.fork() #对父进程返回子进程id,对子进程返回0
if pid == 0:
    #child
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    #parent
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))

多进程模块multiprocessing

1.通过multiprocessing模块的Process类创建一个进程对象

from multiprocessing import Process
import os

#子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s).' % (name, os.getpid()))

if __name__ == '__main__':
    print('Parent process %s.' % os.getpid())
    #传入执行函数和执行函数的参数
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()   #启动子进程
    p.join()    #等待子进程结束后再继续往下运行
    print('Child process end.')

2.通过multiprocessing模块的Pool类【进程池】批量创建子进程

from multiprocessing import Pool
import os, time, random

def long_timr_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time() #获取当前时间
    time.sleep(random.random()*3)
    end = time.time()   #再次获取当前时间
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4) #定义一个进程池,最大进程数4
    for i in range(5):
        #Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
        #传入子进程执行函数和执行函数的参数,并启动进程
        p.apply_async(long_timr_task, args=(i,))

    p.close()   #关闭pool,使其不在接受新的任务。
    p.join()    #等待子进程结束后再继续往下运行
    print('All subprocesses done.')

子进程模块subprocess

  • subprocess模块可以方便地启动一个外部子进程,然后控制其输入和输出
import subprocess

r = subprocess.call(['nslookup', 'www.python.org']) #运行外部进程:即执行命令nslookup
print('Exit code:', r)
r = subprocess.call(['pwd',])   #运行外部进程:即执行命令pwd
print('Exit code:', r)

进程间通信

  • Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据
from multiprocessing import Process, Queue
import os, time, random

#写进程代码
def ps_write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

#读进程代码
def ps_read(q):
    print('Process to read: %s' % os.getpid())
    while(True):
        value = q.get(True) #如果队列为空,get操作会阻塞等待
        print('Get %s from queue.' % value)
    
if __name__=='__main__':
    q = Queue() #创建队列
    pw = Process(target=ps_write, args=(q,))
    pr = Process(target=ps_read, args=(q,))
    pw.start()
    pr.start()
    pw.join()
    pr.terminate()  #pr进程里是死循环,无法等待其结束,只能强行终止

六、线程

  • Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。

线程定义与使用

import time, threading

# 新线程执行的代码
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n = n + 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(0.2)
    print('thread %s ended.' % threading.current_thread().name)


print('thread %s is running...' % threading.current_thread().name)
#传入线程执行函数和函数的参数
t = threading.Thread(target=loop, name='LoopThread')
t.start()   #启动线程
t.join()    #等待线程结束
print('thread %s ended.' % threading.current_thread().name)

互斥量

  • 多线程中,所有变量都由所有线程共享,任何一个变量都可以被任何一个线程修改
  • 要保证一个线程使用资源时,不被其他线程打扰
  • 当两个线程在等待对方的资源时,就有可能导致互斥
import threading

balance = 0
lock = threading.Lock() #定义互斥量

def change_it(n):
    global balance  #全局变量声明
    balance = balance + n
    balance = balance - n
    
def run_thread(n):
    for i in range(100000):
        lock.acquire()  #获取互斥锁
        try:
            change_it(n)
        finally:
            lock.release()  #释放互斥锁

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(5,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

线程内的公共局部变量

  • 线程的局部变量只有自己能看到,但如果线程中调用函数,通过函数入口参数传递会比较麻烦。
  • ThreadLocal是线程的公共变量区,对于线程中调用的其他函数是可访问的,而不必通过参数传递
import threading
local_school = threading.local()
temp_age = 12   #使用全局变量也可以传递参数,但是不安全

def process_student():
    # 获取当前线程关联的student:
    std = local_school.student
    grade = local_school.grade
    age = temp_age  #函数中只读全局变量,不用声明
    print('Hello, %s %d %d(in %s)' % (std, grade, age, threading.current_thread().name))

def process_thread(name, grade, age):
    # 定义ThreadLocal的变量
    local_school.student = name #ThreadLocal全局变量在每个线程中都有独立副本
    local_school.grade = grade
    global temp_age
    temp_age = age  #函数中对全局变量赋值,需要声明,不声明代表赋值的局部变量变量
    process_student()

#name为线程名称
t1 = threading.Thread(target=process_thread, args=('Alice', 6, 14), name='Thread-A')
t2 = threading.Thread(target=process_thread, args=('Bob', 5, 13), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()

七、网络通信

TCP

1.服务器端 使用线程

  • 绑定的ip地址需要是本机地址
import socket
import threading

# 创建socket  AF_INET指定使用IPv4协议,SOCK_STREAM指定使用面向流的TCP协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)       
s.bind(('192.168.83.130', 8000))     # 绑定地址和端口
s.listen(5) #最多监听5个客户端

def fun(sock, addr):
    print('Accept new connection from {}'.format(addr))
    sock.send('Hello!'.encode())    # 向客户端发送数据
    while True:
        data = sock.recv(1024)      # 每次最多接收1024b(1kb)
        if data == 'exit' or not data:
            break
        sock.send('hello,{}'.format(data).encode()) # 向客户端发送数据
    sock.close()
    print('Connection closed {}'.format(addr))

print('Waiting for connection...')
while True:
    sock, addr = s.accept() # 等待连接,返回socket对象和请求连接的客户端地址
    # 创建新线程(或进程)来处理TCP连接
    t = threading.Thread(target=fun, args=(sock, addr))
    t.start()# 启动线程

2.客户端

import socket

#创建socket   AF_INET指定使用IPv4协议,SOCK_STREAM指定使用面向流的TCP协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接,参数是tuple类型
s.connect(('192.168.83.130', 8000)) #阻塞式连接,连接成功继续执行后面代码

print(s.recv(1024))
for data in ['li', 'bo', 'ca']:
    s.send(data.encode())   # 向服务器发送数据  对发送的数据进行编码
    print(s.recv(1024))     # 每次最多接收1024b(1kb)
s.send('exit'.encode())
s.close()

UDP

1.服务器端 使用线程

  • udp服务器不需要连接,对接收的数据处理即可
import socket
import threading

 # 创建一个基于UDP的socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('192.168.83.130', 8000))    # 绑定地址与端口

def fun(data, addr):
    print('from {}, content is {}'.format(addr, data))
    s.sendto('Hi!{}'.format(data).encode(), addr)   # 向客户端返回内容

while True:
    #等待接收客户端发送的内容
    data, addr = s.recvfrom(1024)   #返回客户端的数据和地址
    t = threading.Thread(target=fun, args=(data, addr))
    t.start()   # 启动线程

2.客户端

import socket

# 创建一个基于UDP的socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 向指定服务器与端口号发送内容
s.sendto('hello!'.encode(), ('192.168.83.130', 8000))
print(s.recv(1024))
s.close()

相关文章

网友评论

      本文标题:Python3 快速使用笔记

      本文链接:https://www.haomeiwen.com/subject/hlgqwqtx.html