Python 语法基础

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

更好的阅读体验 \color{red}{更好的阅读体验} 更好的阅读体验


目录


前言


自从对着官方文档对着 ipython 敲了一遍一天学完了 Python 的语法之后我觉得我行了。于是屁颠屁颠地跑去写项目结果显而易见开发之路可谓寸步难行一停下来就光速遗忘。

这引起了我深刻地反思学习这条路上切勿取巧偷懒切勿急于求成切勿自以为是。简言之就是

形不成形意不在意再回去练一练吧。

于是便有了这篇在寒假的尾巴尖上重新学起的 Python 语法基础。现在回看自己的学习历程我竟从未有过像学习 Python 如此认真地学习过一门语言也因此发现了大量速成时遗漏的点。即便如此学习我也只是处于 Python 的入门阶段留下这篇笔记以作警醒学途不尽仍需努力。

本篇大量参考自官方文档亦师从好基友 VJK 并参考其博客 Python 系列。如有谬误之处欢迎指出。


1. 数字类型


1.0 type()函数


type(变量)
print(type(变量)) # 打印出变量的数据类型

1.1 int


不需要像 C/C++ 一样先定义直接声明即可。

a = 2
print(type(a))

1.2 float


C/C++ 不同Python 中的 float 精度更高范围在 -3.4028235 x 10^38 ~ 3.4028235 x 10^38 之间。

a = 2.333
b = 5.
print(type(a))
print(type(b))

1.3 complex


Python 中可以直接表示复数类型。

a = 1 + 2j
print(type(a))

2. 运算符


2.1 除法


  • 除法/
  • 向下取整除法 //
a = 10
b = 3
c = a / b
d = a // b
print("c: ", c, type(c))
print("d: ", d, type(d))

可以得知/ 运算返回一个 float 类型而 // 返回 int 类型。


2.2 取余


  • 取余%
a = 10
b = 3
c = a % b
d = b % a
print("c: ", c, type(c))
print("d: ", d, type(d))

% 运算返回 int 类型。


2.3 乘法


  • 乘法*
  • 乘方**
a = 10
b = 3.0
c = a * b
d = a ** b
print("c: ", c, type(c))
print("d: ", d, type(d))

*** 运算返回精度更高的类型。


2.4 比较运算符


  • 等于==
  • 不等于!=
  • 大于>
  • 大于等于>=
  • 小于<
  • 小于等于<=
a = 1
b = 2
c = 1
print(a == b)
print(a == c)
print(a != b)
print(a > b)
print(a >= c)
print(a < b)
print(b <= c)

3. 字符串


3.1 基本操作


声明即可赋值

a = 'abcd'
b = "abcd"
c = """abcd"""
print("a: ", a, type(a))
print("b: ", b, type(b))
print("c: ", c, type(c))
print(a, b, c)

\ 用于转义例如

# a = 'a'bc'd' 错误语句
b = "a'bc'd"
c = "a\'bc\'d"
# print("a: ", a, type(a))
print("b: ", b, type(b))
print("c: ", c, type(c))

取消全部的转义在前面加上 r

print("a\nbcd")
print(r"a\nbcd")

字符串字面值可以包含多行使用三重引号"""..."""'''...'''

a = """
    'a' is a string
    Python is instring
"""
print(a)

使用 + 进行拼接* 进行重复

a = "abcd"
b = "efgh"
c = a + b
d = a * 2 + b * 3
print("c: ", c, type(c))
print("d: ", d, type(d))

3.2 索引和切片


3.2.1 索引


字符串支持索引下标访问第一个字符的索引是 0单个字符没有专用的类型就是长度为一的字符串

a = "abcd"
print(a[0])
print(a[2])

索引支持负数用负数索引时从右边开始计数

a = "abcd"
print(a[0])
print(a[-0])  # -0 和 0 一样
print(a[1])
print(a[-1])  # 负数索引从 -1 开始

Python 字符串不能修改是 immutable

a = "abcd"
# a[0] = "d"  报错

值得注意的是由于 Python 中的字符串是不可改变的连接两个字符串会创建一个新的字符串而不是修改一个现有的字符串

string = "abc defg hijk"
new_string = ""
for i in string:
    if i != ' ':
        new_string += i

print(new_string)

3.2.2 切片


索引可以提取单个字符切片则提取子字符串

  • 语法str[起始位:终止位:步长]
  • 省略开始索引时默认值为 0省略结束索引时默认为到字符串的结尾。
  • 切片开始包括起始位元素截至到终止位的前一个元素即不包含终止位元素。
  • 其中步长可省略默认为1切片返回一个新的字符串。
a = "abcd"
b = a[0:2]
c = a[2:4]
d = a[:2]
e = a[2:]
f = a[:]
g = a[0:4:2]
h = a[-1::-1]
i = a[0:100]
print(b)
print(c)
print(d)  # 起始索引默认为 0
print(e)  # 结束索引默认为字符串结尾
print(f)
print(g)  # 步长为 2每 2 个元素取一个
print(h)  # 步长为负数从左往右切
print(i)  # 切片越界自动处理

注意索引越界会报错切片越界会自动处理。


3.3 常用内置函数


a = "lys is a dog"
print(len(a))  # len() 返回字符串的长度

print(a.title())  # 给每个单词首字母大写
print(a.upper())  # 把所有字母变成大写
a = a.upper()
print(a.lower())  # 把所有字母变成小写

b = "   lys is a dog   "
print(b.lstrip())  # 去除头空格
print(b.rstrip())  # 去除尾空格
print(b.strip())  # 去除头尾空格

4. 列表与元组


Python 支持多种复合数据类型可将不同值组合在一起。最常用的列表是用方括号标注逗号分隔的一组值。列表可以包含不同类型的元素但一般情况下各个元素的类型相同

a = [1, 2, 3, 4]
b = ['a', 'b', 'c', 'd']
c = ['a', '2', '3.33', "cde"]
d = a + b  # 支持 + 合并
e = c * 2 + d * 3  # 支持 * 合并
print("a: ", a, type(a))
print("b: ", b, type(b))
print("c: ", c, type(c))
print("d: ", d, type(d))
print("e: ", e, type(e))

4.1 列表索引和切片


4.1.1 索引


和数组操作相同

a = [1, 2, 3, 4]
b = ['a', 'b', 'c', 'd']
c = ['a', '2', '3.33', "cde"]
print(a[0])
print(b[1])
print(c[2])

immutable 字符串不同, 列表是 mutable 类型其内容可以改变

