python3语法 余数不等于0_Python3 语法总结

Python 基础

数据类型和变量

整数: 1, -1, 0; 十六进制: 0xab

浮点数: 1.23, -1.23, 1.23e9, 12.3e8, 1.2e-5

字符串: '', "", r''(不转义), '''...'''(表示多行内容), r'''...'''

布尔值: True, False(运算符 and, or, not)

空值:None

变量:变量名必须是大小写英文、数字和_的组合,且不能用数字开头

常量: 通常用全部大写的变量名表示常量(Python没有任何机制保证常量不会被改变)

/精确触发, //地板除, %取余数

字符串和编码

字符编码

ASCII(单字节), Unicode(通常两个字节,复杂的4字节), UTF-8(1~6个字节, 中文3个字节)。

在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

python字符串

在现在的python3 版本中, 字符串以unicode编码,所以python字符串支持多语言。

ord(‘A’), chr(65) 实现单字符编码的整数和字符的转换。

'\u4e2d\u6587' 表示 '中文', 4e2d 是'中'字符整数编码的16进制表示。

‘ABC’: str类型,以unicode编码,通常一个字符对应两个字节;

b’ABC’: bytes类型, 每个字符只占用一个字节(网络传输或保存磁盘需要先变成bytes)。

encode()将unicode表示的str转换成指定编码的bytes。例如:

‘ABC’.encode(‘ascii’) 结果为 b’ABC’

‘中文’.encode(‘utf-8’) 结果为 b’\xe4\xb8\xad\xe6\x96\x87’

decode()将bytes 转变成 str,需指定bytes的编码。例如:

b’ABC’.decode(‘ascii’) ===> ‘ABC’

b’\xe4\xb8\xad\xe6\x96\x87’.decode(‘utf-8’) ===> ‘中文’

b’\xe4\xb8\xad\xff’.decode(‘utf-8’, errors=’ignore’) ; ignore 忽略错误字节, 否则报错。

len(str) 计算字符数, len(bytes)计算字节数

使用UTF-8 without BOM对python源码编码,并且在开头加上# -*- coding: utf-8 -*-

格式化

与C语言一致,使用%

使用字符串的format()方法。它会用传入的参数依次替换字符串内的占位符{0}、{1}…

'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)

‘Hello, 小明, 成绩提升了 17.1%’

list

python内置数据类型: 可变的有序列表

例如:

example = [‘a’, ‘b’, ‘c’]

len(list) 获取元素个数

list[0], list[-1] 索引访问元素

list.appen(‘var’) 追加元素到末尾

list.insert(index, ‘var’) 插入元素到指定位置

list.pop() 删除末尾的元素

list.pop(i) 删除指定位置元素

list[index] = ‘var’ 替换元素值

list 元素类型可以不同

list 可以包含list

tuple

python内置数据类型: 不可变有序列表—元组。

tuple 一旦初始化就不可改变(指向不变),其他获取元素方法与list相同。

只有一个元素的tuple定义时必须加一个逗号:

t = (1,)

条件判断

if condition1:

pass

elif condition2:

pass

else:

pass

循环

break 跳出循环

continue 跳过当前迭代

#for ... in 循环

for x in xrange(1,10):

pass

#while 循环

while condition:

pass

dict

python内置数据类型: dict, 存储键值(key-value)对。

dict根据key来计算value的存储位置, 因此key必须是不可变对象。(list不能作为key)。

#初始化一个dict

`d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}`

#设置或者更改键值

`d['Adam'] = 67`

#访问不存在的key,会报错

`d['abc']`

#使用`in`判断key是否存在

'abc' in d # False

#使用get,如果key不存在,可以返回None,或者自己指定的value

d.get('abc')

d.get('abc', -1)

#删除一个key

d.pop('key')

set

python内置数据类型: 无序无重复元素的集合。

同样的,set中key必须是不可变对象。

