Python基础回顾

数字,字符串和变量

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()重新排列元素

  1. 列表方法sort()会改变原列表内容
  2. 函数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

内部函数与闭包用法比较

  1. 内部函数创建后被调用,闭包则直接返回创建的新函数
  2. 内部函数一般不直接使用外部变量,闭包则直接使用
生成器

生成器是用来创建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
装饰器

主要用于在不修改函数源代码的情况下修改函数
装饰器实际上是一个函数,接受一个函数作为参数返回另一个函数,使用的主要技巧:

  1. *args **kwargs
  2. 闭包
  3. 作为参数的函数

单装饰器

>>> 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 提供了两个获取命名空间内容的函数

  1. locals() 返回一个局部命名空间内容的字典
  2. 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的实际过程

  1. 获取父类定义
  2. 自动将子类对象作为参数传递给父类被调用函数
  3. 传入被调用函数所需其余参数
  4. 执行被调用函数

继承时,应该让类完成自己应该完成的事。所以以上代码并没有写成如下形式

 >>> 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

调用类的实例方法的实际过程

  1. 寻找类对象所属类的定义
  2. 把对象作为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 动态编码方案

  1. 为ASCII 字符分配1 字节
  2. 为拉丁语系(除西里尔语)的语言分配2 字节
  3. 为其他的位于基本多语言平面的字符分配3 字节
  4. 为剩下的字符集分配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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值