a = [1, 2, 3, 4]
b = ['a', 'b', 'c', 'd']
c = ['a', '2', '3.33', "cde"]
a[0], b[1], c[2] = 100, 'x', "abc"
print("a: ", a, type(a))
print("b: ", b, type(b))
print("c: ", c, type(c))

4.1.2 切片


切片操作返回包含请求元素的新列表切片操作会返回列表的浅拷贝

a = [1, 2, 3, 4]
b = a[0:2]
c = a[2:]
print(b)
print(c)

4.2 嵌套列表


a = [1, 2, 3, 4]
b = ['a', 'b', 'c', 'd']
c = ['a', '2', '3.33', "cde"]
e = [a, b, c]
print("e: ", e, type(e))
print(e[0][0], e[1][1], e[2][2])

4.3 列表常用内置函数


a = [1, 2, 3, 4]
print("len(a): ", len(a))  # len() 返回列表的长度

a.append(5)  # 在 a 末尾添加元素 5
print("a.append(5): ", a)

a.insert(1, 3)  # 在位置 1 处插入元素 3
print("a.insert(1, 3): " ,a)

a.remove(3)  # 删除第一个值为 3 的元素
print("a.remove(3): ", a)
# a.remove(0)  删除的元素不存在则会触发 ValueError 异常

a.pop(0)  # pop(i) 删除指定位置 i 的元素
print("a.pop(0):", a)
a.pop()  # 未传入参数时默认删除末尾元素
print(a)

a = [1, 2, 3, 4, 5]
del a[1:3]  # 删除列表的切片
print("del a[1:3]:", a)

a = [6, 5, 4, 3, 2, 1, 1]
print("a.count(1): ", a.count(1))  # count(x) 返回值为 x 的元素出现的次数

a.sort()  # 默认从小到大排序
print("a.sort(): ", a)
a.sort(reverse=True)  # 传入参数从大到小排序
print("a.sort(reverse=True): ", a)

b = sorted(a)  # 默认从小到大排序
print("b: ", b)
b = sorted(a, reverse=True) # 传入参数从大到小排序
print("b: ", b)

a.reverse()  # 翻转列表中的元素
print("a.reverse()", a)

a.clear()  # 清空
print(len(a))

4.4 元组


元组由多个用逗号隔开的值组成

a = 1, 2, 3, 4
print("a: ", a, type(a))
b = ('a', 'b', 'c', 'd', a)  # 由 () 表示一个元组可嵌套使用
print("b: ", b, type(b))

输出时元组都要由圆括号标注这样才能正确地解释嵌套元组。输入时圆括号可有可无不过经常是必须的如果元组是更大的表达式的一部分。不允许为元组中的单个元素赋值当然可以创建含列表等可变对象的元组。

元组同样支持索引和切片

a = 1, 2, 'a', 'b'
print(a[0])
print(a[1:3])
# a[0] = 0  不可修改

虽然元组与列表很像但使用场景不同用途也不同。元组是 immutable 不可变的一般可包含异质元素序列通过解包索引访问如果是 namedtuples可以属性访问。列表是 mutable 可变的列表元素一般为同质类型可迭代访问。


4.5 浅拷贝与深拷贝


copydeepcopyPython 中用于复制对象的两个函数。

  • copy 是浅拷贝只复制对象的引用如果对象内部包含子对象修改子对象的值会影响原对象。
  • deepcopy 是深拷贝会递归复制对象的内部结构从而生成一个完全独立的对象不会与原对象产生任何关系。
import copy

a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]  # c 中包含 a, b 两个子对象
d = c
print("a: ", id(a))
print("b: ", id(b))
print("c: ", id(c))
print("d: ", id(d))  # id(d) == id(c) 说明 d 和 c 是相同的对象

print()

d = copy.copy(c)
print("c: ", id(c))
print("copy(d): ", id(d))  # copy(d) 生成了一个新的对象
print("a: ", id(a))
print("c[0]: ", id(c[0]))
print("copy(d[0]): ", id(d[0]))  # d[0] 和 c[0] 是相同的对象说明新生成的对象没有改变原来 c 中的子对象

print()

d = copy.deepcopy(c)
print("c: ", id(c))
print("copy(d): ", id(d))  # copy(d) 生成了一个新的对象
print("a: ", id(a))
print("c[0]: ", id(c[0]))
print("copy(d[0]): ", id(d[0]))  # d[0] 和 c[0] 不是相同的对象说明新生成的 d 是一个完全独立的对象

总结deepcopy 会生成一个独立的对象而 copy 只是对对象的引用。

参考链接What is the difference between shallow copy, deepcopy and normal assignment operation?


5. 集合与字典


5.1 集合


集合是由不重复元素组成的无序容器基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。

a = {1, 2, 3, 4, 5}
print("a: ", a, type(a))

集合运算

a = {1, 2, 3, 4, 5}
b = {2, 4, 5}
print("1 in a is", 1 in a)
print("1 in b is", 1 in b)
print("a = b is", a == b)
print("a - b =", a - b)
print("b - a =", b - a)
print("a | b =", a | b)
print("a & b =", a & b)
print("a ^ b =", a ^ b)

5.2 字典


字典为键值对的集合字典的键必须是唯一的

a = {1:'a', 2:'b', 3:'c', 4:'d'}
print("a: ", a, type(a))
print("a[1]: ", a[1])

b = {'a':1, "bcd":2, 3.4:"e"}
print("b: ", b, type(b))
print("b['a']: ", b['a'])

与以连续整数为索引的序列不同字典以关键字为索引关键字通常是字符串或数字也可以是其他任意不可变类型。只包含字符串、数字、元组的元组也可以用作关键字。但如果元组直接或间接地包含了可变对象就不能用作关键字。列表不能当关键字因为列表可以用索引、切片、append()extend() 等方法修改。

a = {'name': 'wjq', 'sex': 'male', 'qq': 1145141919}
print(a.get('name'))  # 通过键获取值且不会报错
a.pop('qq')  # 删除键为 qq 的键值对
print(a.keys())  # 获取所有的键
print(a.values())  # 获取所有的值
a['name'] = 'lys'  # 改值
print("a: ", a, type(a))

合并两个键值不冲突的字典可以使用如下方法

a = {1:'a', 2:'b'}
b = {3:'c', 4:'d'}

c = a
c.update(b)  # 内置函数 update

d = {**a, **b}  # 解包合并

print("c: ", c)
print("d: ", d)

6. if 语句


条件表达式为真时执行语句

a = int(input("input 'a' number: "))
if a == 0:
    print("'a' is zero", end='')