#创建一个set,需要提供一个list作为输入集合

s = set([a,b,c])

#添加元素到set

s.add(c)

#删除元素

s.remove(c)

#集合交集、并集操作

s1 & s2

s1 | s2

函数

调用函数

需要知道函数名称和参数,如果参数数量或者参数类型不对,报TypeError。

数据类型转换函数: int(), float(), str(), bool()

定义函数

#如果没有return,返回None

def func_name(x):

pass #占位符,什么也不干,目的是通过语法检查。

#参数检查

isinstance(x, (int, float))

函数返回多个值其实是返回一个tuple,多个变量可以同时接收一个tuple。

函数参数

位置参数

def power(x, n):

pass

power(5,2)

x, n 就是位置参数,按照位置顺序依次传递的参数。

默认参数

def power(x, n=2):

pass

power(5)

必选参数在前,默认参数在后。默认参数可以降低函数调用难度。

默认参数在函数定义的时候就被计算出来了,如果在调用中改变了默认参数,默认参数的内容就变了。因此定义默认参数要牢记一点:默认参数必须指向不变对象

可变参数

def calc(*numbers):

pass

calc(1,2)

calc()

nums = [1,2,3]

calc(*nums)

在函数内部参数numbers接收到的是一个tuple。

*nums 把nums这个list的所有元素作为可变参数传进去。(tuple也一样)

关键字参数

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。关键字参数可以扩展函数功能。

def person(name, age, **kw):

pass

extra = {'city': 'Beijing', 'job':'Engineer'}

person('Jack',24, city=extra['city'], job=extra['job'])

person('Jack', 24, **extra)

**extra 把 extra 这个dict的所有 key-value 用关键字参数传入到函数的**kw, 参数kw将获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra

命名关键字参数

命名关键字参数可可以限制关键字参数的名字。

#需要一个特殊分隔符`*`,否则解释器无法识别位置参数和命名关键字参数

def person(name, age, *, city, job):

pass

#正确调用方式

person('Jack', 24, city='Beijing', job='Engineer')

#如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要特殊分隔符`*`

def person(name, age, *args, city, job)

#命名关键字参数必须传入参数名,否则将被视为位置参数,导致调用报错

person('Jack', 24, 'Beijing', 'Engineer')

#命名关键字参数可以有缺省值,调用时可不传入

def person(name, age, *, city='Beijing', job):

pass

person('Jack', 24, job='Engineer')

参数组合

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数

def f1(a, b, c=0, *args, **kw):

pass

def f2(a, b, c=0, *, d, **kw):

pass

#通过一个tuple和dict调用函数

args = (1, 2, 3, 4)

kw = {'d': 99, 'x': '#'}

f1(*args, **kw)

a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}

args = (1, 2, 3)

kw = {'d': 88, 'x': '#'}

f2(*args, **kw)

a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的

递归函数

函数在内部调用自己叫递归函数。

def fact(n):

if n == 1:

return 1

return n * fact(n-1)

使用递归函数需要注意防止栈溢出。解决递归调用栈溢出的方法是通过尾递归优化。

尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。

这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。改成尾递归:

def fact(n):

return fact_iter(n, 1)

def fact_iter(num, product):

if num == 1:

return product

return fact_iter(num - 1, num * product)。

遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化。

高级特性

切片

切片用于取一个list或tuple的部分元素。

L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']

L[0:3] #表示从索引0开始,直到索引3为止,不含索引3。

['Michael', 'Sarah', 'Tracy']

#如果第一个索引是0,可以省略:

L[:3]

L[-2:]

['Bob', 'Jack']

L[-2:-1]

['Bob']

L=list(range(100))

L[:10:2] # 前10个数,每两个取一个

L[::5] # 所有数,每5个取一个

L[:] # 复制一个list

tuple和字符串也可以使用切片操作,结果仍然是tuple和字符串。

迭代

python使用 for ... in 循环对可迭代对象进行迭代。

