python基本语法笔记

基本输入输出、数据类型和转换

# 基本输入输出
x = input("please input a string")  
print(x)
print('hello, world!')
y = x.split()  # 把字符串以空格为分隔符,返回分割后形成的多个字符串的列表
# 基本数据类型
x = 1  # int
x = 3.14  # float
x = 2+9j  # complex
x = 'hello' # python'', ""用法一样,都用于字符串
x = True  # bool
y = False
x = (1, 'hello', False, 2+9j)  # 元组
x = [1, 'hello', False, 2+9j]  # 列表
x = {'hello': 20, 'jack': 10}  # 字典
x = {'tom', 18, 71}  # 集合
a, b, c = 1, 2, 3  # python支持这种多变量赋值
# 类型转换
int(x)
float(x)
eval(x)  # 字符串转化为python执行语句
str(x)

基本运算语句、条件语句、格式化输出

基本运算

计算: + , − , ∗ , / , / / , % , ∗ ∗ +,-,*,/,//,\%,** +,,,/,//,%, ( / / /总是得到float类型 / / // //用于int间的运算,得商; ∗ ∗ ** 是乘方; python同样支持增强型运算符 + = , − = , % = +=, -=, \%= +=,=,%=等等)

关系: > , < , < = , > = , = = , ! = , i n ( 属 于 ) >, < ,<=, >=, ==, !=, in(属于) >,<,<=,>=,==,!=,in

逻辑: a n d , o r , n o t and,or,not and,or,not (相当于C/C++的&&, ||, !)

eg:

2 ** 3 == 8
5 // 3 == 1
5 % 3 == 2
True == 1 in [1, 2, 3]
False == True and False
True == True or False
False == not True

条件语句

python的缩进和C/C++的{}一样,有语法含义,表示逻辑的嵌套。

x = eval(input())
if  x > 0:
    print('greater than zero!')
else if x == 0:
    print('zero')
else:
    print('less than zero!')

格式化输出

x = 23
print("%d, %.2f, %s" % (x, 23.45, 'hello'))

print()结尾默认加**\n**,可用end更改:

print('hello, world!', end='')  # 结尾不换行
print('hello, world!', end='(')  # 结尾带(
print('hello, world!', end=' by python')

print()支持以,分割的多个元素输出,以一个空格分割

print('34', x, 1, 2, 3, end='')

循环、异常处理

for

for i in range(5):  # [0,5), step = 1
    print(i, end=',')  # >>0,1,2,3,4
for i in range(3, 12, 3):  # [3,12), step=3 (negative number is allowed)
    print(i, end=',')  # >>3,6,9
for i in [2, 'hello', 2.3, False]:  # traverse a list
    print(i)

while

x = int(input())
while x > 2:
    x -= 1
    if x == 5:
        break
    elif x == 6:
        continue
else:  # conduct when while-condition is false, ignored if while-loop is broken
    print("x <= 2")

eg(三个数的最小公倍数):

s = input().split()
m = n = max(s[0], s[1], s[2])
while True:
    if( m % s[0] == 0 and m % s[1] ==0 and m %s[2] == 0):
        print(m)
        break
    m += n

异常和异常处理

常见异常(run time error):

  1. 不合理的类型转换
  2. 数学上无意义的运算
  3. 不合理的两种数据类型间运算
  4. 下标越界
  5. 输入已结束,仍执行input()[OJ做题常见]

异常处理形如:

