数字,字符串和变量
Python里的所有数据——布尔值,整数,浮点数,字符串,甚至大型数据结构,函数以及程序都是以对象(object)的形式存在
对象的类型决定了它装着的数据是允许被修改的变量(可变的)还是不可被修改的常量(不可变的)。你可以把不可变对象想象成一个透明但封闭的盒子:你可以看到里面装的数据,但是无法改变它。类似地,可变对象就像一个开着口的盒子, 你不仅可以看到里面的数据,还可以拿出来修改它,但你无法改变这个盒子本身,即你无法改变对象的类型
Python中的变量有一个非常重要的性质:它仅仅是一个名字。赋值操作并不会实际复制值,它只是为数据对象取个相关的名字。名字是对对象的引用而不是对象本身。你可以把名字想象成贴在盒子上的标签
数字
分浮点数除法和整数除法
>>> 7 / 2
3.5
>>> 7 // 2
3
函数divmod()同时得到商和余数(元组形式)
>>> divmod(7,2)
(3, 1)
进制
1. 二进制
0b or 0B
2. 八进制
0o or 0O
3. 十六进制
0x or 0X
int类型可存储任意大小的整数
>>> 10 ** 100
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Python在处理超大数计算方面不会产生任何错误
函数float()可转换任何有效浮点值
>>> float('1.0e4')
10000.0
字符串
可用单引号,双引号,三引号创建字符串(主要用于创建多行字符串)
函数print()会在各个部分之间添加空格
>>> print(1, 'haha', 'hehe')
1 haha hehe
拼接字符串的两种方式
1. 使用+拼接
>>> 'first' + 'second'
'firstsecond'
2. 字符串紧接着放置
>>> 'first' 'second'
'firstsecond'
使用*号复制字符串
>>> 'abc' * 3
'abcabcabc'
使用[ ]提取字符(偏移量不能超过字符串长度)
>>> s = 'abcdefg'
>>> s[0]
'a'
>>> s[2]
'c'
>>> s[-1]
'g'
一些常用字符串函数
>>> s = 'get gloves,get mask, give cat vitamins'
>>> s.split(',')
['get gloves', 'get mask', ' give cat vitamins']
>>> ','.join(s.split(','))
'get gloves,get mask, give cat vitamins'
>>> s.startswith('get')
True
>>> s.endswith('ins')
True
>>> s.find('glo')
4
>>> s.rfind('glo')
4
>>> s.count('g')
4
>>> s.isalnum()
False
>>> s.capitalize()
'Get gloves,get mask, give cat vitamins'
>>> s.title()
'Get Gloves,Get Mask, Give Cat Vitamins'
>>> s.upper()
'GET GLOVES,GET MASK, GIVE CAT VITAMINS'
>>> s.lower()
'get gloves,get mask, give cat vitamins'
>>> s.center(40)
' get gloves,get mask, give cat vitamins '
>>> s.ljust(40)
'get gloves,get mask, give cat vitamins '
>>> s.replace('give', 'get')
'get gloves,get mask, get cat vitamins'
>>> s.replace('g', 'G', 10)
'Get Gloves,Get mask, Give cat vitamins'
列表,元组,字典与集合
列表
使用 [offset]获取与修改元素
>>> ls = ['a', 'b', 'c', 'd']
>>> ls[0]
'a'
>>> ls[-2]
'c'
>>> ls[1] = 'g'
>>> ls
['a', 'g', 'c', 'd']
使用extend()或+=合并列表
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = [7, 8, 9]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]
>>> b += c
>>> b
[4, 5, 6, 7, 8, 9]
使用sort()重新排列元素
- 列表方法sort()会改变原列表内容
- 函数sorted()返回排好序的列表副本
:
>>> ls = [1, 3, 5, 4, 2]
>>> sorted(ls)
[1, 2, 3, 4, 5]
>>> ls
[1, 3, 5, 4, 2]
>>> ls.sort()
>>> ls
[1, 2, 3, 4, 5]
一些常用列表函数
>>> ls = [1, 2, 3, 'a', 'b', 'c']
>>> ls.insert(2, 4)
>>> ls
[1, 2, 4, 3, 'a', 'b', 'c']
>>> del ls[3]
>>> ls
[1, 2, 4, 'a', 'b', 'c']
>>> del ls[-1]
>>> ls
[1, 2, 4, 'a', 'b']
>>> ls.remove('a')
>>> ls
[1, 2, 4, 'b']
>>> ls.pop()
'b'
>>> ls
[1, 2, 4]
>>> ls.pop(2)
4
>>> ls
[1, 2]
>>> ls.index(2)
1
>>> ls.count(1)
1
元组
创建只含一个元素的元组时,元素后需加逗号,元素数大于1时最后元素后面的逗号可省略
>>> t = ('a',)
>>> type(t)
<class 'tuple'>
>>> t2 = ('a')
>>> type(t2)
<class 'str'>
>>> t3 = 'a',
>>> type(t3)
<class 'tuple'>
>>> t4 = 'a', 'b'
>>> type(t4)
<class 'tuple'>
元组解包以及多变量互换
>>> t = (1, 2, 3)
>>> x, y, z = t
>>> x
1
>>> y
2
>>> z
3
>>> v = 'a'
>>> v2 = 'b'
>>> v, v2 = v2, v
>>> v
'b'
>>> v2
'a'
字典
Python3.6字典默认有序(以后的版本不保证有序)
>>> d = {'a' : 'b', 'c' : 'd', 'e' : 'f'}
>>> for i in d:
... print(i)
...
a
c
e
>>> for i in d:
... print(i)
...
a
c
e
>>> for i in d:
... print(i)
...
a
c
e
使用dict()将包含双值子序列的序列转换成字典
>>> ls = [['a', 'b'], ['c', 'd']]
>>> dict(ls)
{'a': 'b', 'c': 'd'}
>>> t = ('ab', 'cd')
>>> dict(t)
{'a': 'b', 'c': 'd'}
使用update()合并字典(若重复,新值取代旧值)
>>> d = {1:2, 3:4}
>>> d2 = {1:5, 6:7}
>>> d.update(d2)
>>> d
{1: 5, 3: 4, 6: 7}
使用del与clear()删除元素
>>> d = {'a':'b', 'c':'d', 'e':'f'}
>>> del d['a']
>>> d
{'c': 'd', 'e': 'f'}
>>> d.clear()
>>> d
{}
集合
使用{ }创建集合
>>> s = {1, 2, 3, 4}
>>> type(s)
<class 'set'>
将字符串转换为集合
>>> set(str)
{'e', 'a', 'c', 'd', 'b'}
常用集合运算
>>> a = {1, 2}
>>> b = {2, 3}
>>> a & b
{2}
>>> a | b
{1, 2, 3}
>>> a - b
{1}
>>> b - a
{3}
>>> a ^ b
{1, 3}
>>> a <= b
False
>>> a <= a
True
>>> a < b
False
>>> a < a
False
代码结构
风格和规范
使用 \ 连接代码
>>> 1 + 2 +
File "<stdin>", line 1
1 + 2 +
^
SyntaxError: invalid syntax
>>> 1 + 2 + \
... 3
6
连续比较
>>> x = 7
>>> 6 < x < 10 < 999
True
>>> 6 < x > 3
True
假值表
类型 | 值 |
---|---|
布尔 | False |
null类型 | None |
整形 | 0 |
浮点型 | 0.0 |
空字符串 | ’ ‘ |
空列表 | [ ] |
空元组 | ( ) |
空字典 | { } |
空集合 | set( ) |
循环外的else(当没有使用break跳出循环时执行)
>>> n = [1, 2, 3]
>>> for i in n:
... if i > 3:
... break
... else:
... print('hello')
...
hello
>>> for i in n:
... if i > 2:
... break
... else:
... print('hello')
...
>>>
使用zip()并行迭代(在最短序列处停止)
>>> a = [1, 2, 3]
>>> b = (5, 6, 7, 8, 9, 10)
>>> x = zip(a, b)
>>> type(x)
<class 'zip'>
>>> for i in x:
... print(i)
...
(1, 5)
(2, 6)
(3, 7)
像切片一样使用range()
>>> list(range(0, 3))
[0, 1, 2]
>>> list(range(10, -1, -1))
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> list(range(0, 11, 2))
[0, 2, 4, 6, 8, 10]
推导式
列表推导式
>>> a = [num for num in range(1, 11)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = [num for num in range(1, 11) if num % 2 == 0]
>>> a
[2, 4, 6, 8, 10]
>>> a = [(x, y) for x in range(3) for y in range(3)]
>>> a
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
字典推导式
>>> word = 'letters'
>>> d = {letter: word.count(letter) for letter in set(word)}
>>> d
{'e': 2, 'l': 1, 't': 2, 's': 1, 'r': 1}
集合推导式(类似列表推导式)
>>> a = {num for num in range(4)}
>>> a
{0, 1, 2, 3}
>>> type(a)
<class 'set'>
生成器推导式(可直接进行迭代,但只能使用一次)
>>> a = (num for num in range(4))
>>> type(a)
<class 'generator'>
>>> list(a)
[0, 1, 2, 3]
>>> list(a)
[]
函数
函数参数是以元组形式进行传递
函数参数
位置参数(必须记住每个位置的参数的含义)
>>> def test(x, y, z):
... print('x = %d y = %d z = %d' % (x, y, z))
...
>>> test(1, 2, 3)
x = 1 y = 2 z = 3
关键字参数(调用函数时直接指定参数名字,可调参数顺序)
>>> test(x = 3, z = 1, y = 2)
x = 3 y = 2 z = 1
默认参数
默认参数的右边不能有非默认参数,默认参数值在函数被定义时已经计算出来,而不是在程序运行时,所以不要把可变数据类型当作默认参数值
>>> def test(x, y, z = 3):
... print('x = %d y = %d z = %d' % (x, y, z))
...
>>> test(1, 2)
x = 1 y = 2 z = 3
>>> test(1, 2, 4)
x = 1 y = 2 z = 4
>>> def test(x, y = 2, z):
... print('x = %d y = %d z = %d' % (x, y, z))
...
File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
使用 * 收集位置参数(主要用于接收可变数量的参数)
>>> def test(*args):
... print('Positional argument tuple:', args)
...
>>> test(1, 2, 3)
Positional argument tuple: (1, 2, 3)
>>> test('a', 'b', 'c', 'd', 'e')
Positional argument tuple: ('a', 'b', 'c', 'd', 'e')
使用 ** 收集关键字参数
>>> def test(**kwargs):
... print('Keyword arguments:', kwargs)
...
>>> test(x = 1, y = 2, z = 3)
Keyword arguments: {'x': 1, 'y': 2, 'z': 3}
>>> test(x = 'a', z = 'b', y = 'c')
Keyword arguments: {'x': 'a', 'z': 'b', 'y': 'c'}
如果混合使用 * 与 ** 那么参数必须按照顺序出现
>>> def test(*args, **kwargs):
... print('P: ', args)
... print('K: ', kwargs)
...
>>> test(1, 2, 3, x = 4, y = 5)
P: (1, 2, 3)
K: {'x': 4, 'y': 5}
>>> test(1, x = 2, 3)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
文档字符串
相当于函数注释,可使用help()或print()显示文档字符串
>>> def test(anything):
... 'This is a func'
... return anything
...
>>> def test2(allthing):
... '''
... This is a func2
... '''
... return allthing
...
>>> help(test)
Help on function test in module __main__:
test(anything)
This is a func
>>> print(test2.__doc__)
This is a func2
>>>
函数类型
内部函数
>>> def outer(a, b):
... def inner(c, d):
... return c + d
... return inner(a, b)
...
>>> outer(4, 7)
11
闭包
>>> def test(saying):
... def inner():
... return 'You said : %s' % saying
... return inner
...
>>> a = test('haha')
>>> type(a)
<class 'function'>
>>> a()
'You said : haha'
匿名函数( 冒号前为参数,后为返回值)
>>> def test(ls, func):
... for i in ls:
... print(func(i))
...
>>> a = [1, 2, 3]
>>> test(a, lambda item: item * item)
1
4
9
内部函数与闭包用法比较
- 内部函数创建后被调用,闭包则直接返回创建的新函数
- 内部函数一般不直接使用外部变量,闭包则直接使用
生成器
生成器是用来创建Python 序列的一个对象。使用它可以迭代庞大的序列,且不需要在内
存中创建和存储整个序列
>>> def one2ten():
... i = 1
... while i < 11:
... yield i
... i += 1
...
>>> g = one2ten()
>>> for i in g:
... print(i)
...
1
2
3
4
5
6
7
8
9
10
装饰器
主要用于在不修改函数源代码的情况下修改函数
装饰器实际上是一个函数,接受一个函数作为参数返回另一个函数,使用的主要技巧:
- *args **kwargs
- 闭包
- 作为参数的函数
单装饰器
>>> def docu(func):
... def new_func(*args, **kwargs):
... print('start :', func.__name__)
... result = func(*args, **kwargs)
... print('end :', func.__name__)
... return result
... return new_func
...
>>> def test(a, b):
... return a + b
...
>>> a = docu(test)
>>> a(1, 2)
start : test
end : test
3
>>> @docu
... def test2(c, d):
... return c + d
...
>>> test2(1, 2)
start : test2
end : test2
3
多装饰器(靠近函数的先执行)
>>> def square(func):
... def new_func(*args, **kwargs):
... result = func(*args, **kwargs)
... result *= result
... print('square result: ', result)
... return result
... return new_func
...
>>>
>>> @docu
... @square
... def test3(x, y):
... return x + y
...
>>> test3(1, 2)
start : new_func
square result: 9
end : new_func
9
>>>
>>> @square
... @docu
... def test4(x, y):
... return x + y
...
>>> test4(1, 1)
start : test4
end : test4
square result: 4
4
命名空间和作用域
函数内如果先引用全局变量再修改则会报错,反过来先修改再引用则不会(后者实际是声明了同名的局部变量)
>>> def test():
... print('animal: ', animal)
...
>>> test()
animal: cat
>>> def test2():
... print('in test2 animal: ', animal)
... animal = 'dog'
...
>>> test2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in test2
UnboundLocalError: local variable 'animal' referenced before assignment
使用global读取全局变量
>>> animal = 'cat'
>>> def test():
... global animal
... animal = 'dog'
... print('animal: ', animal)
...
>>> test()
animal: dog
>>> animal
'dog'
Python 提供了两个获取命名空间内容的函数
- locals() 返回一个局部命名空间内容的字典
- globals() 返回一个全局命名空间内容的字典
:
>>> animal = 'cat'
>>> def test():
... animal = 'dog'
... print('local: ', locals())
...
>>> test()
local: {'animal': 'dog'}
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'animal': 'cat', 'test': <function test at 0x02BDD588>, 'test2': <function test2 at 0x04F94B70>}
以两个下划线__ 开头和结束的名称都是Python 的保留用法
>>> def test():
... 'document'
... print('test func')
...
>>> test.__name__
'test'
>>> test.__doc__
'document'
异常
捕获所有异常
>>> ls = [1, 2, 3]
>>> try:
... ls[6]
... except:
... print('error')
...
error
捕获特定异常
>>> ls = [1, 2, 3]
>>> try:
... ls[6]
... except IndexError as err:
... print(err)
...
list index out of range
编写自己的异常
>>> class CosError(Exception):
... pass
...
>>> ls = ['haha', 'cos', 'hehe']
>>> for i in ls:
... if i == 'cos':
... raise CosError(i)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
__main__.CosError: cos
模块、包和程序
命令行参数
import sys
print('Argument: ', sys.argv)
---
python test.py
Argument: ['test.py']
---
python test.py 1 2 a b
Argument: ['test.py', '1', '2', 'a', 'b']
模块和import语句
直接导入
import random
别名导入
import random as rd
全局导入(全局可见)
import random
xxx
xxx
xxx
局部导入(局部可见)
ls = [1, 2, 3]
def test():
import random
xxx
xxx
部分导入
>>> from random import choice as ch
>>> ls = [1, 2, 3]
>>> ch(ls)
2
模块搜索路径
Python 会在什么地方寻找文件来导入模块?使用命名为path 变量的存储在标准sys 模块
下的一系列目录名和ZIP 压缩文件
第一个匹配到的模块会先被使用,这也就意味着如果你在标准库之前的搜索路径上定义一
个模块random,就不会导入标准库中的random 模块
>>> import sys
>>> for p in sys.path:
... print(p)
...
C:\Users\xxxxx\AppData\Local\Programs\Python\Python36-32\python36.zip
C:\Users\xxxxx\AppData\Local\Programs\Python\Python36-32\DLLs
C:\Users\xxxxx\AppData\Local\Programs\Python\Python36-32\lib
C:\Users\xxxxx\AppData\Local\Programs\Python\Python36-32
C:\Users\xxxxx\AppData\Local\Programs\Python\Python36-32\lib\site-packages
Python标准库
处理字典缺失的键
函数setdefault (键不存在时在字典中添加一项)
>>> d = {'a' : 1, 'b': 2}
>>> t = d.setdefault('c', 3)
>>> t
3
>>> t = d.setdefault('c', 4)
>>> t
3
函数defaultdict (创建字典时为每个键指定默认值,参数为函数用于设置默认值)
>>> from collections import defaultdict
>>> d = defaultdict(int)
>>> d['a']
0
>>> d['b']
0
>>> d
defaultdict(<class 'int'>, {'a': 0, 'b': 0})
>>> def fl():
... return 2.0
...
>>> d2 = defaultdict(fl)
>>> d2['a']
2.0
使用Counter计数
交集取两者中较小值,并集取两者中较大值
>>> from collections import Counter
>>> ls = ['a', 'a', 'b', 'a']
>>> ls2 = ['b', 'b', 'd']
>>> ls_counter = Counter(ls)
>>> ls_counter
Counter({'a': 3, 'b': 1})
>>> ls_counter.most_common()
[('a', 3), ('b', 1)]
>>> ls_counter.most_common(1)
[('a', 3)]
>>> ls2_counter = Counter(ls2)
>>> ls_counter + ls2_counter
Counter({'a': 3, 'b': 3, 'd': 1})
>>> ls_counter - ls2_counter
Counter({'a': 3})
>>> ls2_counter - ls_counter
Counter({'b': 1, 'd': 1})
>>> ls_counter & ls2_counter
Counter({'b': 1})
>>> ls_counter | ls2_counter
Counter({'a': 3, 'b': 2, 'd': 1})
双端队列:栈+队列
deque 是一种双端队列,同时具有栈和队列的特征。它可以从序列的任何一端添加和删除
项
>>> from collections import deque
>>> s = 'abcdcba'
>>> dq = deque(s)
>>> while len(dq) > 1:
... if dq.popleft() != dq.pop():
... break
... else:
... print('ok')
...
ok
使用itertools迭代代码结构
串联多个可迭代对象
>>> import itertools
>>> for i in itertools.chain(['a', 'b'], [1, 2]):
... print(i)
...
a
b
1
2
可迭代对象循环
>>> import itertools
>>> for i in itertools.cycle([1, 2, 3]):
... print(i)
...
1
2
3
1
...
计算累积值(accumulate接收函数参数,该函数必须接收两个参数并返回单个值)
>>> import itertools
>>> for i in itertools.accumulate([1, 2, 3]):
... print(i)
...
1
3
6
>>> def mul(x, y):
... return x * y
...
>>> for i in itertools.accumulate([1, 2, 3], mul):
... print(i)
...
1
2
6
:
对象和类
继承和覆盖
子类可继承父类所有方法(包括__init__ 方法),也可以覆盖父类的任何方法
继承
>>> class test():
... def __init__(self, name):
... self.name = name
...
>>> class test2(test):
... pass
...
>>> a = test2('haha')
>>> a.name
'haha'
覆盖(同名即为覆盖,没有重载的概念)
>>> class t():
... def say(self, name):
... print(name)
...
>>> class t2(t):
... def say(self, name, word):
... print(name, word)
...
>>> a = t2()
>>> a.say('haha', 'hehe')
haha hehe
>>> a.te('haha')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: say() missing 1 required positional argument: 'word'
使用super从父类得到帮助
当父类方法被覆盖而又需要调用父类方法时使用super
>>> class test():
... def __init__(self, name):
... self.name = name
...
>>> class test2(test):
... def __init__(self, name, email):
... super().__init__(name)
... self.email =email
...
>>> a = test2('haha', '123@.com')
>>> a.name
'haha'
>>> a.email
'123@.com'
使用super的实际过程
- 获取父类定义
- 自动将子类对象作为参数传递给父类被调用函数
- 传入被调用函数所需其余参数
- 执行被调用函数
继承时,应该让类完成自己应该完成的事。所以以上代码并没有写成如下形式
>>> class test2(test):
... def __init__(self, name, email):
... self.name = name
... self.email =email
self的自辩
Python 使用self 参数来找到正确的对象所包含的特性和方法
>>> class test():
... def say(self):
... print('haha')
...
>>> a = test()
>>> a.say()
haha
>>> test.say(a)
haha
调用类的实例方法的实际过程
- 寻找类对象所属类的定义
- 把对象作为self参数传给所属类的被调用方法
使用属性对特性进行访问和设置
Python里所有特性(attribute)都是公开的
使用property(属性)设置特性
>>> class test():
... def __init__(self, name):
... self.hide_name = name
... def get_name(self):
... print('inside the getter')
... return self.hide_name
... def set_name(self, name):
... print('inside the setter')
... self.hide_name = name
... name = property(get_name, set_name)
...
>>> a = test('haha')
>>> a.name
inside the getter
'haha'
>>> a.name = 'hehe'
inside the setter
>>> a.name
inside the getter
'hehe'
使用修饰符@设置特性(@property相当于getter)
>>> class test():
... def __init__(self, name):
... self.hide_name = name
... @property
... def name(self):
... print('inside the getter')
... return self.hide_name
... @name.setter
... def name(self, name):
... print('inside the setter')
... self.hide_name = name
...
>>> a = test('haha')
>>> a.name
inside the getter
'haha'
>>> a.name = 'hehe'
inside the setter
>>> a.name
inside the getter
'hehe'
可以只设置getter使得特性无法被修改(不过不建议只设置setter)
>>> class test():
... def __init__(self, name):
... self.hide_name = name
... def getter(self):
... return self.hide_name
... name = property(getter)
...
>>> a = test('haha')
>>> a.name
'haha'
>>> a.name = 'hehe'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>> class test():
... def __init__(self, name):
... self.hide_name = name
... @property
... def name(self):
... return self.hide_name
...
>>> a = test('hehe')
>>> a.name
'hehe'
>>> a.name = 'haha'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
使用名称重整保护私有特性
Python对那些需要刻意隐藏在类内部的特性有自己的命名规范:由连续的两个下划线开头(__)
只设置属性类外部仍能通过特性名直接访问特性,为防止这种情况以双下划线开头命名特性
>>> class test():
... def __init__(self, name):
... self.__name = name
... @property
... def name(self):
... return self.__name
... @name.setter
... def name(self, name):
... self.__name = name
...
>>> a = test('haha')
>>> a.name
'haha'
>>> a.name = 'hehe'
>>> a.name
'hehe'
>>> a.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'test' object has no attribute '__name'
名称重整实际上并没有把变量变成私有,但确实让外部代码无法使用
>>> a._test__name
'hehe'
方法的类型
实例方法
以self 作为第一个参数的方法都是实例方法(instance method)。实例方法的首个参数是self,当它被调用时,Python 会把调用该方法的对象作为self 参数传入
类方法
以@classmethod修饰,与实例方法类似,第一个参数cls为类本身
>>> class test():
... count = 0
... def __init__(self):
... test.count += 1
... @classmethod
... def kids(cls):
... print('Test has', cls.count, 'kids')
...
>>> a = test()
>>> b = test()
>>> c = test()
>>> test.kids()
Test has 3 kids
静态方法
以@staticmethod修饰,不需要self和cls作为参数,可通过实例调用或类名直接调用,可调用类特性不能调用实例特性
>>> class test():
... count = 0
... def __init__(self, name):
... test.count += 1
... self.name = name
... @staticmethod
... def say():
... print(test.count)
... print(self.name)
...
>>> a = test('haha')
>>> b = test('hehe')
>>> test.say()
2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in say
NameError: name 'self' is not defined
>>> a.say()
2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in say
NameError: name 'self' is not defined
鸭子类型
如果它像鸭子一样走路,像鸭子一样叫,那么它就是一只鸭子
Python多态的形式,我们可以对不同对象调用同名操作(只要它具有这种操作)而不必管对象的类型是什么
>>> class man():
... def say(self):
... print('I am man')
...
>>> class tiger():
... def say(self):
... print('I am tiger')
...
>>> def what(obj):
... obj.say()
...
>>> m = man()
>>> t = tiger()
>>> what(m)
I am man
>>> what(t)
I am tiger
魔术方法
魔术方法名称以双下划线开头和结束
>>> class word():
... def __init__(self, text):
... self.text = text
... def __eq__(self, other):
... return self.text == other.text
...
>>> a = word('haha')
>>> b = word('haha')
>>> c = word('hehe')
>>> a == b
True
>>> a == c
False
常用魔术方法
方法名 | 使用 |
---|---|
__eq__(self, other) | self == other |
__ne__(self, other) | self != other |
__lt__(self, other) | self < other |
__gt__(self, other) | self > other |
__le__(self, other) | self <= other |
__ge__(self, other) | self >= other |
__add__(self, other) | self + other |
__sub__(self, other) | self - other |
__mul__(self, other) | self * other |
__floordiv__(self, other) | self // other |
__truediv__(self, other) | self / other |
__mod__(self, other) | self % other |
__pow__(self, other) | self ** other |
何时使用类和对象而不是模块
来自创始人——Guido van Rossum的建议:
不要过度构建数据结构。尽量使用元组(以及命名元组)而不是对象。尽量使用
简单的属性域而不是getter/setter 函数……内置数据类型是你最好的朋友。尽可
能多地使用数字、字符串、元组、列表、集合以及字典。多看看容器库提供的类
型,尤其是双端队列。
命名元组
命名元组是元组的子类,你既可以通过名称(使用.name)来访问其中的值,也可以通过
位置进行访问(使用[offset])。
创建命名元组
>>> from collections import namedtuple
>>> a = namedtuple('t_name', 'one two')
>>> b = a('hi', 'hello')
>>> b
t_name(one='hi', two='hello')
>>> d = {'one': 1, 'two': 2}
>>> a2 = a(**d)
>>> a2
t_name(one=1, two=2)
命名元组不可更改,但可替换某些值后返回新的元组
>>> a3 = a2._replace(one = 'haha', two = 'hehe')
>>> a3
t_name(one='haha', two='hehe')
像高手一样玩转数据
Unicode
根据名称返回字符与根据字符返回名称(如果使用的字体无该符号则以占位符形式出现)
>>> import unicodedata
>>> unicodedata.name('A')
'LATIN CAPITAL LETTER A'
>>> unicodedata.lookup('LATIN CAPITAL LETTER A')
'A'
为了方便查阅,Unicode 字符名称索引页列出的字符名称是经过修改的,因此与由name() 函数得到的名称有所不同。如果需要将它们转化为真实的Unicode 名称(Python 使用的),只需将逗号舍去,并将逗号后面的内容移到最前面即可。据此,我们应将E WITH ACUTE, LATIN SMALL LETTER 改为LATINSMALL LETTER E WITH ACUTE:
字符串中直接使用Unicode字符
>>> a = '\N{LATIN SMALL LETTER U WITH DIAERESIS}'
>>> a
'ü'
UTF-8 动态编码方案
- 为ASCII 字符分配1 字节
- 为拉丁语系(除西里尔语)的语言分配2 字节
- 为其他的位于基本多语言平面的字符分配3 字节
- 为剩下的字符集分配4 字节,这包括一些亚洲语言及符号
len()中Unicode编码返回字符个数,其他编码返回字节数
>>> a = '\u2603'
>>> len(a)
1
>>> b = a.encode('utf-8')
>>> len(b)
3
格式化
旧式格式化
符号 | 含义 |
---|---|
%s | 字符串 |
%d | 十进制 |
%x | 十六进制 |
%o | 八进制 |
%f | 十进制浮点数 |
%e | 科学记数法浮点数 |
%g | 十进制或科学记数法表示的浮点数 |
%% | %本身 |
旧式常见格式化
>>> a = 42
>>> b = 1.23
>>> c = 'string'
>>> '%d %f %s' % (a, b, c)
'42 1.230000 string'
>>> '%10d %10f %10s' % (a, b, c)
' 42 1.230000 string'
>>> '%-10d %-10f %-10s' % (a, b, c)
'42 1.230000 string '
>>> '%10.4d %10.4f %10.4s' % (a, b, c)
' 0042 1.2300 stri'
>>> '%.4d %.4f %.4s' % (a, b, c)
'0042 1.2300 stri'
>>> '%*.*d %*.*f %*.*s' % (10, 4, a, 10, 4, b, 10, 4, c)
' 0042 1.2300 stri'
新式常见格式化(无法对整数设置精度)
>>> '{} {} {}'.format(a, b, c)
'42 1.23 string'
>>> '{2} {0} {1}'.format(a, b, c)
'string 42 1.23'
>>> '{a} {b} {c}'.format(a = 42, b = 1.23, c = 'string')
'42 1.23 string'
>>> '{0:d} {1:f} {2:s}'.format(a, b, c)
'42 1.230000 string'
>>> '{a:d} {b:f} {c:s}'.format(a = 42, b = 1.23, c = 'string')
'42 1.230000 string'
>>> '{0:10d} {1:10f} {2:10s}'.format(a, b, c)
' 42 1.230000 string '
>>> '{0:>10d} {1:>10f} {2:>10s}'.format(a, b, c)
' 42 1.230000 string'
>>> '{0:^10d} {1:^10f} {2:^10s}'.format(a, b, c)
' 42 1.230000 string '
>>> '{0:^10d} {1:^10.1f} {2:^10.5s}'.format(a, b, c)
' 42 1.2 strin '
>>> '{0:^10.3d} {1:^10.1f} {2:^10.5s}'.format(a, b, c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Precision not allowed in integer format specifier