dict默认对key进行迭代,for key in d

dist 迭代value: for value in d.values()

同时迭代key,value: fro k, v in d.items()

判断一个对象是不是可迭代对象:

from collections import Iterable

isinstance('abc', Iterable)

enumerate把list变成索引元素对

for i, value in enumerate(['A', 'B', 'C'])

列表生成式

python 内置用来创建list的生成式

#要生成的元素放前面,后跟for循环

>>>[x * x for x in range(1,11)]

[1,4,9,16,25,36,49,64,81,100]

#for循环后可以加if判断

>>>[x * x for x in range(1,11) if x % 2 == 0]

[4,16,36,64,100]

#两层循环,生成全排列

>>>[m+n for m in 'ABC' for n in 'XYZ']

['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

#使用两个变量

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }

>>> [k + '=' + v for k, v in d.items()]

['y=B', 'x=A', 'z=C']

生成器(generator)

一边循环一边计算的机制,称为生成器。

把列表生成式的[]改成(), next()函数获得generator的下一个返回值。

用包含yield关键字的函数定义generator。在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

捕获StopIteration错误,获取generator返回值(包含在value中,参考代码)。

g = (x * x for x in range(10))

#next(g),没有更多元素时,抛出StopIteration错误。一般使用for循环迭代生成器

for n in g:

print(n)

def fib(max):

n,a,b = 0,0,1

while n

yield b

a, b = b, a+ b

n =n+1

return 'done'

for n in fib(6):

print(n)

>>> g = fib(6)

while True:

try:

x = next(g)

print('g:', x)

except StopIteration as e:

print('Generator return value: ', e.value)

break

迭代器

凡是可作用于for循环的对象都是Iterable类型

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列。

list,tuple,dict,set,str是Iterable, 通过iter()函数变成Iterator

+ isinstance(g, Iterator)判断g是不是一个Iterator

函数式编程

高阶函数

变量可以指向函数, 函数名是指向函数的变量。一个函数接收另一个函数作为参数,就叫高阶函数。

map/reduce

map() 接收func和Iterable, 将func应用到Iterable中的每个元素,返回Iterator。

list() 函数可以把Iterator整个序列都计算出来,返回一个list。

reduce() 把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

def f(x):

return x*x

r = map(f, [1,2,3,4])

list(r)

[1,4,9,16]

def add(x,y):

return x+y

reduce(add, [1,2,3,4])

10

filter

filter()函数用于过滤序列,接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素, 返回一个Iterator

def is_odd(n):

return n%2 == 1

list(filter(is_odd, [1,2,3,4,5,6,7,8]))

[1,3,5,7]

sorted

sorted() 函数可以对list直接进行排序

sorted() 函数可以接收一个key函数,key函数作用于list的每一个元素,并对key函数返回的结果进行排序,最后按照对应关系返回list相应的元素。

反向排序,传入第三个参数 reverse=True

sorted([36, 5, -12, 9, -21])

[-21, -12, 5, 9, 36]

sorted([36, 5, -12, 9, -21], key=abs)

[5,9,-12,-21,36]

sorted([36, 5, -12, 9, -21], key=abs, reverse=True)

[36,-21,-12,9,5]

返回函数

闭包:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

def lazy_sum(*args):

def sum():

ax = 0

for n in args:

ax = ax + n

return ax

return sum

匿名函数

关键字lambda表示匿名函数,冒号前面表示函数参数,只能有一个表达式。可以把匿名函数赋值给变量。

f = lambda x: x*x

装饰器

装饰器的本质是一个返回函数的高阶函数,用于在代码运行期间动态增加功能。

import functools

def log(func):

@functools.wraps(func) # 复制func的属性到wrapper

def wrapper(*args, **kw):

print('call%s():' % func.__name__)

return func(*args, **kw)

return wrapper

def log(text):

def decorator(func):

@functools.wraps(func)