elif a > 0:
    print("'a' is a positive number", end='')
else:
    print("'a' is a negative number")

支持嵌套

a = int(input("input 'a' number: "))
if a == 0:
    print("'a' is zero", end='')
elif a > 0:
    if a > 100:
        print("'a' is a positive number and 'a' is bigger than 100", end='')
    elif a == 100 :
        print("'a' is equal to 100", end='')
    else :
        print("'a' is a positive number and 'a' is smaller than 100", end='')
else:
    print("'a' is a negative number")

注意条件表达式的本质是得到一个 bool 值以下非条件表达式的值也会被视为 False

  • False
  • 0
  • None
  • ""[](){}

7. while 语句


while 语句用于在表达式保持为真的情况下重复地执行

flag = 10
a = 0
while a < flag:
    print(a, end=' ')
    a += 1
print("\na:", a)

其余扩展用法同 for 语句相同详见下面内容。


8. for 语句


8.1 基本使用


Pythonfor 语句不迭代算术递增数值也不给予用户定义迭代步骤和暂停条件的能力而是迭代列表或字符串等任意序列元素的迭代顺序与在序列中出现的顺序一致。

a = [1, 2, 3, 4, 5]
for i in a:
    print(i, end=' ')
print()
b = [1, 2.333, 'a', "bcd"]
for i in b:
    print(i, type(i))

注意Python 中在使用 for 循环遍历列表元素时不能直接在循环体中删除列表元素这样会导致迭代错误。

a = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(len(a)):
    if a[i] % 2 == 0:
        del a[i]
print(a)
# IndexError: list index out of range

要在遍历时修改集合的内容应该遍历该集合的副本或创建新的集合

a = [1, 2, 3, 4, 5, 6, 7, 8]
b = []
for i in range(len(a)):
    if a[i] % 2 != 0:
        b.append(a[i])
print(b)

8.2 range() 函数


range 类型表示不可变的数字序列通常用于在 for 循环中循环指定的次数。

for i in range(10):
    print(i, end=' ')

a = list(range(10))  # 生成一个列表 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(a)

生成的序列不包含给定的终止数值range(10) 生成 10 个值这是一个长度为 10 的序列其中的元素索引都是合法的。

  • range(起始值,终止值,步进)
  • 起始值省略默认为 0
  • 步进值省略时默认为 1可以为负数。
for i in range(1, 10):
    print(i, end=' ')
print()
for i in range(0, 10, 2):
    print(i, end=' ')
print()
for i in range(0, -10, -1):
    print(i, end=' ')

range()len() 组合在一起可以按索引迭代序列等价于 enumerate() 函数

a = [1, 2, 3, 4, 5]
for i in range(len(a)):
    print(f"index: {i}, value: {a[i]}")
print()
for i, v in enumerate(a):
    print(f"index: {i}, value: {v}")

只输出 range():

print(range(1, 10))
# range(1, 10)  输出内容

range() 返回对象的操作和列表很像但其实这两种对象不是一回事。迭代时该对象基于所需序列返回连续项并没有生成真正的列表从而节省了空间。

这种对象称为可迭代对象 iterable函数或程序结构可通过该对象获取连续项直到所有元素全部迭代完毕。for 语句就是这样的架构sum() 是一种把可迭代对象作为参数的函数

print(sum(range(1, 5)))  #sum 计算了 1 + 2 + 3 + 4 的值
# 10  输出内容

8.3 循环嵌套语句


8.3.1 嵌套 if 语句


a = [1, 2, 3, 4, 5, 6, 7, 8]
for i in a:
    if i % 2 == 0:
        print(i, end=' ')
    else :
        print(-1, end=' ')

8.3.2 嵌套循环语句


a = [0, 1, 2, 3, 4, 5]
b = [[], []]
for i in list(range(len(b))):
    for j in a:
        b[i].append(j)
print(b)

8.3.3 break、continue、pass 语句


a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
for i in a:
    if i % 2 == 0:
        continue
        # pass  不执行任何内容此处效果和continue 相同
    elif i % 3 == 0:
        print(i, end=' ')
print()
for i in a:
    if i % 5 != 0:
        print(i, end=' ')
    else:
        break  # 提前跳出本层循环

8.4 循环的技巧


在字典中循环时用 items() 方法可同时取出键和对应的值

a = {1:'a', 2:'b', 3:'c', 4:'d'}
for k, v in a.items():
    print(f"key:{k}, value:{v}")

若只需要字典中的值可以用 values() 方法

a = {1:'a', 2:'b', 3:'c', 4:'d'}
for v in a.values():
    print(f"value:{v}")

在序列中循环时用 enumerate() 函数可以同时取出位置索引和对应的值

a = [1, 2, 3, 4, 5]
for i, v in enumerate(a):
    print(f"index:{i}, value:{v}")

同时循环两个或多个序列时用 zip() 函数可以将其内的元素一一匹配