try:
    a = int(input())
    print(100 // n)
except:  # try中发生异常,跳入except;不发生异常则无视except中的语句
    print('error')
print('end')

还可进一步获知错误类型:

try:
    a = int(input())
    print(100 // n)
except Exception as e:
    print(e)
print('end')

eg:

try:
	while True:
    	s = input().split()
    	print(s)
except:
    pass  # do nothing

函数

基本语句

函数定义形如:

def myFunc(x, y):  # 形参
    return x + y, x - y
a, b = myFunc(3, 4)
def myfunc2():
    x = [1, 2, 3]
    return x
y = myFunc2()
print(y, end='')

python的函数可返回多个数,可返回组合数据类型

无返回值,则只写return, 后不接东西

def myFunc(x):
    x[0] = 1
    return

变量、全局变量

x = 1
def f1():
    x = 2  # 内部声明赋值:局部变量
    return x
def f2():
    return x + 1  # 内部不声明:全局变量
def f3():
    global x   #global声明本函数中所用的x是全局变量
    return x - 1

python的内置函数

int(x)
float(x)
str(x)
eval(x)

ord('P')  #字符转十进制ASCLL码
chr(44)  #十进制ASCLL码转字符

x = [1, 2, 3, 0]
len(x)
max(x)
min(x)
max(1, 2, 3)
min(1, 2, 3)
abs(-3)

isinstance(x, list)  # 返回bool, 查询x是否是某类型(基本数据类型int, float, complex |组合数据类型str, tuple, list, set)

字符串

python变量的指针本质

python所有变量都是指针。 = = =使指针指向一个地方; i s is is判断是否指向一个地方; = = == ==单纯判断内容是否一样;

a = [1, 2]
b = [1, 2]
print(a is b)  # >>False
print(a == b)  # >>True
a = b
print(a is b)  # >>True
a[0] = 0
print(b[0])  # >>0 (因为指向同一个地方)

通过指针,可以函数中改变形参指向的地方的内容,和C/C++一样。

def swap(x, y):
    tmp = x[0]
    x[0] = y[0]
    y[0] = tmp

转义字符

print('\\ \t \n \* \. and so on')  # \ 	 
 								   #  \* \. and so on

字符串前面加r,规定不转义

print(r'\\ \t \n \* \. and so on')  # \\ \t \n \* \. and so on

切片

方式与matlab一样。切片同样适用于元组和列表。

a = 'abcde'
a[1:3]  # bc 左闭右开
a[0:5:2] # ace 步长为2(步长支持负数)
a[-3:-1]  # cd 起终点支持负数(想象成一个环)
a[2:]  # cde 省略终点,则取到最后
a[:4] # abc 省略起点,从头开始取
a[::-1]  # edcba 反转字符串

字符串的分割

单分隔符分割

用s.split(x)函数,以字符串x为分隔符,实现字符串分割,返回列表。

a = 'aa.&.bb..&.cc.&.dd'
print(a.split('.'))  # >>['aa', '&', 'bb', '', '&', 'cc', '&', 'dd'] 连续两个分隔符的情况,出现一个空字符串
print(a.split('&'))  # >>['aa.', '.bb..', '.cc.', '.dd']
print(a.split('..'))  # >>['aa.&.bb', '&.cc.&.dd']

多分隔符分割——使用正则表达式

import re  # import语句导入模块
s = '-What would you like?\n-Three apples and a banana. How much?'
x = '-|\?|\n| |\.'  # 用|隔开不同分隔符,注意转义字符
print(re.split(x, s))  # 用正则表达式x分割字符串s

常用字符串函数

s = 'AABBAAb'
m = s.count('AA')  # 返回字符串'AA'出现次数
m = len(s)  # 字符串长度

s1 = s.upper(s)  # 串中全部小写转大写(字符串s本身不变,字符串是不可变数据类型)
s2 = s.lower(s)  # 串中全部大写转小写(字符串s本身不变,字符串是不可变数据类型)

m = s.find('AA')  # 从头找'AA'字串,返回下标,找不到返回-1
m = s.rfind('AA')  # 从尾找'AA'字串,返回下标,找不到返回-1
m = s.index('AA')  # 从头找'AA'字串,返回下标,找不到抛出异常
m = s.rindex('AA')  # 从尾找'AA'字串,返回下标,找不到抛出异常
m = s.find('b', 3)  # find()还能指定查找起点
s3 = s.replace('AA', 'cc')  # 替换

False == s.islower()  # 判断出现的字母是否全是小写
False == s.isupper()  # 判断出现的字母是否全是大写
False == s.isdigit()  # 判断字符串是否仅含有数字
True == s.startswith('AAB')  #是否以某字符串开头
True == s.endswith('Ab')  #是否以某字符串结尾

s4 = s.strip()  # s除去两端空格字符后的字符串
s5 = s.lstrip()  # s除去左端空格字符后的字符串
s6 = s.rstrip()  # s除去右端空格字符后的字符串
s7 = s.strip('Ab')  #s除去两端出现在'Ab'中字符('A','b')后的字符串
s7 = s.strip('Ab')  #s除去左端出现在'Ab'中字符('A','b')后的字符串
s7 = s.strip('Ab')  #s除去右端出现在'Ab'中字符('A','b')后的字符串

字符串的格式化

{序号:<^>宽度.精度 类型}

<、^、>对应左对齐、中对齐、右对齐

x = 'hello, {0}{1:>10}, you get ${2:0.4f}'  # 宽度可以是0
y = '{0:>7.5f}'  #右对齐,至少占7字符宽度,精度5位的浮点数
x1 = x.format('Mr', 'Jack', 12.34)
z = 'Today is {0}, {1}.{2}.'
z1 = z.format('Monday', 'February', '14th')

元组

元组是不可变数据类型,元素可以为任意数据类型。不能增减,修改数据,或改变顺序。

但是若元组的元素中有可变组合类型,则可以修改该可变组合类型的元素。

tuple1 = ('hello', True, 3.14, 233, [1, 2, 3])
tuple2 = 'hello', True, 3.14, 233, [1, 2, 3]  # 可不加小括号
tuple3 = 'hello',  # 尾部加逗号,认为是含一个元素的元组
tuple1[4][0] = 100  # 有元素是列表,列表含有的元素可以修改

元组的元素仍然用下标访问;元组切片与字符串相同;可以连接组合创建新的元组;元组比大小是元素逐个比大小,直到分出胜负。

print(tuple[1])
print(tuple1[:3])
tuple4 = tuple2 + tuple3
tuple5 = (1, 2, 3) * 3
True == tuple4 > tuple1

列表

列表可变, 可增删、修改元素,改变顺序等。元素可以为任意数据类型。

基本操作

建立、增删、修改、切片、比较

empty = []
list0 = ['BUAA', 'Beihang University', 2.71828, 11]
list1 = [True, False]
list0[-1] = 1111
list0 += list1  # 列表相加
list0.extend(list1)  # 与上等效
del list0[-1]  #按下标删除
list0.pop(-1)  #与上等效
list0.append([0, 1]) #增加一个元素, 与列表相加不同,此处列表整体作为一个元素添加
list2 = list0[1::2]  #切片与字符串、元组相同
['hello', 'apple'] > ['apple', 'hello']  # 列表比大小与元组相同

a += c, a = a + c对列表不同

a1 = a = b =[1, 2]
a += [3]  # a, b指向相同, 改a也改了b
a1 = a1 + [3]  # 对a1再赋值, 不影响b

列表乘法

注意中括号嵌套的规律。

print([True] * 3)  # >>[True, True, True]
a = [1]
b = a * 2  # >>[1, 1]
b = [a] * 2  # >>[[1], [1]]

排序——使用排序函数

缺省规则排序

a = [23, 1, -10, 34, 4, 3.99]
b = sorted(a)  # a不变,返回正序的a
a.sort()  # a改变,元素按正序排列
a.sort(reverse = True) # a改变,元素按倒序排列
stu = [('Lisa', 'A', 19), ('Mike', 'B', 12), ('Ann', 'C', 11), ('Emma', 'B', 14)]
stu.sort()  # 默认按名字-等级-年龄排序

元组不能改变,因此只能使用

自定义规则排序

def myKey(x):
    x % 10 / 10
a.sort(key = myKey)
s = 'A message from my hometown'
li0 = sorted(s.split(), key=str.lower)  # 不区分大小写排序
stu1 = sorted(stu, key=lambda x: x[2])  #按x[2]排序
lambda表达式
lambda x: x[2]  # 一个函数,参数是x,返回x[2]
k = lambda x, y: x + y  # k是一个函数,返回x+y
print(k(2.3, 3.7))  # >>6.0
多级排序
def k(x):
	return x[2], x[1], x[0]
stu2 = sorted(stu, key=k)

列表相关函数

基本操作

a.count(1)  # 数1出现次数
a.append([3, 5])  # 尾部加元素
a.extend([3, 5])  # 等价于a += [3, 5]
a.insert(0, 'a') # 下标处插入
a.remove('a')  # 若没有该元素,引发异常
a.reverse()  # 翻转
a.index(4)  # 查找,找不到则引发异常
a.index(4, 1)  # 可指定开始查找的下标

映射函数map(func, seq)

将一个序列seq(原像)映射到另一个序列(像),func是映射的规则。它返回一个延时求值对象,可转化为list, tuple, set…

s = [1, 3, 5]
a = map(lambda x: x + 1, s)  # a是延时求值对象
print(tuple(a))
print(list(a))
x, y, z = map(int, input().split())  
print(x, y, z)

原序列可以是多个:

q0 = [0, 1, 2]
q1 = [1, 2, 3]
q2 = [2, 3, 4]
a = list(map(lambda x, y, z: x + y + z, q0, q1, q2))
a == [3, 6, 9]

过滤函数filter(func, seq)

从序列中筛选出令func返回值是True的元素。它返回一个延时求值对象,可转化为list, tuple, set…

def func(x):
    return x % 2 == 0
a = [0, 1, 2, 3, 4, 5, 6, 7]
print(list(filter(func, a)))  # >>[0, 2, 4, 6]

列表、元组生成式

[1 for i in range(3)]  # >>[1, 1, 1]
[x**2 for x in range(3)]  # >>[0, 1, 4]
[m + n for m in 'abc' for n in 'cba']  # >>['ac', 'bb', 'ca']
w = ['a', 'b', True, 3.14, 2]
[s.upper() for i in w if isinstance(i, str)]  # >>['A', 'B']
print(tuple(x + 1 for i in range(5)))  # 元组的生成也类似,需要用tuple()函数

二维列表

一种错误的生成二维列表的方法:

a = [0, 0, 0]
b = [a] * 3  # >> [[0, 0, 0], [0, 0, 0], [0, 0, 0]] 此时,三行都指向同一个地方
b[1][1] = 1
print(b)  # >> [[0, 1, 0], [0, 1, 0], [0, 1, 0]]

生成二维列表 法1:

lst = []
for i in range(3):
    lst.append([0, 0, 0, 0])  # 3 * 4 matrix

生成二维列表 法2:

[[0 for i in range(4)] for j in range(3)]  # 3 * 4 matrix

生成二维列表 法3:

m = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

生成二维元组使用tuple()函数,方法类似。

列表拷贝

a = [1, [1, 2], 3]
b = a[:]  # 这种写法使b, a指向的对象不同
b[1][0] = 100
print(a)  # >>[1, [100, 2], 3] (因为b仅仅复制了[1, 2]的指针,因而a[1],b[1]依然指向同一个对象; b, a仍然“藕断丝连”

需要通过深拷贝,让a, b指向的对象完完全全分开。

import copy
b = copy.deepcopy(a)

列表、元组、字符串的相互转换

通过tuple()函数,转到元组;通过list()函数,转到列表;通过’’.join()函数,转到字符串。

tuple([1, 2, 3])
tuple('hello')
list((1, 2, 3))
list('hello')
str0 = ''.join([1, 2, 3])
str0 = ''.join((1, 2, 3))

字典

字典是键值对 key:value 的集合,通过key快速查找。

  • 可变数据类型不能作为key
  • 一个字典中所有元素的key各不相同
  • value可赋值,因此也是指针

基本操作

empty = {}  # empty dictionary
dt = {'mike': 18, 'lisa': 15, 'joe': 12, 312: 111, (1, 2): [4, 5]}  # keys can't be repeated
print(dt['mike'])
print(dt[(1, 2)])
print(dt['c'])  # cause exception if not exist
dt['school'] = 'buaa'  # add new element if not exist
del dt[312]  # deletion
print((1, 2) in dt)  # >>True dt中是否有key(1, 2)
dt['Joe'] = dt.get('Joe', 0) + 1  #get(key, x)函数,字典中能找到则返回value, 不能找到则返回x

构造方法

a = dict([('Jack', 18), ('Mike', 32)])
print(a)  # >>{'Jack': 18, 'Mike': 32}
b = dict(name = 'Jenny', age = 15, height = 1.75)
print(b)  # >>{'name': 'Jenny', 'age': 15, 'height': 1.75}

常用函数

dt.keys()  # 返回键的序列
dt.values()  # 返回值的序列
dt.items()  # 返回元素的序列
dt.get(key, value) 
dt.pop((1, 2))  # 删除键为(1, 2)的元素,无该元素则弹出异常
c = dt.copy()  # 浅拷贝
import copy
c = copy.deepcopy(dt)  # 深拷贝
dt.clear()  # 清空字典

上述的“序列”不是list, tuple或set类型。

eg:

dt = {'mike': 18, 'lisa': 15, 'joe': 12}
print(dt.values())  # >>dict_values([18, 15, 12])
print(dt.keys())  # >>dict_keys(['mike', 'lisa', 'joe'])
print(dt.items())  # >>dict_items([('mike', 18), ('lisa', 15), ('joe', 12)])
if 'lisa' in dt.keys():
    print(dt[lisa])
for i in dt.items(): 
    print(i[0], i[1], end=',')  # 这也是遍历字典的方式
for j, k in dt.items():
    print(j, k, end=',')

集合

  • 元素类型可不同,但必须是不可变的,而且不可变元素若包含可变元素(如包含列表的元组),也不能作为集合的元素。
  • 元素不重复
  • 可以增删元素
  • 作用是快速判断某元素是否属于这个集合(用 i n in in

其它类型向集合转换

a = set([1, 1, 2, 2, 'hi', True, 2.2])
print(a, end='')  # >>{1, 2, 2.2, 'hi'} 自动去重
b = set('banana')  # >>{'b', 'a', 'n'}

集合常用函数

a.add('wa')  # 添加元素
a.remove('wa')  # 移除,不存在则报错
a.update([1, 2])  # 序列的元素加入集合
b = a.copy()  # 浅拷贝
a.clear()  # 清空

集合的运算

A ,   B A,\,B A,B是集合,存在运算: A ∩ B ,   A ∪ B ,   A − B ,   A ⊕ B A\cap B,\,A\cup B,\,A-B,\,A\oplus B AB,AB,AB,AB

其中,

A − B = A   ∩ ∼ B A-B=A\,\cap\sim B AB=AB

A ⊕ B = ( A − B ) ∪ ( B − A ) = A ∪ B − A   ∩ B A\oplus B = (A-B)\cup(B-A)=A\cup B-A\,\cap B AB=(AB)(BA)=ABAB

python依次对应:

a = {1, 2, 3}
b = {2, 3, 5}
a & b == {2, 3}
a | b == {1, 2, 3, 5}
a - b == {1}
a ^ b == {1, 5}

增强型运算仍然可以使用, 如

a ^= {1, 3, 5}
a &= {1, 8}

a ∈ A : a \in A: aA:

True == 1 in a

集合间存在关系: A = B ,   A ≠ B ,   A ⊆ B ,   A ⊂ B A=B,\,A\neq B,\,A\subseteq B,\,A\subset B A=B,A=B,AB,AB

python依次对应:

a == b
a != b
a <= b
a < b

文件读写

打开文件

用open()函数打开文件,与C/C++类似。

file = open('D:\\text.txt', 'r+')

有以下几种模式可选

  • ‘r’——读
  • ‘rb’——二进制读
  • ‘w’——写,原先的内容会被覆盖
  • ‘wb’——二进制写
  • ‘a’——写,若文件不存在则创建
  • ‘r+’——读写
  • ‘rb+’——二进制读写

除‘a’模式外,其他模式下若文件不存在则抛出异常。

读取内容

若某文本如下:

hi!

How are you?

多行读取:

f1 = file.readlines()  # f1是列表,一行就是一个元素(带换行符)
print(f1)  # >>['hi!\n', 'How are you?']

单行读取:

while True:
    data = file.readline()
    print(data)
    if data == '':
        break

写入内容

使用write()函数写入内容。

file.write('How\'s it going?\n')

关闭文件

file.close()

文件编码

常见编码有gbk(ANSI), utf-8两种,打开文件时编码不对则不能正确读取文件。

Linux,MacOS使用utf-8缺省编码,即不指定时默认的编码规则。

.py文件必须存为utf-8编码,如果非要存为ANSI格式,文件开头要写:

#coding=gbk

open()函数可以指定编码规则,若不指定则用系统的缺省编码。

file = open('D:\\text.txt', 'r+', encoding='utf-8')
file = open('D:\\text.txt', 'r+', encoding='gbk')

文件路径

相对路径

open('readme.txt', 'r')  # 文件在当前文件夹下
open('tmp/readme.txt', 'r')  # 文件在当前文件夹的tmp文件夹里
open('../readme,txt', 'r')  # 在上一级文件夹里
open('../../readme,txt', 'r')  # 在上二级文件夹里
open('/tmp/tmp1/readme.txt', 'r')  # 在当前盘符的根文件夹下的tmp/tmp1里

相对路径是以当前文件的位置为参考位置的。一般来说,.py文件所在的文件夹,就是程序运行时的“当前文件夹”。

绝对路径

当文件路径包含盘符时,目标文件位置的确定不依赖于当前文件。

open('D:/tmp/project0/readme.txt', 'w')

文件夹操作

os和shutil库中有一些操作文件、文件夹的函数。

os.chdir(x)  # 程序当前文件夹设置为x
path = os.getcwd()  # 返回程序当前文件夹路径
fileList = os.listdir(x)  # 返回列表,列表中是x中所有文件和子文件夹的名字
os.mkdir(x)  # 创建文件夹x
os.path.exists(x)  # 判断文件/文件夹是否存在
os.path.getsize(x)  # 获取文件夹大小(字节)
os.path.isfile(x)  # 判断是不是文件
os.path.isdir(x)  # 判断是不是文件夹
os.remove(x)  # 删除文件x
os.rmdir(x)  # 删除空文件夹x,必须为空才能删除成功
os.rename(x, y)  # 重命名文件,同时还可以移动文件
shutil.copyfile(x, y)  # 拷贝文件x到文件y,若y存在则会被覆盖

综合1:连根删除一个非空文件夹

import os
def delDir(path):
    list0 = os.listdir(path)
    for i in list0:
        i = path + '/' + i
        if os.path.isfile(i):
            os.remove(i)
        else:
            delDir(i)
    os.rmdir(path)

综合2:获取一个文件夹的大小

import os
def getDirSize(path):
    size = 0
    list0 = os.listdir(path)
    for i in list0:
        i = path + '/' + i
        if os.path.isfile(i):
            size += os.path.getsize(i)
        else:
            size += getDirSize(i)
    return size

命令行运行程序

在命令行窗口输入:

python xxx.py

就能运行程序。

但是有的程序需要提供外部命令行参数。比如合成A.txt和B.txt的程序,用命令行运行:

python xxx.py 'A.txt' 'B.txt'

命令行参数存在sys.argv里。写python程序时通过sys.argv读取命令行参数。

sys.argv[0] == 'A.txt'
sys.argv[1] == 'C.txt'

面向对象程序设计

类的基础构造

python中的类定义实例:

import math


class Circle:
    def __init__(self, x, y, radius):  # 每个类必有的构造函数__init__
        self.x, self.y, self.radius = x, y, radius  # 成员在此处定义并赋值
        
    def getSquare(self):
        return math.pi * self.radius * self.radius
    
    def getCir(self):
        return 2 * math.pi * self.radius
    
    
c = Circle(4, 6, 1)  # 生成对象
print(c.getSquare())

类的方法若引用非静态属性、方法要有self作为参数,self指向对象自己。引用对象的属性时用 self.参数 引用。

实际上,python除了整数常量以外,复数、小数、字符串、元组、集合、字典的常量都是对象。各种库(模块)都是由类构成。

类的比较

内置类的比较

  • x == y——__eq__(equal)

python中所有的类都有__eq__方法。x==y的值,就是x.__eq__(y)的值,若无定义则是y.__eq__(x)的值,若二者都无定义,则x == y也没有定义。下面也同理,

  • x < y——__lt__(less than)
  • x <= y——__le__(less or equal)
  • x > y——__gt__(greater than)
  • x >= y——__ge__(greater or equal)

因为整数常量不是对象,所以这不适用于整数常量。

自定义类的比较

  • 默认情况下,自定义类的__eq__功能是判断两个对象的id是否相同。也就是对于一个没有重写__eq__的自定义类,x == y和 x is y是等价的。
  • 默认情况下,自定义类的__lt__、__le__、__gt__、__ge__都被设为None,于是默认两个对象不能用<, <=, >, >=比较大小。

但是通过重写这些方法,可让自定义类的对象可以用<, <=, >, >=比较大小:

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.radius == other.radius

    def __ge__(self, other):
        return self.radius >= other.radius


c1 = Circle(2, 3, 5)
c2 = Circle(2, 3, 5)
c3 = Circle(1, 1, 4)
print(c1 == c2)  # >>True
print(c1 >= c3, end='')  # >>True

继承和派生

class Cylinder(Circle):  # 继承,小括号里是父类
    def __init__(self, x, y, r, h):
        Circle.__init__(x, y, r)
        self.height = h

    def getVolume(self):
        return Circle.getSquare() * self.height

    def getSuperficialArea(self):
        return 2 * Circle.getSquare() + self.height * Circle.getCir()

其实所有类都是object类的派生类,因此具有object类的所有方法:

print(dir(Cylinder))  # >>['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

静态属性和方法

  • 静态属性在类中定义,只有一个,被类创建出的所有对象共享。
  • 静态方法不作用于具体对象,不能访问非静态属性。
  • 静态属性和静态方法的存在是为了高度封装,减少全局变量和全局函数的使用。
class Activity:
    total = 0  # 静态属性
    spendSum = 0  # 静态属性

    def __init__(self, time, loc, spend):
        self.time, self.loc, self.spend = time, loc, spend

    def conduct(self):
        Activity.total += 1  # 区别于非静态属性,静态属性用类名调用
        Activity.spendSum += self.spend

    @staticmethod  # 静态方法
    def printStatics():
        print(Activity.total, Activity.spendSum)
        

a1 = Activity('2021.5.23', 'abc square', 1000)
a2 = Activity('2022.1.1', 'aaa square', 500)
a1.conduct()
Activity.printStatics()  # >>1 1000  区别于非静态方法用对象名调用,静态方法用类名调用
a2.conduct()
Activity.printStatics()  # >>2 1500

建立可哈希对象

内置类的哈希

x可哈希,即hash(x)有定义。

对于整型常量, hash(x) = x

其他:hash(x) = x.__hash__() [object类有这个方法]

只有可哈希的对象才能作为字典的键、集合的元素。列表、集合、字典的__hash__被设为None,因此不可哈希,不能作为字典的键或集合的元素。

eg(计算一些可哈希对象的哈希值):

print(3.14.__hash__())  # >> 322818021289917443
print(2+3j.__hash__())  # >> 3000011
print('hello, world!'.__hash__())  # >> -3904558826133324077
print((1, 2, True, 'a', 3.1).__hash__())  # >> -5065489019475364519

字典和集合的底层实现是哈希表:

元素都放在“槽”里,“槽”编号即元素哈希值hash(x). 哈希碰撞的元素存在同一个“槽"里。

找dt[x]时,先计算hash(x), 得到“槽’'编号;若槽空,则不存在;若槽不空,把槽里面存在的元素的key与x一一比对,吻合则提取出value,都不吻合则不存在。

自定义类的哈希

默认自定义类的对象的哈希是根据对象id来计算。即对某对象a,hash(a) = hash(id(a))

即只要a is b == False,a和b就能共存于一个集合,或作为字典里不同元素的键。

可以重写__hash__使自定义对象的哈希值与对象的属性绑定。

    def __hash__(self):
        return self.loc.__hash__()

如果重写了__eq__但没有重写__hash__,此时__hash__会自动设置成None,变得不可哈希了。因此只有重写了__eq__但没有重写__hash__的自定义类是不可哈希的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值