def wrapper(*args, **kw):

print('%s%s():' %(text, func.__name__))

return func(**args, **kw)

return wrapper

return decorator

#@log放到now()函数的定义处,相当于执行了语句: now = log(now)

@log

def now():

print('2015-01-01')

# 相当于 now = log('execute')(now)

@log('execute')

def now():

print('2015-01-01')

偏函数

functools.partial 把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数。

创建偏函数时,实际上可以接收 函数对象 、*args 和 **kw 这3个参数 。

例如:

int2 = functools.partial(int, base=2)

max2 = functools.partial(max, 10)

模块

一个.py文件就称之为一个模块(Module)

按目录组织模块的方法称为包(Package)

每个包目录下面都有一个__init__.py,这个文件必须存在,否则,Python把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是包目录名, 多层级包目录使用.引用。

标识符名称不要与内置函数冲突,模块名不要与内置模块名冲突。

使用模块

任何模块代码的第一个字符串都被视为模块的文档注释

使用模块前先导入,使用import导入模块

在命令行运行模块文件,解释器设置 __name__为__main__,而如果模块被导入,则不设置。

正常的函数和变量名是公开的(public),可以被直接引用

类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,自己的变量一般不要用这种变量名

类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该 被直接引用

Python并没有一种方法可以完全限制访问private函数或变量

安装第三方模块

使用包管理工具 pip 安装第三方模块

安装常用模块 Anaconda

解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中

添加自己的搜索目录:

一是直接修改sys.path,添加要搜索的目录

设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。

面向对象编程

类和实例

class Student(object):

def __init__(self, name, score):

self.name = name

self.score = score

def print_score(self):

print('%s:%s' % (self.name, self.score))

bart = Student('Bart Simpson', 59)

Python允许对实例变量绑定任何数据

访问限制

class Student(object):

def __init__(self, name, score):

self.__name = name

self.__score = score

def print_score(self):

print('%s:%s' % (self.__name, self.__score))

def get_score(self):

return self.__score

#可以对参数做检查,避免传入无效的参数

def set_score(self, score):

if 0 <= score <= 100:

self.__score = score

else:

raise ValueError('bad score')

以一个下划线开头的实例变量名_xxx外部是可以访问的,但一般视为私有变量。

双下划线开头的实例变量__xxx不能直接访问__xxx,因为解释器对外把__变量改成了_Class__xxx。

不同版本的Python解释器可能会把__xxx改成不同的变量名。

继承和多态

class Animal(object):

def run(self):

print('Animal is running...')

class Dog(Animal):

def run(self):

print('Dog is running...')

class Cat(Animal):

def run(self):

print('Cat is running...')

def run_twice(animal):

animal.run()

animal.run()

run_twice(Animal())

Animal is running...

Animal is running...

run_twice(Dog())

Dog is running...

Dog is running.

#使用isinstance()判断一个对象的类型

a = list()

b = Animal()

c = Dog()

isinstance(a,list) # True

isinstance(b, Animal) # True

isinstance(c,Dog) # True

isinstance(c,Animal) # True

isinstance(b,Dog) # False 子类可以转变成父类, 父类不能变成子类(数据丢失)。

#动态语言的鸭子类型, 并不要求严格的继承体系,

#一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

class Timer(object):

def run(self):

print('Start...')

run_twice(Timer())

Start...

Start...

获取对象信息

使用type()

使用type()返回对应的Class类型。基本类型和指向函数或者类的变量可以使用type判断。

a = Animal()

type(123) #

type('str') #

type(None) #

type(abs) #

type(a) #

#类型判断

type(123)==type(456) #True

#判断基本数据类型可以直接写int,str等

type(123)==int #True

type('abc')==type(123) # False

#使用types模块中定义的常量判断一个对象是否是函数

import types

def fn():

pass

type(fn)==types.FunctionType #True

type(abs)==types.BuiltinFunctionType #True