questions = ['name', 'quest', 'favorite color']
answers = ['lys', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
    # print(f"What is your {q}? It is {a}.")
    print("What is your {0}? It is {1}.".format(q, a))

逆向循环序列时调用 reversed() 函数

a = [1, 2, 3, 4, 5]
for i in reversed(a):
    print(i, end=' ')

按指定顺序循环序列可以用 sorted() 函数在不改动原序列的基础上返回一个重新的序列

a = [2, 5, 1, 4, 3]
for i in sorted(a):
    print(i, end=' ')
print()
for i in sorted(a, reverse=True):
    print(i, end=' ')
print()
for i in a:
    print(i, end=' ')

使用 set() 去除序列中的重复元素。使用 sorted()set() 则按排序后的顺序循环遍历序列中的唯一元素

a = [1, 3, 1, 2, 3, 4, 5, 4, 3, 2, 1, 5, 4]
for i in sorted(set(a)):
    print(i, end=' ')

for 支持推导式表达

a = list(range(1, 10))
print("a: ", a)
b = [i*i for i in a]  # b 为 a 中元素的平方
print("b: ", b)
c = {k:v for k,v in zip(a, b)}
print("c: ", c)

9. 格式化输出


9.1 格式化字符串字面值


格式化字符串字面值 简称为 f-字符串在字符串前加前缀 fF通过 {expression} 表达式把 Python 表达式的值添加到字符串内

a = 100
b = 'lys'
print(f"{b} is {a} years old")

格式说明符是可选的写在表达式后面可以更好地控制格式化值的方式。下例将 pi 舍入到小数点后三位

import math
print(f'The value of pi is approximately {math.pi:.3f}.')

':' 后传递整数为该字段设置最小字符宽度常用于列对齐

table = {1:'a', 2:'bc', 3:'def', 4:'ghij'}
for k, v in table.items():
    print(f'key is {k:5} ==> value is {v:5} in this table')

9.2 字符串 format() 方法


str.format() 方法的基本用法如下所示

print("{} is a {}.".format('lys', 'dog'))

花括号及之内的字符称为格式字段被替换为传递给 str.format() 方法的对象。花括号中的数字表示传递给 str.format() 方法的对象所在的位置

print("{0} is a {2} and {1} is a {2}, too.".format('lys', 'wjq', 'dog'))

str.format() 方法中使用关键字参数名引用值

print("{name1} is a {name3} and {name2} is a {name3}, too.".format(name1='lys', name2='wjq', name3='dog'))

上述方法也可以交叉使用

print("{name1} is a {0} and {name2} is a {0}, too.".format('dog', name1='lys', name2='wjq'))

10. 异常处理


10.1 异常处理语句


利用 tryexceptfinallyelse 语句处理异常

a = 100
b = 0;
d = [1, 2, 3, 4]
try:
    c = a / b
    e = d[10]  # 前两条语句异常只会处理第一条语句异常直接跳出 try进入 except 匹配异常
    f = a + b  # 若前两条语句无异常执行 else 中的语句
except ValueError:  # 异常匹配
    print("ValueError")
except ZeroDivisionError:
    print("ZeroDivisionError")
except IndexError:
    print("IndexError")
else:
    print("No Error Exist")  # try 无异常则执行
finally:  # 无论是否有其他异常都会执行
    print("Over")
  • 首先执行 try 子句tryexcept 关键字之间的多行语句。
  • 如果没有触发异常则跳过 except 子句try 语句执行完毕。
  • 如果执行 try 子句时发生了异常则跳过该子句中剩下的部分。如果异常的类型与 except 关键字后面的异常匹配则执行 except 子句。
  • 如果发生的异常不是 except 子句中列示的异常则将其传递到外部的 try 语句中如果没有找到处理程序则它是一个未处理异常语句执行将终止。
  • 如果 try 子句没有触发异常但又必须执行一些代码时利用 else 语句执行子句内容注意该语句只能放在所有的 except 语句后。
  • 最后无论是否出现异常都会执行 finally 语句的子句。

其中except 可以用元组命名多个异常

a = 100
b = 0;
d = [1, 2, 3, 4]
Errors = (ValueError, RuntimeError, FloatingPointError, IndexError, TypeError, ZeroDivisionError)
try:
    c = a / b
    e = d[10]  # 前两条语句异常只会处理第一条语句异常直接跳出 try进入 except 匹配异常
    f = a + b  # 若前两条语句无异常执行 else 中的语句
except Errors:
    print("Errors")
else:
    print("No Error Exist")  # try 无异常则执行
finally:  # 无论是否有其他异常都会执行
    print("Over")
    # print(f)

10.2 抛出异常


raise 语句支持强制触发指定的异常

a = 100
b = 0
try:
    c = b / a
    raise ZeroDivisionError('Zero  can be divided')
except ZeroDivisionError:
    print("ZeroDivisionError")
    raise
finally:
    print("Over")

11. 函数


11.1 定义函数


使用关键字 def 定义函数后跟函数名与括号内的形参列表

def solve(n):
    """Print 1 to n"""
    for i in range(1, n + 1):
        print(i, end=' ')

a = int(input())
solve(a)

函数内的第一条语句是字符串时该字符串就是文档字符串也称为 docstring详见文档字符串。利用文档字符串可以自动生成在线文档或打印版文档。

print(solve.__doc__)  # 打印出 solve 的说明

11.2 默认值参数和关键字参数


函数定义时参数列表的值可以设置初始值作为默认值参数

def solve(age=24, name="lys", status="dog"):
    print(f"{name} is", end=' ')
    print(f"{age} years old, and {name}", end=' ')
    print(f"is a {status} .")

solve()  # 函数参数都存在默认值调用

若存在未初始化的参数则可以 kwarg=value 形式的 关键字参数 调用函数

def solve(age, name="lys", status="dog"):
    print(f"{name} is", end=' ')
    print(f"{age} years old, and {name}", end=' ')
    print(f"is a {status} .")

solve(114514)  # 第一个参数是必选参数剩余参数可不选
solve(114514, "LYS")  # 不声明关键字会默认匹配除默认参数后的最近的关键字参数
solve(114514, name="LYS")
solve(14, status="debu cat", name="Hiiro")  # 传入关键字参数与参数列表的关键字对应

除上述调用方法外以下调用非法

solve()  # 缺省 age 参数
solve(name="Hiiro")  # 缺省 age 参数
solve(age=114514, "debu cat")  # debu cat 需要照应一个关键字
solve(114514, age=1919)  # age 存在多个不同的值

总结

  • 函数调用时关键字参数必须跟在位置参数后面。
  • 所有传递的关键字参数都必须匹配一个函数接受的有效参数。
  • 关键字参数的顺序并不重要但不能对同一个参数多次赋值。

11.3 解包实参列表


需要将序列作为参数时用 * 操作符把实参从列表或元组解包出来

name1 = [114514, 'Lys', 'dog']
name2 = (14, 'Hiiro', 'debu cat')

def solve(age, name, status):
    print(f"{name} is", end=' ')
    print(f"{age} years old, and {name}", end=' ')
    print(f"is a {status} .")

solve(*name1)
solve(*name2)

同样字典可以用 ** 操作符传递关键字参数

name1 = {'age':114514, 'name':'Lys', 'status':'dog'}

def solve(age=24, name='Van', status='XainBei'):
    print(f"{name} is", end=' ')
    print(f"{age} years old, and {name}", end=' ')
    print(f"is a {status} .")

solve(**name1)
# solve(*name1) Output: name is age years old, and name is a status . 

11.4 函数的返回值


return 语句返回函数的值。return 语句不带表达式参数时返回 None。函数执行完毕退出也返回 None

# 返回值
def solve(n):
    """Show 1 * 2 * ... * n"""
    if n > 1:
        return solve(n - 1) * n
    else:
        return 1

a = int(input())
print(solve(a))
# 返回一个 list
def solve(n):
    """Create a list which is the first n terms of the Fibonacci series"""
    fib = [0, 1]
    for i in range(2, n):
        fib.append(fib[i - 1] + fib[i - 2])
    return fib

a = int(input())
print(solve(a))
# 返回多个值
def solve(a, b):
    return a + b, a - b

n , m = solve(1, 2)  # 用对应数量的变量接收
print(f"n = {n}, m = {m}")

t = solve(1, 2)  # 用一个值接收则会返回一个元组
print(f"t: {t}", type(t))

11.5 变量作用域


函数内部只作引用的 Python 变量隐式视为全局变量。如果在函数内部任何位置为变量赋值则除非明确声明为全局变量否则均将其视为局部变量

a = 1

def use():
    print(f"use: {a}")

def change():
    a = 114514

use()
change()  # 调用函数

print(a)  # a 的值不发生改变

可以看到use() 函数在只做引用的情况下将 a 视为了全局变量而在 change() 函数中对 a 做修改则将 a 视为了局部变量并没有改变其值。

使用关键词 global 声明变量将被视为全局变量在函数对象中更改不再视为局部变量

a = 1

def use():
    print(f"use: {a}")

def change():
    global a
    a = 114514

use()
change()  # 调用函数

print(a)  # a 的值不发生改变

11.6 Lambda表达式


lambda 表达式有时称为 lambda 构型被用于创建匿名函数。 表达式 lambda parameters: expression 会产生一个函数对象

f = lambda a, b: a + b
print(f(1, 2))
def solve(n):
    return lambda t: t + n

a = 114
f = solve(a)
print(f(1000))

print(solve(114)(1000))  # 或直接调用

11.7 函数闭包


函数闭包是一种特殊的函数它不仅包含函数代码还引用了它外部作用域中的一些变量。这种引用关系使得闭包可以在外部作用域中的变量保持其生存周期即使闭包被销毁。

闭包可以用于缓存函数的结果避免重复计算也可以用于实现装饰器等高阶函数。

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(10)
print(closure(5))  # Output: 15

11.8 装饰器


装饰器其实也是一种闭包作为一种语法糖Python 中广泛使用当对某个冗长的函数加上其他功能利用装饰器可以在不修改原本函数内容的同时增添新的功能

现在有 solve() 函数如下

def solve():
    print("Function solve is called.")

若要求再输出一行 "Calling finished."

简单方法如下

def solve():
    print("Function solve is called.")
    print("Calling finished.")

闭包思路如下

def solve():
    print("Function solve is called.")

def addition(func):
    def inner():
        func()
        print("Calling finished.")
    return inner

Func = addition(solve)
Func()

语法糖思路如下

def addition(func):
    def inner():
        func()
        print("Calling finished.")
    return inner

@addition
def solve():
    print("Function solve is called.")

solve()

由此可以看出利用语法糖可以在不改变原函数内容和调用的情况下增加修改。


11.9 生成器


yield是用于实现迭代器。它可以在函数中生成多个值每次运行到 yield 语句时都会暂停函数的执行并返回一个值。下次调用函数时会从上次暂停的地方继续执行

def solve():
    for i in range(1, 10):
        yield i


func = solve()  # 得到生成器对象
print(func)  # 得到生成器时是不会执行函数内部代码的

# 使用next()对象进入生成器执行代码同时可以用变量的到 yield 的返回值
num = next(func)
print(num)

num = next(func)
print(num)

# next 方法在执行完后会抛出 StopIteration 异常表示生成器已经结束需要捕获该异常
# 若没有执行完用 del 释放资源
del func

# 重新得到生成器对象并用 for 迭代所有数据此方法不会抛出异常
func = solve()
for i in func:
    print(i, end=' ')

生成器是一种特殊的迭代器可以动态生成值。它可以使代码简洁并且对大数据集的处理效率更高。

实际上在生成器函数中我们可以使用 变量1 = yield 变量2 的方式将生成器封存直到下次对生成器对象使用 send(value) 方法将 value 的值赋给 变量1 之后才可以继续往下执行代码。

def solve():
    for i in range(10):
        v = yield i
        print(v)

func = solve()  # 得到生成器对象

func.send(None)  # 传入第一个值必须为 None

num = func.send("Counting: ")
print(num)

num = func.send("Counting: ")
print(num)

del func

func = solve()
func.send(None)

for i in range(9):
    num = func.send("Counting: ")
    print(num)

12. 模块


模块是包含 Python 定义和语句的文件。其文件名是模块名加后缀名 .py 。在模块内部通过全局变量 __name__ 可以获取模块名即字符串。

模块包含可执行语句及函数定义。这些语句用于初始化模块且仅在 import 语句第一次遇到模块名时执行。

首先创建一个名为 solve.py 的文件

def Sum(n):
    """Calculate the sum of list and return the result"""
    t = 0;
    for i in range(len(n)):
        t += n[i]
    return t

def Fib(n):
    """Create a list which is the first n terms of the Fibonacci series"""
    fib = [0, 1]
    for i in range(2, n):
        fib.append(fib[i - 1] + fib[i - 2])
    return fib

在该文件中我们定义了 Sumfib 函数接下来在另一个 .py 文件里导入并使用

from solve import Sum
from solve import Fib
a = [1, 2, 3, 4]
print(Fib(Sum(a)))

也可以一次性导入该模块中所有的函数定义

from solve import *
a = [1, 2, 3, 4]
print(Fib(Sum(a)))

13. 类


类把数据与功能绑定在一起

创建新类就是创建新的对象类型从而创建该类型的新实例。类实例具有多种保持自身状态的属性。类实例还支持由类定义的修改自身状态的方法。

Python 的类是 C++Modula-3 中类机制的结合体而且支持所有面向对象编程OOP的标准特性

  • 类继承机制支持多个基类。
  • 派生类可以覆盖基类的任何方法。
  • 类的方法可以调用基类中相同名称的方法。
  • 对象可以包含任意数量和类型的数据。

和模块一样类也拥有 Python 天然的动态特性

  • 在运行时创建创建后也可以修改。

如果用 C++ 术语来描述的话类成员包括数据成员通常为 public 例外的情况见私有变量所有成员函数都是 virtual。与 C++ 不同Python 的内置类型可以用作基类供用户扩展。 此外与 C++ 一样算术运算符、下标等具有特殊语法的内置运算符都可以为类实例而重新定义。


13.1 作用域和命名空间


13.1.1 命名空间


namespace命名空间是一个从名字到对象的映射。 当前大部分命名空间都由 Python 字典实现但一般情况下基本不会去关注它们除了要面对性能问题时而且也有可能在将来更改。

下面是几个命名空间的例子

  • 存放内置函数的集合包含 abs() 这样的函数和内建的异常等

  • 模块中的全局名称

  • 函数调用中的局部名称。

    从某种意义上说对象的属性集合也是一种命名空间的形式。 关于命名空间的重要一点是不同命名空间中的名称之间绝对没有关系例如两个不同的模块都可以定义一个 maximize 函数而不会产生混淆 — 模块的用户必须在其前面加上模块名称。

    命名空间在不同时刻被创建拥有不同的生存期。包含内置名称的命名空间是在 Python 解释器启动时创建的永远不会被删除。模块的全局命名空间在模块定义被读入时创建通常模块命名空间也会持续到解释器退出。被解释器的顶层调用执行的语句从一个脚本文件读取或交互式地读取被认为是 __main__ 模块调用的一部分因此它们拥有自己的全局命名空间。内置名称实际上也存在于一个模块中这个模块被称作 builtins

    函数的本地命名空间在调用该函数时创建并在函数返回或抛出不在函数内部处理的错误时被删除。当然每次递归调用都会有自己的本地命名空间。


13.1.2 作用域


一个作用域是一个命名空间可直接访问的 Python 程序的文本区域。 这里的 “可直接访问” 意味着对名称的非限定引用会尝试在命名空间中查找名称。

虽然作用域是静态地确定的但它们会被动态地使用。 在执行期间的任何时刻会有 34 个命名空间可被直接访问的嵌套作用域

  • 最先搜索的最内部作用域包含局部名称。

  • 从最近的封闭作用域开始搜索的任何封闭函数的作用域包含非局部名称也包括非全局名称。

  • 倒数第二个作用域包含当前模块的全局名称。

  • 最外面的作用域最后搜索是包含内置名称的命名空间。

    如果一个名称被声明为全局变量则所有引用和赋值将直接指向包含该模块的全局名称的中间作用域。 要重新绑定在最内层作用域以外找到的变量可以使用 nonlocal 语句声明为非本地变量。 如果没有被声明为非本地变量这些变量将是只读的尝试写入这样的变量只会在最内层作用域中创建一个新的局部变量而同名的外部变量保持不变。

    通常当前局部作用域将引用当前函数的局部名称。 在函数以外局部作用域将引用与全局作用域相一致的命名空间模块的命名空间。 类定义将在局部命名空间内再放置另一个命名空间。

    在一个模块内定义的函数的全局作用域就是该模块的命名空间无论该函数从什么地方或以什么别名被调用。 另一方面实际的名称搜索是在运行时动态完成的。

    Python 的一个特殊规定是这样的

  • 如果不存在生效的 globalnonlocal 语句

  • 则对名称的赋值总是会进入最内层作用域。

    赋值不会复制数据它们只是将名称绑定到对象。 删除也是如此语句 del x 会从局部作用域所引用的命名空间中移除对 x 的绑定。 事实上所有引入新名称的操作都是使用局部作用域特别地import 语句和函数定义会在局部作用域中绑定模块或函数名称。

global 语句可被用来表明特定变量生存于全局作用域并且应当在其中被重新绑定nonlocal 语句表明特定变量生存于外层作用域中并且应当在其中被重新绑定。


13.1.3 示例


对象之间相互独立多个名称在多个作用域内可以绑定到同一个对象。

下面示例引用不同作用域和名称空间以及 globalnonlocal 会如何影响变量绑定

def solve():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"  # 此处 spam 为 solve() 命名空间下的一个局部变量
    do_local()
    print("After local assignment:", spam)  # 调用 do_local() 修改 spam 会隐性的视为 do_local() 的局部变量
    do_nonlocal()
    print("After nonlocal assignment:", spam)  # 此处 spam 被 nonlocal 修饰会绑定之前在最近的包含作用域中绑定的除全局变量以外的变量即其绑定到了 solve() 命名空间下的 spam
    do_global()
    print("After global assignment:", spam)  # 此处 spam 被 global 修饰即此处的 spam 为全局变量位置在 solve 之外的全局区

solve()
print("In global scope:", spam)

13.2 定义类


使用 class 关键字定义一个类

class ClassName:
    """This is a Class"""

类定义与函数定义 (def 语句) 一样必须被执行才会起作用支持文档字符串。

进入类定义时将创建一个新的命名空间并将其用作局部作用域。因此所有对局部变量的赋值都是在这个新命名空间之内。 特别的函数定义会绑定到这里的新函数名称。


13.3 类对象


类对象支持两种操作

  • 属性引用
  • 实例化

属性引用使用 Python 中所有属性引用所使用的标准语法: obj.name。 有效的属性名称是类对象被创建时存在于类命名空间中的所有名称。 因此如果类定义是这样的:

class MyClass:
    """A simple example class"""
    i = 114514

    def f(self):
        print("Lys is a dog.")

那么 MyClass.iMyClass.f() 就是有效的属性引用将分别返回一个整数和一个函数对象。 类属性也可以被赋值因此可以通过赋值来更改 MyClass.i 的值。 __doc__ 也是一个有效的属性将返回所属类的文档字符串: "A simple example class"

类的实例化使用函数表示法。 可以把类对象视为是返回该类的一个新实例的不带参数的函数

class MyClass:
    """A simple example class"""
    i = 114514

    def f(self):
        print("Lys is a dog.")

x = MyClass()  # 获得一个类的实例

创建类的新实例并将此对象分配给局部变量 x

实例化操作“调用”类对象会创建一个空对象。 许多类喜欢创建带有特定初始状态的自定义实例。 为此类定义可能包含一个名为 __init__() 的特殊方法就像这样:

def __init__(self):
    self.data = []

当一个类定义了 __init__() 方法时类的实例化操作会自动为新创建的类实例发起调用 __init__()。 因此在这个示例中可以通过以下语句获得一个经初始化的新实例

class MyClass:
    """A simple example class"""

    def __init__(self):
        self.i = 1919

    def f(self):
        print("Lys is a dog.")

x = MyClass()  # 获得一个经过初始化的实例其中 x.i = 1919

当然__init__() 方法还可以有额外参数以实现更高灵活性。 在这种情况下提供给类实例化运算符的参数将被传递给 __init__()

class MyClass:
    """A simple example class"""

    def __init__(self, num1, num2):
        self.i = num1
        self.j = num2

    def f(self):
        print("Lys is a dog.")

x = MyClass(114514, 1919)

x.f()
print(x.i, x.j)

注意在我们执行 x = MyClass()生成了一个实例对象 x这个实例对象有两种有效的属性名称

  • 数据属性
  • 方法
class MyClass:
    def __init__(self):
        i = 114514

    i = 1919

    def hello(self):
        return "Hello world"

print(MyClass.i)
print(MyClass.hello)

x = MyClass()
print(x.i)
print(x.hello)
print(x.hello())
  • MyClass.i 是类变量它的值可以通过类名直接访问它的值在所有实例之间共享。
  • MyClass.hello 是类方法这是一个可调用的对象但需要通过实例调用而不是直接通过类名调用直接调用返回该方法的地址。
  • x.i 是实例变量它的值必须通过实例名访问它的值在不同实例之间互不影响。
  • x.hello 是实例方法它的值必须通过实例名访问它只能在实例内部调用。
  • x.hello() 则是调用实例方法它会执行方法内部的代码并返回结果。

13.4 继承


13.4.1 单继承


C++ 等支持面向对象的语言一样Python 的类也支持继承其派生类定义语法如下

class DerivedClassName(BaseClassName):
    """This is a derived class"""

名称 BaseClassName 必须定义于包含派生类定义的作用域中。

子类不声明新属性将全部继承父类属性和方法

class Father:
    """This is father class."""
    def __init__(self):
        self.i = 114514
        self.j = 1919

    def show(self, num):
        print(f"{self.__doc__}: {num}")

class Son(Father):
    """This is son class"""

x = Father()
x.show(x.i)

y = Son()
y.show(y.i)  # 子类继承了父类全部属性和方法

子类声明新属性父类属性不继承但可以直接调用父类方法

class Father:
    """This is father class."""
    def __init__(self):
        self.i = 114514
        self.j = 1919

    def show(self, num):
        print(f"{self.__doc__}: {num}")

class Son(Father):
    """This is son class"""
    def __init__(self):
        self.k = 1145141919

x = Father()
x.show(x.i)

y = Son()
# y.show(y.i)  # 不再继承父类属性
y.show(y.k)  # 但仍继承父类方法

若仍要保留父类属性可再次初始化父类属性

class Father:
    """This is father class."""
    def __init__(self):
        self.i = 114514
        self.j = 1919

    def show(self, num):
        print(f"{self.__doc__}: {num}")

class Son(Father):
    """This is son class"""
    def __init__(self):
        Father.__init__(self)  # 调用父类的初始化属性
        self.k = 1145141919

x = Father()
x.show(x.i)

y = Son()
y.show(y.i)  # 重新继承了父类属性
y.show(y.k)  # 仍继承父类方法

13.4.2 多重继承


Python 也支持一种多重继承。 带有多个基类的类定义语句如下所示

class DerivedClassName(Base1, Base2, Base3):
	"""This is a multiple derived class"""

注意多重继承需要子类调用基类的 __init__ 方法否则只继承第一个基类的属性

class Father:
    """This is father class."""
    def __init__(self):
        self.i = 114514

class Mother:
    """This is mother class."""
    def __init__(self):
        self.j = 1919

class Son(Father, Mother):
    """This is son class"""

x = Son()
print(x.i)
# print(x.j)  # 缺少调用父类的 __init__ 方法的情况下j 属性未定义。
class Father:
    """This is father class."""
    def __init__(self):
        self.i = 114514

class Mother:
    """This is mother class."""
    def __init__(self):
        self.j = 1919

class Son(Father, Mother):
    """This is son class"""
    def __init__(self):  # 调用基类的 __init__ 方法
        Father.__init__(self)
        Mother.__init__(self)

x = Son()
print(x.i)
print(x.j)

在一般情况下搜索从父类所继承属性的操作是深度优先、从左至右的当层次结构中存在重叠时不会在同一个类中搜索两次。 因此如果某一属性在 DerivedClassName 中未找到则会到 Base1 中搜索它然后递归地到 Base1 的基类中搜索如果在那里未找到再到 Base2 中搜索依此类推。

真实情况比这个更复杂一些方法解析顺序会动态改变以支持对 super() 的协同调用。 这种方式在某些其他多重继承型语言中被称为后续方法调用它比单继承型语言中的 super() 调用更强大。


13.4.3 私有变量


仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。 但是大多数 Python 代码都遵循这样一个约定带有一个下划线的名称 (例如 _spam) 应该被当作是 API 的非公有部分 (无论它是函数、方法或是数据成员)。 这应当被视为一个实现细节可能不经通知即加以改变。

任何形式为 __spam 的标识符至少带有两个前缀下划线至多一个后缀下划线的文本将被替换为 _classname__spam其中 classname 为去除了前缀下划线的当前类名称。这种改写不考虑标识符的句法位置只要它出现在类定义内部就会进行。

直观地这些被改写的名称不会被子类继承有助于让子类重载方法而不破坏类内方法调用

class Father:
    """This is father class."""
    def __init__(self):
        self.i = 114514
        self.__j = 1919

    def show(self, num):
        print(f"{self.__doc__}: {num}")

class Son(Father):
    """This is son class"""

y = Son()
y.show(y.i)  # 子类继承了 i
# y.show(y.j)  # 没有继承 j

13.5 魔法方法


魔法方法Magic Methods是 Python 中的内置函数一般以双下划线开头和结尾例如 __init____del__等。之所以称之为魔法方法是因为这些方法会在进行特定的操作时会自动被调用。


13.5.1 常见的魔法方法


__doc__

表示类的描述信息

class solve:
    """This is a class."""

print(solve.__doc__)

__moudle____class__

  • __module__ 表示当前操作的对象所在的模块。
  • __class__ 表示当前操作的对象所在的类。
class solve:
    """This is a class."""

x = solve()
print(x.__module__)
print(x.__class__)

__init____new__

__init__() 初始化方法 和 __new__()通过类创建对象时自动触发执行。__new__ 是用来创建类并返回这个类的实例而 __init__ 只是将传入的参数来初始化该实例

  • __new__() 创建对象时调用会返回当前对象的一个实例。

  • __init__() 创建完对象后调用对当前对象的一些实例初始化无返回值。

    值得注意的是调用 __new__ 以创建一个 cls 类的新实例。它会将所请求实例所属的类作为第一个参数,其余的参数会被传递给对象构造器表达式 对类的调用返回值应为新对象实例通常是 cls 的实例。

如果 __new__() 在构造对象期间被发起调用并且它返回了一个 cls 的实例则新实例的 __init__() 方法将以 __init__(self[, ...]) 的形式被发起调用其中 self 为新实例而其余的参数与被传给对象构造器的参数相同。

如果 __new__() 未返回一个 cls 的实例则新实例的 __init__() 方法就不会被执行参考自 __new__()


__del__

__new____init__ 是对象的构造器 __del__ 是对象的销毁器在实例将被销毁时调用。 如果一个基类具有 __del__() 方法则其所派生的类如果也有 __del__() 方法就必须显式地调用它以确保实例基类部分的正确清除。

class solve:
    """This is a class."""
    def __del__(self):
        print("Class __del__() is called.")

x = solve()

一般情况下无需显示调用 __del__ 由解释器在进行垃圾回收时自动触发执行的。


13.5.2 数值操作操作符


Python 包含了一系列的魔法方法用于实现对象之间直接比较而不需要采用方法调用。同样也可以重载 Python 默认的比较方法改变它们的行为。下面是这些方法的列表


比较操作符


方法作用
__eq__(self, other)定义相等符号的行为 ==
__ne__(self, other)定义不等符号的行为 !=
__lt__(self, other)定义小于符号的行为 <
__gt__(self, other)定义大于符号的行为 >
__le__(self, other)定义小于等于符号的行为 <=
__ge__(self, other)定义大于等于符号的行为 >=

创建一个自定义的 str 类其中排序不再按照字典序而是按照去掉空格的字符串的长度排序

class String(str):
    """This is a string class."""

    def __new__(cls, string):
        new_string = ""
        for i in string:
            if i != ' ':
                new_string += i
        return str.__new__(cls, new_string)

    def __gt__(self, other):
        return len(self) > len(other)

    def __lt__(self, other):
        return len(self) < len(other)

x = String("abc def")
y = String("114 514 1919")

if x.__gt__(y):
    print(f"True length {x} is longer than {y}.")
elif x.__lt__(y):
    print(f"True length {x} is shorter than {y}.")
else:
    print(f"True length {x} is equal to {y}.")

单目运算符


方法作用
__pos__(self)实现一个取正数的操作
__neg__(self)实现一个取负数的操作
__abs__(self)实现一个内建的 abs() 函数的行为
__invert__(self)实现一个取反操作符~操作符的行为
__round__(self, n)实现一个内建的 round() 函数的行为
__floor__(self)实现 math.floor() 的函数行为
__ceil__(self)实现 math.ceil() 的函数行为
__trunc__(self)实现 math.trunc() 的函数行为

双目运算符


方法作用
__add__(self, other)实现一个加法
__sub__(self, other)实现一个减法
__mul__(self, other)实现一个乘法
__floordiv__(self, other)实现一个 // 操作符产生的整除操作
__div__(self, other)实现一个 / 操作符代表的除法操作
__truediv__(self, other)实现真实除法
__mod__(self, other)实现一个 % 操作符代表的取模操作
__divmod__(self, other)实现一个内建函数 divmod()
__pow__(self, other)实现一个指数操作( ** 操作符的行为
__lshift__(self, other)实现一个位左移操作 << 的功能
__rshift__(self, other)实现一个位右移操作 >> 的功能
__and__(self, other)实现一个按位进行与操作 & 的行为
__or__(self, other)实现一个按位进行或操作的行为
__xor__(self, other)异或运算符相当于 ^

反射运算


方法作用
__radd__(self, other)反射加法操作
__rsub__(self, other)反射减法操作
__rmul__(self, other)反射乘法操作
__rfloordiv__(self, other)使用 // 操作符的整数反射除法
__rdiv__(self, other)使用 / 操作符的反射除法
__rtruediv__(self, other)_true_ 反射除法这个函数只有使用 from __future__ import division 时才有作用
__rmod__(self, other)% 反射取余操作符
__rdivmod__(self, other)调用 divmod(other, self)divmod 内建函数的操作
__rpow__** 反射操作符
__rlshift__(self, other)反射左移位运算符 <<
__rshift__(self, other)反射右移位运算符 >>
__rand__(self, other)反射按位与运算符 &
__ror__(self, other)反射按位或运算符 `
__rxor__(self, other)反射按位异或运算符 ^

增量运算


方法作用
__iadd__(self, other)加法赋值
__isub__(self, other)减法赋值
__imul__(self, other)乘法赋值
__ifloordiv__(self, other)整除赋值地板除相当于 //= 运算符
__idiv__(self, other)除法赋值相当于 /= 运算符
__itruediv__(self, other)真除赋值
__imod_(self, other)模赋值相当于 %= 运算符
__ipow__(self, other)乘方赋值相当于 **= 运算符
__ilshift__(self, other)左移赋值相当于 <<= 运算符
__irshift__(self, other)左移赋值相当于 >>= 运算符
__iand__(self, other)与赋值相当于 &= 运算符
__ior__(self, other)或赋值
__ixor__(self, other)异或运算符相当于 ^= 运算符

类型转换符


方法作用
__int__(self)转换成整型
__long__(self)转换成长整型
__float__(self)转换成浮点型
__complex__(self)转换成 复数型
__oct__(self)转换成八进制
__hex__(self)转换成十六进制
__index__(self)如果你定义了一个可能被用来做切片操作的数值型你就应该定义__index__
__trunc__(self)math.trunc(self) 使用时被调用 __trunc__ 返回自身类型的整型截取
__coerce__(self, other)执行混合类型的运算

13.5.3 调用其他魔法方法


魔法方法调用条件解释
__new__(cls [,...])instance = MyClass(arg1, arg2)__new__ 在实例创建时调用
·init(self [,…])`instance = MyClass(arg1,arg2)__init__ 在实例创建时调用
__pos__(self)+self一元加法符号
__neg__(self)-self一元减法符号
__invert__(self)~self按位取反
__index__(self)x[self]当对象用于索引时
__bool__(self)bool(self)对象的布尔值
__getattr__(self, name)self.name # name不存在访问不存在的属性
__setattr__(self, name)self.name = val给属性赋值
__delattr_(self, name)del self.name删除属性
__getattribute__(self,name)self.name访问任意属性
__getitem__(self, key)self[key]使用索引访问某个元素
__setitem__(self, key)self[key] = val使用索引给某个元素赋值
__delitem__(self, key)del self[key]使用索引删除某个对象
__iter__(self)for x in self迭代
__contains__(self, value)value in self, value not in self使用 in 进行成员测试
__call__(self [,...])self(args)“调用”一个实例
__enter__(self)with self as x:with 声明的上下文管理器
__exit__(self, exc, val, trace)with self as x:with 声明的上下文管理器
__getstate__(self)pickle.dump(pkl_file, self)Pickling
__setstate__(self)data = pickle.load(pkl_file)Pickling
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: python