文章目录
字符串方法
-
find
- 可以指定搜索的起点和重点
- 指定的范围包括起点,但不包括终点
-
join
-
>>> seq = [1, 2, 3, 4, 5] >>> sep = '+' >>> sep.join(seq) # 尝试合并一个数字列表Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: sequence item 0: expected string, int found >>> seq = ['1', '2', '3', '4', '5'] >>> sep.join(seq) # 合并一个字符串列'1+2+3+4+5' >>> dirs = '', 'usr', 'bin', 'env' >>> '/'.join(dirs) '/usr/bin/env' >>> print('C:' + '\\'.join(dirs)) C:\usr\bin\env
-
所合并序列都必须是字符串
-
-
lower
返回小写版本
-
replace
>>> 'This is a test'.replace('is', 'eez') 'Theez eez a test'
-
split
>>> '1+2+3+4+5'.split('+') ['1', '2', '3', '4', '5'] >>> '/usr/bin/env'.split('/') ['', 'usr', 'bin', 'env'] >>> 'Using the default'.split() ['Using', 'the', 'default']
注意,如果没有指定分隔符,将默认在单个或多个连续的空白字符(空格、制表符、换行符等)处进行拆分
-
strip
去除开头和结尾的空白,但不包括中间的
-
translate
方法translate与replace一样替换字符串的特定部分,但不同的是它只能进行单字符替换。这个方法的优势在于能够同时替换多个字符,因此效率比replace高
-
判断字符串是否满足某些条件
isalnum、isalpha、isdecimal、isdigit、isidentifier、islower、isnumeric、isprintable、isspace、istitle、isupper
字典
字典是python中唯一的内置映射类型
-
创建字典
phonebook = {'Alice':'2341','Beth':'9102','Ceil':'3258'}
-
函数dict
>>> items = [('name', 'Gumby'), ('age', 42)] >>> d = dict(items) >>> d {'age': 42, 'name': 'Gumby'} >>> d['name'] 'Gumby'
还可使用关键字实参来调用这个函数,如下所示
>>> d = dict(name='Gumby', age=42) >>> d {'age': 42, 'name': 'Gumby'}
-
基本的字典操作
-
len(d)
返回包含的键值对数
-
d[k]
返回与键k相关联的值
-
d[k] = v
将值v关联到键k
-
del d[k]
删除键为k的项
-
k in d
检查字典d是否包含键为k的项
-
-
键的类型
字典中的键可以是整数,但并非必须是整数。字典中的键可以是任何不可变
的类型,如浮点数(实数)、字符串或元组
-
自动添加
-
即便是字典中原本没有的键,也可以给它赋值,这将在字典中创建一个新项。
-
然而,如果不使用append或其他类似的方法,就不能给列表中没有的元素赋值
-
-
成员资格
表达式k in d(其中d是一个字典)查找的是键而不是值
表达式v in l(其中l是一个列表)查找的是值而不是索引
这看似不太一致,但你习惯后就会觉得相当自然。毕竟如果字典包含指定的
键,检查相应的值就很容易
字典的内置方法
-
clear
删除所有的字典项
-
copy
copy为浅复制,即修改复制后的会影响原来的
可以使用copy中的函数deepcopy进行深复制
>>> from copy import deepcopy >>> d = {} >>> d['names'] = ['Alfred', 'Bertrand'] >>> c = d.copy() >>> dc = deepcopy(d)
-
fromkeys
>>> dict.fromkeys(['name', 'age']) {'age': None, 'name': None
如果你不想使用默认值None,可提供特定的值
>>> dict.fromkeys(['name', 'age'], '(unknown)') {'age': '(unknown)', 'name': '(unknown)
-
get
方法get为访问字典项提供了宽松的环境。通常,如果你试图访问字典中没有的项,将引发错误
>>> d = {} >>> print(d['name']) Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: 'name'
而使用get不会这样
>>> print(d.get('name')) None >>> d.get('name', 'N/A') 'N/A'
-
items
方法items返回一个包含所有字典项的列表,其中每个元素都为(key, value)
的形式。字典项在列表中的排列顺序不确定
-
keys
返回一个字典视图,其中包含指定字典中的键
-
pop
方法pop可用于获取与指定键相关联的值,并将该键值对从字典中删除
-
popitem
方法popitem类似于list.pop,但list.pop弹出列表中的最后一个元素,而
popitem随机地弹出一个字典项,因为字典项的顺序是不确定的,没有“最后
一个元素”的概念。
如果你要以高效地方式逐个删除并处理所有字典项,这可能很有用,因为这样
无需先获取键列表
-
setdefault
方法setdefault有点像get,因为它也获取与指定键相关联的值,但除此之
外,setdefault还在字典不包含指定的键时,在字典中添加指定的键值对
-
dic = {"one":1,"two":2} dic.setdefault("three",3)
-
返回值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6u300esP-1635823411541)(https://i.loli.net/2021/04/08/mi1VNnEbUMuGPAg.png)]
-
-
update
方法update使用一个字典中的项来更新另一个字典
-
values
方法values返回一个由字典中的值组成的字典视图。不同于方法keys,方法
values返回的视图可能包含重复的值
条件、循环及其他语句
-
打印多个参数
你可同时打印多个表达式,条件是用逗号分隔它们:
>>> print('Age:', 42) Age: 42
如你所见,在参数之间插入了一个空格字符。在你要合并文本和变量
值,而又不想使用字符串格式设置功能时,这种行为很有帮助
>>> name = 'Gumby' >>> salutation = 'Mr.' >>> greeting = 'Hello,' >>> print(greeting, salutation, name) Hello, Mr. Gumby
如果字符串变量greeting不包含逗号,如何在结果中添加呢?你不能
像下面这样做
print(greeting, ',', salutation, name)
因为这将在逗号前添加一个空格。下面是一种可行的解决方案
print(greeting + ',', salutation, name)
它将逗号和变量greeting相加。如果需要,可自定义分隔符
>>> print("I", "wish", "to", "register", "a", "complaint", sep="_") I_wish_to_register_a_complaint
你还可自定义结束字符串,以替换默认的换行符。例如,如果将结束
字符串指定为空字符串,以后就可继续打印到当前行
print('Hello,', end='') print('world!')
上述代码打印Hello, world!
赋值魔法
-
序列解包
这在使用返回元组(或其他序列或可迭代对象)的函数或方法时很有用。假设要从字典中随便获取(或删除)一个键值对,可使用方法popitem,它随便获取一个键值对并以元组的方式返回。接下来,可直接将返回的元组解包到两个变量中
>>> scoundrel = {'name': 'Robin', 'girlfriend': 'Marion'} >>> key, value = scoundrel.popitem() >>> key 'girlfriend' >>> value 'Marion'
可使用星号运算符(*)来收集多余的值,这样无需确保值和变量的个数相同,如下例所示
>>> a, b, *rest = [1, 2, 3, 4] >>> rest [3, 4]
还可将带星号的变量放在其他位置
>>> name = "Albus Percival Wulfric Brian Dumbledore" >>> first, *middle, last = name.split() >>> middle ['Percival', 'Wulfric', 'Brian']
赋值语句的右边可以是任何类型的序列,但带星号的变量最终包含的
总是一个列表。在变量和值的个数相同时亦如此
>>> a, *b, c = "abc" >>> a, b, c ('a', ['b'], 'c')
代码块
在Python中,使用冒号(:)指出接下来是一个代码块,并将该代码块中
的每行代码都缩进相同的程度
-
条件和条件语句
用作布尔表达式(如用作if语句中的条件)时,下面的值都将被解释器视为假:
False None 0 “” () [] {}
换而言之,标准值False和None、各种类型(包括浮点数、复数等)的数值0、空序列(如空字符串、空元组和空列表)以及空映射(如空字典)都被视为假,而其他各种值都被视为真,包括特殊值True
。
- 实际上,True和False不过是0和1的别名,虽然看起来不同,但作用是相同的。
>>> True True >>> False False >>> True == 1 True >>> False == 0 True >>> True + False + 42 43
- else语句
name = input('What is your name?') if name.endswith('Gumby'): print('Hello, Mr. Gumby') else: print('Hello, stranger')
- elif子句
-
比较运算符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Y1aSLqm-1635823411543)(https://i.loli.net/2021/04/08/YjOxFE2tCoUNHpr.png)]
-
顺序值和符号
要获悉字母的顺序值,可使用函数ord。这个函数的作用与函数chr
相反
>>> ord("") 128585 >>> ord("") 128586 >>> chr(128584) ''
-
and、or、not
断言
>>> age = 10
>>> assert 0 < age < 100
>>> age = -1
>>> assert 0 < age < 100
Traceback (most recent call last): File "<stdin>", line 1, in ? AssertionError
可在条件后面加上一个字符串,对断言做出说明
>>> age = -1
>>> assert 0 < age < 100, 'The age must be realistic' Traceback (most recent call last): File "<stdin>", line 1, in ? AssertionError: The age must be realistic
循环
-
while循环
-
for循环
-
迭代字典
for key, value in d.items(): print(key, 'corresponds to', value)
-
并行迭代
简单推导
>>> [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [x*x for x in range(10) if x % 3 == 0]
[0, 9, 36, 81]
>>> [(x, y) for x in range(3) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
好像if只能有一个
三人行
-
pass
python中代码块不能为空,此时就能用pass来解决
if name == 'Ralph Auldus Melish': print('Welcome!') elif name == 'Enid': # 还未完成...... pass elif name == 'Bill Gates': print('Access Denied')
-
del
垃圾收集
>>> scoundrel = {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'} >>> robin = scoundrel >>> scoundrel {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'} >>> robin {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'} >>> scoundrel = None >>> robin {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'} >>> robin = None
- 最初,robin和scoundrel指向同一个字典,因此将None赋给scoundrel后,依然可以通过robin来访问这个字典。但robin也设置为None之后,这个字典就漂浮在计算机内存中,没有任何名称与之相关联,再也无法获取或使用它了。因此,智慧无穷的Python解释器直接将其删除。这被称为垃圾收集。请注意,在前面的代码中,也可将其他任何值(而不是None)赋给两个变量,这样字典也将消失
- 另一种办法是使用del语句。(第2章和第4章使用这条语句来删除序列和字典,还记得吗?)这不仅会删除到对象的引用,还会删除名称本身
-
使用exec和eval执行字符串及计算机其结果
exec eval 最好提供命名空间
函数
- 定义
def hello(name): return 'hello,'+name+'!'
-
如果参数不可变
在有些语言(如C++、Pascal和Ada)中,经常需要给参数
赋值并让这种修改影响函数外部的变量。
在Python中,没法直接这样做,只能修改参数对象本身。
如果参数是不可变的(如数)呢?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HTMzW02L-1635823411545)(https://i.loli.net/2021/04/08/puzCc1y6Um8EVLP.png)]
-
函数参数的顺序
>>> hello_1(greeting='Hello', name='world') Hello, world!
像这样使用名称指定的参数称为关键字参数,主要优点是有
助于澄清各个参数的作用。
-
关键字参数可以指定参数的默认值
def hello_3(greeting='Hello', name='world'): print('{}, {}!'.format(greeting, name)
>>> hello_3() Hello, world! >>> hello_3('Greetings') Greetings, world! >>> hello_3('Greetings', 'universe') Greetings, universe
参数收集
def print_params(*params):
print(params)
>>> print_params('Testing')
('Testing',)
参数前面的星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。
这样的行为我们在5.2.1节见过:赋值时带星号的变量收集多余的值。它收集的是列表而不是元组中多余的值,但除此之外,这两种用法很像
与赋值时一样,带星号的参数也可放在其他位置(而不是最后),但不同的是,在这种情况下你需要做些额外的工作:使用名称来指定后续参数
>>> def in_the_middle(x, *y, z): ... print(x, y, z) ... >>> in_the_middle(1, 2, 3, 4, 5, z=7) 1 (2, 3, 4, 5) 7 >>> in_the_middle(1, 2, 3, 4, 5, 7) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: in_the_middle() missing 1 required keyword-only argument: '
要收集关键字参数,可使用两个星号
>>> def print_params_3(**params): ... print(params) ... >>> print_params_3(x=1, y=2, z=3) {'z': 3, 'x': 1, 'y': 2}
def print_params_4(x, y, z=3, *pospar, **keypar): print(x, y, z) print(pospar) print(keypar)
>>> print_params_4(1, 2, 3, 5, 6, 7, foo=1, bar=2) 1 2 3 (5, 6, 7) {'foo': 1, 'bar': 2} >>> print_params_4(1, 2) 1 2 3 () {}
分配参数
def add(x, y):
return x + y
params = (1, 2)
>>> add(*params)
3
格式化输出
-
name = liwei print("{name} hello")
-
print("{} hello".format(name));
变量遮盖问题
如果需要,可使用函数globals来访问全局变量。这个函数类似于vars,返回一个包含全局变量的字典。(locals返回一个包含局部变量的字典。)
>>> def combine(parameter): ... print(parameter + globals()['parameter']) ... >>> parameter = 'berry' >>> combine('Shrub') Shrubberry
函数嵌套
def multiplier(factor):
def multiplyByFactor(number):
return number * factor
return multiplyByFactor
在这里,一个函数位于另一个函数中,且外面的函数返回里面的函数。也就是返回一个函数,而不是调用它。重要的是,返回的函数能够访问其定义所在的作用域。换而言之,它携带着自己所在的环境(和相关的局部变量)!
创建类
class Person:
def set_name(self,name):
self.name = name
def get_name(self):
return self.name
def greet(self):
print("Hello,world!I'm{}".format(self.name))
self指向对象本身
- 让另一个变量指向同一个方法
>>> class Bird:
... song = 'Squaawk!'
... def sing(self):
... print(self.song)
...
>>> bird = Bird()
>>> bird.sing()
Squaawk!
>>> birdsong = bird.sing
>>> birdsong()
Squaawk!
- 获取私有变量和私有方法的效果
class Secretive:
def __inaccessible(self):
print("Bet you can't see me ...")
def accessible(self):
print("The secret message is:")
self.__inaccessible()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xLsxo4YG-1635823411547)(https://i.loli.net/2021/04/09/nCNwGiJZd79IVEs.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AW4r1Onf-1635823411548)(https://i.loli.net/2021/04/09/SQtXgE1DueBbN9j.png)]
命名空间
在class语句中定义的代码都是在一个特殊的命名空间(类的命名空间内)执行的,而类的所有成员都可以访问这个命名空间
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
>>> m1 = MemberCounter()
>>> m1.init()
>>> MemberCounter.members
1
>>> m2 = MemberCounter()
>>> m2.init()
>>> MemberCounter.members
2
如果你在一个实例中给属性members赋值,结果将如何呢
>>> m1.members = 'Two'
>>> m1.members
'Two'
>>> m2.members
2
新值被写入m1的一个属性中,这个属性遮住了类级变量。这类似于第6章的旁注“遮盖的问题”所讨论的,函数中局部变量和全局变量之间的关系
超类和子类
- 指定超类
class Filter:
def init(self):
self.blocked = []
def filter(self, sequence):
return [x for x in sequence if x not in self.blocked]
class SPAMFilter(Filter): # SPAMFilter是Filter的子类
def init(self): # 重写超类Filter的方法init
self.blocked = ['SPAM']
继承
同样,要确定对象是否是特定类的实例,可使用isinstance
>>> s = SPAMFilter()
>>> isinstance(s, SPAMFilter)
True
>>> isinstance(s, Filter)
True
>>> isinstance(s, str)
False
如果你要获悉对象属于哪个类,可使用属性__class__
>>> s.__class__ <class __main__.SPAMFilter at 0x1707c0>
多个超类
class Calculator:
def calculate(self, expression):
self.value = eval(expression)
class Talker:
def talk(self):
print('Hi, my value is', self.value)
class TalkingCalculator(Calculator, Talker):
pass
这被称为多重继承,是一个功能强大的工具。然而,除非万不得已,否则应避免使用多重继承,因为在有些情况下,它可能带来意外的“并发症”
-
如果多个超类含有同名的方法
必须在class语句中小心排列这些超类,因为位于前面的类的方法将覆盖位于后面的类的方法。因此,在前面的示例中,如果Calculator类包含方法talk,那么这个方法将覆盖Talker类的方法talk(导致它不可访问)
构造函数
class FooBar:
def __init__(self):
self.somevar = 42
>>> f = FooBar()
>>> f.somevar
42
set集合
- 不重复性
- 不支持下标访问
- 添加方法为add
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bWgL12d5-1635823411550)(https://i.loli.net/2021/04/09/zWjfa52GYqCuHMI.png)]
类方法和函数
实际上,方法和函数的区别表现在前一节提到的参数self上。方法(更准确地说是关联的方法)将其第一个参数关联到它所属的实例,因此无需提供这个参数。无疑可以将属性关联到一个普通函数,但这样就没有特殊的self参数了
>>> class Class:
... def method(self):
... print('I have a self!')
...
>>> def function():
... print("I don't...")
...
>>> instance = Class()
>>> instance.method()
I have a self!
>>> instance.method = function
>>> instance.method()
I don't
抽象基类
from abc import ABC, abstractmethod
class Talker(ABC):
@abstractmethod
def talk(self):
pass
这里的要点是你使用@abstractmethodS来将方法标记为抽象的——在子类中必须实现的方法
- 集成抽象基类进行实例化
class Knigget(Talker):
def talk(self):
print("ni!")
调用未关联的超类构造函数和使用函数Super
-
未关联的超类构造函数
class SongBird(Bird): def __init__(self): Bird.__init__(self) self.sound = 'Squawk!' def sing(self): print(self.soun
-
使用super()函数
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry: print('Aaaah ...') self.hungry = False else: print('No, thanks!') class SongBird(Bird): def __init__(self): super().__init__
你无需知道函数super的内部工作原理,但必须知道的是,使用函数super比调用超类的未关联构造函数(或其他方法)要好得多。函数super返回的到底是什么呢?通常,你无需关心这个问题,只管假定它返回你所需的超类即可。实际上,它返回的是一个super对象,这个对象将负责为你执行方法解析。当你访问它的属性时,它将在所有的超类(以及超类的超类,等等)中查找,直到找到指定的属性或引发AttributeError异常
函数property
class Rectangle:
def __init__ (self):
self.width = 0
self.height = 0
def set_size(self, size):
self.width, self.height = size
def get_size(self):
return self.width, self.height
size = property(get_size, set_size)
在这个新版的Rectangle中,通过调用函数property并将存取方法作为参数(获取方法在前,设置方法在后)创建了一个特性,然后将名称size关联到这个特性。这样,你就能以同样的方式对待width、height和size,而无需关心它们是如何实现的
>>> r = Rectangle()
>>> r.width = 10
>>> r.height = 5
>>> r.size
(10, 5)
>>> r.size = 150, 100
>>> r.width
150