type(lambda x: x)==types.LambdaType #True

type((x for x in range(10)))==types.GeneratorType #True

对于class的继承关系来说,使用type()就很不方便,应该使用isinstance()函数,见前面小节。

使用dir()

dir()获得一个对象的所有属性和方法,返回字符串list。

dir('ABC')

['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

class MyObject(object):

def __init__(self):

self.x = 9

def power(self):

return self.x * self.x

#hasattr(), getattr(), setattr()

obj = MyObject()

hasattr(obj, 'x') #True

hasattr(obj, 'y') #False

setattr(obj, 'y', 19)

hasattr(obj, 'y') #True

#如果试图获取不存在的属性会抛出AttributeError的错误

getattr(obj, 'z')

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'MyObject' object has no attribute 'z'

#传入一个默认参数,如果属性不存在,返回默认值

getattr(obj, 'z', 404) # 404

#也可以获得对象的方法

fn = getattr(obj, 'power')

实例属性和类属性

#实例属性通过self绑定,或者实例变量自身

class Student(object):

def __init__(self, name):

self.name = name

s = Student('Bob')

s.score = 90

#类属性直接在Class中定义,可以被所有实例访问

class Student(object):

name = 'Student'

s = Student()

print(s.name) #Student

print(Student.name)# Student

#因为相同名称的实例属性将屏蔽掉类属性。

s.name='Mac'

print(s.name) # Mac

del s.name # 删除属性

print(s.name) # Student

面向对象高级编程

使用__slots__

使用__slots__限制实例的属性。__slots__ 定义的属性只对当前的类实例起作用,对继承子类不起作用。除非在子类中也定义__slots__, 这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。

#给实例绑定一个方法

from types import MethodType

class Student(object):

pass

s = Student()

def set_age(self, age):

self.age = age

s.set_age = MethodType(set_age,s)

#给class绑定一个方法

def set_score(self, score):

self.score = score

Student.set_score = set_score

class Student(object):

__slots__ = ('name', 'age')

s = Student()

s.age = 25

s.score = 99 ## AttributeError错误

使用@property

@property 把一个方法变成属性调用。把一个getter方法(func)变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@func.setter,负责把一个setter方法变成属性赋值。只定义getter方法,不定义setter方法就是一个只读属性。

class Student(object):

@property

def score(self):

return self._score

@score.setter

def score(self, value):

if not isinstance(value, int):

raise ValueError('score must be an integer!')

if value < 0 or value > 100:

raise ValueError('score must between 0~100!')

self._score = value

#只读属性

@property

def age(self):

return self._age

s = Student()

s.score = 60 # 调用s.set_score(60)

s.core # s.get_socre

多重继承

使用MixIn给一个类增加多个功能

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):

pass

#编写一个多进程模式的TCP服务

class MyTCPServer(TCPServer, ForkingMixIn):

pass

#编写一个多线程模式的UDP服务

class MyUDPServer(UDPServer, ThreadingMixIn):

pass

#协程模型

class MyTCPServer(TCPServer, CoroutineMixIn):

pass

定制类

__str__

打印实例,定义__str__方法, __repr__用于调试服务

class Student(object):

def __init__(self, name):

self.name = name

def __str__(self):

return 'Student object (name=%s)' % self.name

__repr__ = __str__

s = Student('Mark')

print(s) # 调用 __str__

s # 直接显示变量 调用 __repr__

__iter__

如果一个类想被用于 for ... in 循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环

class Fib(object):

def __init__(self):

self.a, self.b = 0, 1 # 初始化两个计数器a,b

def __iter__(self):

return self # 实例本身就是迭代对象,故返回自己

def __next__(self):

self.a, self.b = self.b, self.a + self.b # 计算下一个值

if self.a > 100000: # 退出循环的条件

raise StopIteration()

return self.a # 返回下一个值

for n in Fib():

print(n)

__getitem__

按索引访问元素,定义__getitem. 此外还有 __setitem__()把对象视作list 或dict来对集合赋值, __delitem__()用于删除某个元素

class Fib(object):

def __getitem__(self, n):

if isinstance(n, int): # n是索引

a, b = 1, 1

for x in range(n):

a, b = b, a+b

return a

if isinstance(n, slice): #n是切片

start = n.start

stop = n.stop

if start is None:

start = 0

a, b = 1,1

L = []

for x in range(stop):

if x >=start:

L.append(a)

a, b = b, a+b

return L

f = Fib()

f[0] # 1

f[0:5] # [1,1,2,3,5]

f[:10]#[1,1,2,3,5,8,13,21,34,55,89]

__getattr__

__getattr__ 动态的返回一个属性, 可以是方法。只有在没有找到属性的情况下,才调用__getattr__。(不会注册属性,也就是说一个不存在的属性,每次获取都会调用__getattr__)

class Student(object):

def __init__(self):

self.name = 'mac'

def __getattr__(self,attr):

if attr=='score': # 返回属性

return 99

if attr=='age':

return lambda:25 # 返回方法

raise AttributeError('\'Student\'object has no attribute\'%s\'' % attr)

__call__

类如果定义了__call__() 方法, 就可以直接对实例进行调用。

class Student(object):

def __init__(self, name):

self.name = name

def __call__(self):

print('My name is%s.' % self.name)

s = Student('Michael')

s() # My name is Michael

callable(Student()) # True

__call__()还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。使用callable判断一个对象是否能被调用。

使用枚举类

from enum import Enum, unique

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',

'Jul', 'Aug', 'Sep','Oct', 'Nov', 'Dec'))

#value属性是自动赋给成员的int常量,默认从1开始计数

for name, member in Month.__members__.items():

print(name, '=>', member, ',', member.value) # Jan => Month.Jan, 1

#从Enum派生出自定义类

#@unique装饰器可以帮助我们检查保证没有重复值。

@unique

class Weekday(Enum):

Sun = 0 # Sun的value被设定为0

Mon = 1

Tue = 2

Wed = 3

Thu = 4

Fri = 5

Sat = 6

#既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。

print(Weekday.Tue) #Weekday.Tue

print(Weekday['Tue'])#Weekday.Tue

print(Weekday.Tue.value) # 2

print(Weekday(1)) # Weekday.Mon

使用元类

type()

type() 函数既可以返回一个对象的类型,又可以创建出新的类型。

要创建一个class对象,type()函数依次传入3个参数:

class的名称;

继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;

class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。

def fn(self, name='world'): # 先定义函数

print('Hello,%s.' % name)

Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class

metaclass

metaclass 元类,可以看作是模板。先定义metaclass,就可以创建类,最后创建实例。

具体应用参考orm的例子。

# metaclass是类的模板,所以必须从`type`类型派生:

class ListMetaclass(type):

def __new__(cls, name, bases, attrs):

attrs['add'] = lambda self, value: self.append(value)

return type.__new__(cls, name, bases, attrs)

#定义类的时候使用ListMetaclass来定制类,传入关键字参数metaclass

class MyList(list, metaclass=ListMetaclass):

pass

L = MyList()

L.add(1)

L.add(2)

L # [1, 2]

__new__()方法接收到的参数依次是:

当前准备创建的类的对象;

类的名字;

类继承的父类集合;

类的方法集合。

当用户定义一个类时,Python解释器首先在当前类的定义中查找metaclass,如果没有找到,就继续在父类中查找metaclass,找到了,就使用父类中定义的metaclass来创建类。即metaclass可以隐式地继承到子类。

错误调试和测试

错误处理

try

try:

print('try...')

r = 10 / int('2')

print('result:', r)

except ValueError as e: # 捕获所有指定类型及其子类型的错误

print('ValueError:',e)

except ZeroDivisionError as e:#可以有多个except子句

print('ZeroDivisionError:' ,e)

else: # 没有错误发生时执行

print('no error!')

finally: # 可以没有finally语句, 如果有,一定会执行

print('finally...')

print('END')

调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。

# err.py:

def foo(s):

return 10 / int(s)

def bar(s):

return foo(s) * 2

def main():

bar('0')

main()

#执行 err.py

$ python3 err.py

Traceback (most recent call last):

File "err.py", line 11, in

main()

File "err.py", line 9, in main

bar('0')

File "err.py", line 6, in bar

return foo(s) * 2

File "err.py", line 3, in foo

return 10 / int(s)

ZeroDivisionError: division by zero

记录错误

把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去

import logging

def foo(s):

return 10 / int(s)

def bar(s):

return foo(s) * 2

def main():

try:

bar('0')

except Exception as e:

logging.exception(e)

main()

print('END')

抛出错误

因为错误是class,捕获一个错误就是捕获到该class的一个实例。

尽量使用Python内置的错误类型,只有在必要的时候才定义我们自己的错误类型。

raise语句如果不带参数,就会把当前错误原样抛出。

raise可以抛出与当前错误类型不同的错误。

# err_raise.py

class FooError(ValueError):

pass

def foo(s):

n = int(s)

if n==0:

raise FooError('invalid value:%s' % s)

return 10 / n

foo('0')

调试

断言

如果断言失败,assert语句本身就会抛出AssertionError

启动Python解释器时可以用-O参数来关闭assert

def foo(s):

n = int(s)

assert n != 0, 'n is zero!'

return 10 / n

def main():

foo('0')

##断言失败

$ python err.py

Traceback (most recent call last):

...

AssertionError: n is zero!

logging

logging,允许指定记录信息的级别, 比如debug,info,warning,error

通过简单的配置,可以输出到不同的地方。

pdb

与gdb使用方式相同, 以 -m pdb启动单步调试。如:python -m pdb err.py

在程序中需要设置断点的地方插入一条语句pdb.set_trace(), 需要导入模块import pdb

IO编程

文件读写

#如果文件不存在,抛出IOError 错误

#读取‘UTF-8’编码的文本文件

f = open('path', 'r')

#读取二进制文件

f = open('path', 'rb')

#读取非UTF-8编码文本文件,传入encoding参数

f = open('gbk.txt','r', encoding='gbk')

#处理编码错误

f = open('gbk.txt', 'r', encoding='gbk', errors='ignore')

#read()一次读取文件全部内容,用str表示

f.read() # 'Hello, world!'

#最多读取指定size个字节内容

f.read(size)

#每次读取一行

f.readline()

#一次读取所有内容,按行返回list

f.readlines()

#写文件,以'w','wb', 'a'模式打开文件

f = open('path', 'w')

#写入指定编码的文本文件,open添加encoding参数。

f.write('Hello, world!')

# 使用完关闭文件

f.close()

#try ... finally 捕获读写错误,关闭文件

try:

f = open('path', 'r')

print(f.read())

finally:

if f:

f.close()

#with 语句自动调用close, 与try ... finally 等效

with open('path', 'r') as f:

print(f.read())

StringIO和BytesIO

StringIO

在内存中读写str

from io import StringIO

#先创建一个StringIO,像文件一样读写

f = StringIO()

f.write('hello') # 5

f.wite(' ') # 1

f.write('world!') # 6

print(f.getvalue())

hello world!

f = StringIO('Hello!\nHi!\nGoodbye!')

while True:

s.f.readline

if s == '':

break

print(s.strip())

BytesIO

在内存中操作二进制数据

from io import BytesIO

f = BytesIO()

f.write('中文'.encode('utf-8')) #6

print(f.getvalue())

b'\xe4\xb8\xad\xe6\x96\x87'

f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')

f.read()

b'\xe4\xb8\xad\xe6\x96\x87'

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值