Python3开发笔记(简洁版)

一、开发编辑器

1. pycharm

2. IDLE(Python自带软件)

方法:Microsoft Store搜索 Python 安装

二、数据类型

  • Python中有以下几种主要的数据类型:
    数字(Numbers)、
    字符串(Strings)、
    布尔值(Boolean)、
    空值(None)、
    列表(Lists)、
    元组(Tuples)、
    字典(Dictionaries)、
    集合(Sets)。

1. 数字(Numbers)

  • 在Python中,number数据类型可以分为以下几种:整数、浮点数、复数。
# 整数  
num1 = 42 #【注:python定义变量的方式很简单,通过变量名 = 数据,即可定义一个变量】
num2 = 0b0110 #【注:在Python中,二进制整数使用前缀0b表示】  # 浮点数  
num3 = 3.14159  # 复数  
num4 = 3+4j

整数、浮点数可以直接进行四则运算:

# 加法
num1 = 10 
num2 = 0.5
result = num1 + num2
print(result) # ==> 10.5
# 减法
result = num1 - num2
print(result) # ==> 9.5
# 乘法
result = num1 * num2
print(result) # ==> 5.0
# 除法
result = num1 / num2
print(result) # ==>20.0

取模运算

print(3 % 2) # ==> 1
print(33 % 10) # ==> 3
print(99 % 30) # ==> 9

地板除

  • Python除了普通除法以外,还有一个特殊的除法被称为地板除,对于地板除,结果会忽略纯小数的部分,得到整数的部分,地板除使用//进行。
10//4 # ==> 2
10//2.5 # ==> 4.0
10//3 # ==> 3

小数点位数

  • 使用Python计算小数的时候,经常需要保留小数点后若干位,可以使用round()函数来处理,这里先了解round的调用方式,使用两个参数,第一个是需要保留小数点位数的数值,第二个是保留的位数。
num = 10 / 3
print(num) # ==> 3.3333333333333335
# 使用round保留两位小数
round(num, 2) # ==> 3.33

2. 字符串(Strings)

#定义一个字符串str变量
str = "Hello, World!"# 字符串模板
template = 'Hello {}'
# 模板数据内容
world = 'World'
result = template.format(world)
print(result) # ==> Hello World#读取字符串某个值
s = 'ABC'
a = s[0] # 第一个
b = s[1] # 第二个
c = s[2] # 第三个
print(a) # ==> A
print(b) # ==> B
print(c) # ==> C#字符串切片
s1 = 'ABCDEFGHIJK'
abcd = s1[0:4] # 取字符串s1中的第一个字符到第五个字符,不包括第五个字符
print(abcd) # ==> ABCD

3. 布尔值(Boolean)

b1 = True #【在Python中,布尔值True和False都是关键字,首字母需要大写】
b2 = False #【布尔值可以用and、or和not运算(注意and,or,not都是Python语言本身的关键字)】

与运算:只有两个布尔值都为 True 时,计算结果才为 True。
或运算:只要有一个布尔值为 True,计算结果就是 True。
非运算:把True变为False,或者把False变为True:

#举例
True and True # ==> True
True and False # ==> False
True or True # ==> True
True or False # ==> True
not True # ==> False
not False # ==> True

4. 空值(None)

# 空值
n = None # 【在Python中,None表示空值,它是一个特殊的类型,叫做NoneType】

5. 列表(Lists)

  • 列表(list)是一种有序的容器,放入list中的元素,将会按照一定顺序排列。构造list的方法非常简单,使用中括号[]把需要放在容器里面的元素括起来,就定义了一个列表。
scores = [45, 60, 75, 86, 49, 100]
names = ['Alice', 'Bob', 'David', 'Ellena'] # 注意,字符串元素仍需要引号
L = ['Alice', 66, 'Bob', True, 'False', 100]
  • 列表是有序的,因此我们可以按顺序访问列表中的元素。
L = ['Alice', 66, 'Bob', True, 'False', 100]
for item in L:print(item)#获取L中第二个元素
print(L[1]) #66#使用-1来获取最后一个元素
print(L[-1]) #100#使用索引的方式访问列表时,一定要特别注意不要越界
print(L[10]) # IndexError: list index out of range#列表和字符串一样,也支持切片
print(L[0:2]) #['Alice', 66]
  • 向list添加新的元素
names = ['Alice', 'Bob', 'David', 'Ellena']
names.append('Candy') # append()方法:追加到列表的末尾
print(names) # ==> ['Alice', 'Bob', 'David', 'Ellena', 'Candy']
names.insert(2, 'LBJ') # insert()方法需要两个参数,分别是需要插入的位置,以及需要插入的元素
print(names) # ==> ['Alice', 'Bob', 'LBJ', 'David', 'Ellena', 'Candy']
  • 从list删除元素
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name = L.pop() # pop()方法默认删除列表的最后一个元素,并返回
print(name) # ==> Ellena
print(L) # ==> L = ['Alice', 'Bob', 'Candy', 'David']
name2 = L.pop(2) # pop()还可以接收一个参数,指定需要删除的元素的位置
print(L) # ==> L = ['Alice', 'Bob', 'David']
  • 替换list中的元素
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
L[2] = 'Canlina'
print(L) # ['Alice', 'Bob', 'Canlina', 'David', 'Ellena']

6. 元组(Tuples)

  • 元组(tuple)和list一样,也是一个有序容器,在元组中,同样可以包含0个或者多个元素,并且也支持索引访问、切片等操作。
  • 定义元组的方式是使用小括号()将元组内的元素括起来。
T = ('Alice', 'Bob', 'Candy', 'David', 'Ellena')
# 通过下标的方式访问元素
print(T[0]) # ==> Alice
print(T[4]) # ==> Ellena
# 切片
print(T[1:3]) # ==> ('Bob', 'Candy')
  • tuple和list不一样的是,tuple是固定不变的,一旦变成tuple,tuple中的每一个元素都不可被改变,同时也不能再往tuple中添加数据,而list是可以的。【请注意,元组的这个特性是非常重要的,在运行上tuple的性能是list的数倍。】
T = ('Alice', 'Bob', 'Candy', 'David', 'Ellena')
# 替换元素
T[1] = 'Boby' # TypeError: 'tuple' object does not support item assignment
  • 元组类型和列表类型相互转换
L = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
T = tuple(L)
print(T) # ==> ('Alice', 'Bob', 'Candy', 'David', 'Ellena')
L2 = list(T)
print(L2) # ==> ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
  • tuple元素的其他方法

(1)count:用来统计tuple中某个元素出现的次数。


T = (1, 1, 2, 2, 3, 3, 1, 3, 5, 7, 9)
print(T.count(1)) # ==> 3
print(T.count(5)) # ==> 1#对于不存在的元素,count方法不会报错,而是返回0,这是合理的,因为元组里面有0个不存在的元素。
print(T.count(10)) # ==> 0

(2)index:可以返回指定元素的下标,当一个元素多次重复出现时,则返回第一次出现的下标位置。

T = (1, 1, 2, 2, 3, 3, 1, 3, 5, 7, 9)
T.index(9) # ==> 10
T.index(5) # ==> 8
T.index(1) # ==> 0 # 多次出现,返回第一次出现的位置#注意,index()方法和count()方法不一样,当指定的元素不存在时,使用index()方法Python会报错。
T.index(100)
# 报错 ValueError: tuple.index(x): x not in tuple
  • 要定义只有一个元素的tuple,需要在元素后面添加一个逗号
T = (1, )
print(T) # ==> (1, )
  • tuple的元素也可以是tuple
T = ((1+2),  ((1+2),), ('a'+'b'), (1, ), (1,2,3,4,5))
print(len(T)) # 5
  • 对于tuple,它和list一个最大的不同点就是tuple是不可变的,tuple里面的元素,也是不可替换的。但是这针对的是仅包含基础数据类型(数字类型、布尔类型、字符串类型)的数据,对于组合数据类型,则不受这个约束。
T = (1, 'CH', [3, 4])
L = T[2]
print(L) # ==> [3, 4]
# 尝试替换L中的元素
L[1] = 40
print(L) # ==> [3, 40]
print(T) # ==> (1, 'CH', [3, 40])

7. 字典(Dictionaries)

  • 在dict中,每一项包含一个key和一个value,key和value是一一对应的

(1)读取dict元素

d = {'Alice': 45,'Bob': 60,'Candy': 75,'David': 86,'Ellena': 49,'Gaven': 86
}
print(d['Bob']) # ==> 60
print(d['Alice']) # ==> 45
print(d['Dodo']) # 报错:KeyError: 'Dodo'# get方法读取【推荐】
# print(d.get('Dodo')) # ==> None 【dict本身提供get方法,把key当作参数传递给get方法,
# 就可以获取对应的value,当key不存在时,也不会报错,而是返回None】

(2)添加dict元素

d = {'Alice': 45,'Bob': 60,'Candy': 75,'David': 86,'Ellena': 49
}
d['Alice'] = 100 # Alice存在,将被替换
d['Dodo'] = 88
d['Mimi'] = [72, 73]
d['Mimi'].append(75)
print(d)

(3)删除dict元素

  • pop()方法需要指定需要删除的元素的key,当key不存在时,同样会引起错误。
d = {'Alice': 45,'Bob': 60,'Candy': 75,'David': 86,'Ellena': 49
}
d.pop('Alice')
print(d)
d.pop('LBJ') # 报错 KeyError: 'LBJ'

(4)dict的特点

  • 查找速度快
  • dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样。而list的查找速度随着元素增加而逐渐下降。
  • 不过dict的查找速度快不是没有代价的,dict的缺点是占用内存大,还会浪费很多内容,list正好相反,占用内存小,但是查找速度慢。
  • key不可变

tuple是不可变的,list是可变的,因此tuple可以作为dict的key,但是list不可以作为dict的key,否则将会报错。

d = {'Alice': 45,'Bob': 60,'Candy': 75,'David': 86,'Ellena': 49
}
key = (1, 2, 3) # 以tuple作为key
d[key] = True
print(d) # {'Alice': 45, 'Bob': 60, 'Candy': 75, 'David': 86, 'Ellena': 49, (1, 2, 3): True}
key2 = [1, 2, 3]
d[key2] = True # 报错 TypeError: unhashable type: 'list'
  • 遍历dict

遍历dict有两种方法, 第一种是遍历dict的所有key,并通过key获得对应的value。

d = {'Alice': 45,'Bob': 60,'Candy': 75,'David': 86,'Ellena': 49
}
for key in d: value = d[key]if value > 60:print(key, value)
# ==> Candy 75
# ==> David 86

第二种方法是通过dict提供的items()方法,items()方法会返回dict中所有的元素,每个元素包含key和value。

for key, value in d.items():if value > 60:print(key, value)
# ==> Candy 75
# ==> David 86

(5)dict的其他方法

  • 获取dict的所有key

dict提供keys()函数,可以返回dict中所有的key。

d = {'Alice': [50, 61, 66], 'Bob': [80, 61, 66], 'Candy': [88, 75, 90]}
for key in d.keys():print(key)
# ==> Alice
# ==> Bob
# ==> Candy
  • 获取dict所有的value

dict提供values()函数,可以返回dict中所有的value。

d = {'Alice': [50, 61, 66], 'Bob': [80, 61, 66], 'Candy': [88, 75, 90]}
for key in d.values():print(key)
# ==> [50, 61, 66]
# ==> [80, 61, 66]
# ==> [88, 75, 90]
  • 清除所有元素

dict提供clear()函数,可以直接清除dict中所有的元素。

d = {'Alice': [50, 61, 66], 'Bob': [80, 61, 66], 'Candy': [88, 75, 90]}
d.clear()
print(d) # ==> {}

8. 集合(Sets)

  • set和list类似,拥有一系列元素,但是set和list不一样,set里面的元素是不允许重复的,并且,set里面的元素是没有顺序的。
s = set([1, 4, 3, 2, 5, 4, 2, 3, 1])
print(s) # ==> set([1, 2, 3, 4, 5])

(1)读取set元素

由于set里面的元素是没有顺序的,因此我们不能像list那样通过索引来访问。访问set中的某个元素实际上就是判断一个元素是否在set中,这个时候我们可以使用in来判断某个元素是否在set中。

s = set([1, 4, 3, 2, 5, 4, 2, 3, 1])
print(1 in s) #True
print(6 in s) #False

(2)添加set元素

names = ['Alice', 'Bob', 'Candy', 'David', 'Ellena']
name_set = set(names)
name_set.add('Gina') #add:逐个添加
print(name_set) # ==> set(['Gina', 'Alice', 'Candy', 'David', 'Ellena', 'Bob'])new_names = ['Hally', 'Isen', 'Jenny', 'Karl']
name_set.update(new_names) #update:批量添加
print(name_set) # ==> set(['Gina', 'Karl', 'Bob', 'Hally', 'Jenny', 'Alice', 'David', 'Isen', 'Ellena', 'Candy'])

(3)删除set元素

set提供了remove()方法允许我们删除set中的元素。如果remove的元素不在set里面的话,那么将会引发错误。

name_set = set(['Jenny', 'Ellena', 'Alice'])
name_set.remove('Jenny')
print(name_set) # ==> set(['Ellena', 'Alice'])

(4)set的其他方法

  • 不会报错的删除方法discard()
name_set = set(['Jenny', 'Ellena', 'Alice'])
name_set.discard('LBJ')
print(name_set) # ==> set(['Jenny','Ellena', 'Alice'])
  • 清除所有元素的方法clear()

和dict一样,set也提供了clear()方法,可以快速清除set中的所有元素。

name_set = set(['Jenny', 'Ellena', 'Alice'])
name_set.clear()
print(name_set) # ==> set([])
  • 集合的子集和超集

set提供方法判断两个set之间的关系,比如两个集合set,判断其中一个set是否为另外一个set的子集或者超集。

s1 = set([1, 2, 3, 4, 5])
s2 = set([1, 2, 3, 4, 5, 6, 7, 8, 9])
# 判断s1是否为s2的子集
s1.issubset(s2) # ==> True
# 判断s2是否为s1的超集
s2.issuperset(s1) # ==> True
  • 判断集合是否重合

isdisjoint:用于检查两个集合是否完全独立,即它们没有任何共同的元素。

set1 = {1, 2, 3}  
set2 = {4, 5, 6}  
print(set1.isdisjoint(set2))  # 输出:True  set3 = {2, 4, 6}  
print(set1.isdisjoint(set3))  # 输出:False

【扩展】:使用type,可以区分不同的数据类型

print(type(3.1415926))
print(type('Learn Python in imooc.'))
print(type(100))
print(type(0b1101))
print(type([1,2,3]))
'''
结果:
<class 'float'>
<class 'str'>
<class 'int'>
<class 'int'>
<class 'list'>
'''

三、循环控制语句

1. if-else相关:

score = 59
if score < 60:print('抱歉,考试不及格')
else:if score >= 90:print('恭喜你,拿到卓越的成绩')else:if score >= 80:print('恭喜你,拿到优秀的成绩')else:print('恭喜你,考试及格')

可以使用if-elif-else语句来简化以上的逻辑。其中elif就是else if的意思。

score = 59
if score < 60:print('抱歉,考试不及格')
elif score >= 90:print('恭喜你,拿到卓越的成绩')
elif score >= 80:print('恭喜你,拿到优秀的成绩')
else:print('恭喜你,考试及格')

2. for循环

s = 'ABCD'
for item in s:print(item) # 注意缩进

3. while循环

  • 计算1~100的和
num = 1
sum = 0
while num <= 100:sum = sum + num # 注意缩进num = num + 1 # 注意缩进
print(sum) # ==> 5050
  • 计算0~1000以内,所有偶数的和
num = 1
sum = 0
while True:if num > 1000:breakif num % 2 == 0: sum = sum + numnum = num + 1
print(sum) # 250500
  • 输出字符串s中第10个以后的字符
s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
num = 1
for ch in s:if num < 10:num = num + 1continue # 当num < 10时,跳过后续循环代码,继续下一次for循环print(ch)num = num + 1

4. 嵌套循环

s1 = 'ABC'
s2 = '123'
for x in s1:for y in s2:print(x + y)
'''
结果:
A1
A2
A3
B1
B2
B3
C1
C2
C3
'''

四、函数

1. 定义函数

  • 在Python中,定义一个函数要使用 def 语句,依次写出函数名、括号()、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。
def fn(x):if x >= 0:return xelse:return -x
result = fn(1)
print(1)

2. 递归函数

  • 计算n的阶乘
def fact(n):if n==1:return 1return n * fact(n - 1)
res = fact(5)
print(res) #120

我们可以拆解fact(5)计算的详细逻辑:

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

五、面向对象编程

1. 类的定义与实例化

class Person(object): pass
xiaohong = Person()
xiaoming = Person()
  • 在Python中,pass是一个空操作语句,意思是什么都不做。pass常常用在定义一个空的类、函数、循环或条件语句等场合。

  • 在以上的代码中,pass不能删除。pass是Python语法的一部分,用于定义一个空的类(如Person)。如果删除pass,Python解释器会报错,因为这不符合Python的语法规则。

  • 当你创建类的实例时,如xiaohong = Person()和xiaoming = Person(),你实际上是在调用Person类的构造方法(如果定义了的话),然后创建了两个新的Person对象。这些对象是独立的,它们的属性不会互相影响。

  • 如果你删除pass,你需要在类中定义一个构造方法(使用__init__方法),并在这个构造方法中初始化你想要的属性。例如:

class Person(object):def __init__(self, name, sex, age):self.name = nameself.sex = sexself.age = age
xiaoming = Person('Xiao Ming', 'boy', 13)
xiaohong = Person('Xiao Hong', 'girl', 14)
print(xiaohong.name) # Xiao Hong
print(xiaohong.sex) # girl
print(xiaohong.age) # 14
# 但当访问不存在的属性时,依然会报错
print(xiaohong.birth)
  • 以上需要注意的是,init() 方法的第一个参数必须是 self(此处self不能省略,self 也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定,和定义函数没有任何区别。定义类后,就可以相应的实例化对象了,需要注意的是,在实例化的时候,需要提供除self以外的所有参数。

2. 类属性

在前面,实例对象绑定的属性只属于这个实例,绑定在一个实例上的属性不会影响其它实例;同样的,类也可以绑定属性,但是类的属性不属于任何一个对象,而是属于这个类。如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。

定义类属性可以直接在 class 中定义,比如在Animal类中,加入地域的类属性:

class Animal(object):localtion = 'Asia'def __init__(self, name, age):self.name = nameself.age = age

在上面的代码中,localtion就是属于Animal这个类的类属性,此后,通过Animal()实例化的所有对象,都可以访问到localtion,并且得到唯一的结果。

dog = Animal('wangwang', 1)
cat = Animal('mimi', 3)
print(dog.localtion) # ==> Asia
print(cat.localtion) # ==> Asia
# 类属性,也可以通过类名直接访问
print(Animal.localtion) # ==> Asia

类属性也是可以动态添加和修改的,需要注意的是,因为类属性只有一份,所以改变了,所有实例可以访问到的类属性都会变更:

Animal.localtion = 'Africa'
print(cat.localtion) # ==>Africa
print(dog.localtion) # ==>Africa
  • 案例:请给 Animal类添加一个类属性 count,每创建一个实例,count 属性就加 1,这样就可以统计出一共创建了多少个 Animal的实例。
class Animal():count = 0def __init__(self,name,age):Animal.count+=1 # 每创建一个实例,count 属性就加 1self.name = nameself.age = age
dog = Animal('dog',2)
cat = Animal('cat',3)
print(Animal.count) #2

3. 类属性和实例属性的优先级

可以看到,属性可以分为类属性和实例属性,那么问题就来了,如果类属性和实例属性名字相同时,会怎么样?

class Animal(object):localtion = 'Asia'def __init__(self, name, age, localtion):self.name = nameself.age = ageself.localtion = localtion
dog = Animal('wangwang', 1, 'GuangDong')
cat = Animal('mimi', 3, 'ChongQing')
print(dog.localtion) # ==> GuangDong
print(cat.localtion) # ==> ChongQing
print(Animal.localtion) # ==> Asia

可见,在类属性和实例属性同时存在的情况下,实例属性的优先级是要高于类属性的,在操作实例的时候,优先是操作实例的属性。

那通过实例,可不可以修改类属性呢?我们来尝试一下:

cat.localtion = 'Africa'
print(Animal.localtion) # ==> Asia

这里依然打印了Asia,可见通过实例是无法修改类的属性的,事实上,通过实例方法修改类属性,只是给实例绑定了一个对应的实例属性:

# 新增的实例属性
print(cat.localtion) # ==> Africa

因此,需要特别注意,尽量不要通过实例来修改类属性,否则很容易引发意想不到的错误。

4. 属性访问限制

并不是所有的属性都可以被外部访问的,这种不能被外部访问的属性称为私有属性。私有属性是以双下划线’_ _'开头的属性。

  • 类私有属性
class Animal(object):__localtion = 'Asia'print(Animal.__localtion) # 报错 AttributeError: type object 'Animal' has no attribute '__localtion'
  • 实例私有属性
class Animal(object):def __init__(self, name, age, localtion):self.name = nameself.age = ageself.__localtion = localtiondog = Animal('wangwang', 1, 'GuangDong')
print(dog.name) # ==> wangwang
print(dog.age) # ==> 1
print(dog.__localtion) # 报错 AttributeError: 'Animal' object has no attribute '__localtion'

在外部访问私有属性将会抛出异常,提示没有这个属性。虽然私有属性无法从外部访问,但是,从类的内部是可以访问的。私有属性是为了保护类或实例属性不被外部污染而设计的。

5. 定义实例方法

前面提到,私有属性没有办法从外部访问,只能在类的内部操作;那如果外部需要操作私有属性怎么办?这个时候可以通过定义类或者实例的方法来操作私有属性。

实例的方法指的就是在类中定义的函数,实例方法的第一个参数永远都是self,self是一个引用,指向调用该方法的实例对象本身,除此以外,其他参数和普通函数是完全一样的。

class Person(object):def __init__(self, name):self.__name = namedef get_name(self):return self.__name

在上面的定义,name是实例的私有属性,从外部是无法访问的,而get_name(self) 就是一个实例方法,在实例方法里面是可以操作私有属性的,注意,它的第一个参数是self。

另外,init(self, name)其实也可看做是一个特殊的实例方法。通过定义get_name(self)方法,在外部就可以通过这个方法访问私有属性了。

​p = Person('Alice')
print(p.get_name()) # ==> Alice

6. 定义类方法

为了操作实例对象的私有属性,我们定义了实例方法;同样的,如果需要需要操作类的私有属性,则应该定义类的方法。默认的,在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。

要在class中定义类方法,需要这么写:

class Animal(object):__localtion = 'Asia'def __init__(self, name, age):self.name = nameself.age = age@classmethoddef set_localtion(cls, localtion):cls.__localtion = localtion@classmethoddef get_localtion(cls):return cls.__localtionprint(Animal.get_localtion()) # ==> Asia
Animal.set_localtion('Afica')
print(Animal.get_localtion()) # ==> Africa

和实例方法不同的是,这里有两点需要特别注意:

  • 类方法需要使用@classmethod来标记为类方法,否则定义的还是实例方法
  • 类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.__localtion 实际上相当于Animal.__localtion。

六、类的继承

1. 继承类

对人类的抽象可以定义为Person类,而学生、老师等,也都是人类,所以,在Python当中,如果定义学生Student的类,可以继承Person类。

class Person(object):def __init__(self, name, gender):self.name = nameself.gender = gender

接着定义Student类,在定义Student类的时候,由于继承了Person类,所以Student类自动拥有name、gender属性,因此,在定义Student类的时候,只需要把额外的属性加上即可。

class Student(Person):def __init__(self, name, gender, score):super(Student, self).__init__(name, gender)self.score = scorestudent = Student('Alice', 'girl', 100)
print(student.name) # ==> Alice
print(student.gender) # ==> girl
print(student.score) # ==> 100

在定义继承类的时候,有两点是需要【注意】的:

  • class Student()定义的时候,需要在括号内写明继承的类Person
  • 在__init__()方法,需要调用super(Student, self).init(name, gender),来初始化从父类继承过来的属性

2.判断类型

随着我们学习步伐的前进,我们的程序会出现越来越多的类型,有我们自己定义的类,也有Python自有的str、list、dict等,他们的本质都是都是Python中的一种数据类型,这时有必要去判断数据的类型,通过函数isinstance()可以判断一个变量的类型

class Person(object):def __init__(self, name, gender):self.name = nameself.gender = genderclass Student(Person):def __init__(self, name, gender, score):super(Student, self).__init__(name, gender)self.score = scoreclass Teacher(Person):def __init__(self, name, gender, course):super(Teacher, self).__init__(name, gender)self.course = coursep = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')
print(isinstance(p, Person)) # True,p是Person类型
print(isinstance(p, Student)) # False,p不是Student类型
print(isinstance(p, Teacher)) # False,p不是Teacher类型print(isinstance(s, Person)) #True,s是Person类型
print(isinstance(s, Student)) #True,s是Student类型
print(isinstance(s, Teacher)) #False,s不是Teacher类型

s 是Student类型,不是Teacher类型,这很容易理解。但是,s 也是Person类型,因为Student继承自Person,虽然它比Person多了一些属性和方法,但是,把 s 看成Person的实例也是可以的。

这说明在一条继承链上,一个实例可以看成它本身的类型,也可以看成它父类的类型。

isinstance也可以用于Python自有数据类型的判断。

s = 'this is a string.'
n = 10
print(isinstance(s, str)) # ==> True
print(isinstance(n, str)) # ==> False

3.多态

类具有继承关系,并且子类类型可以向上转型看做父类类型,如果我们从 Person 派生出 Student和Teacher ,并都写了一个who() 方法:

class Person(object):def __init__(self, name, gender):self.name = nameself.gender = genderdef who(self):return 'I am a Person, my name is %s' % self.nameclass Student(Person):def __init__(self, name, gender, score):super(Student, self).__init__(name, gender)self.score = scoredef who(self):return 'I am a Student, my name is %s' % self.nameclass Teacher(Person):def __init__(self, name, gender, course):super(Teacher, self).__init__(name, gender)self.course = coursedef who(self):return 'I am a Teacher, my name is %s' % self.name
class Boss(Person):def __init__(self, name, gender,company):super(Boss, self).__init__(name, gender)self.company = companyp = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')
b = Boss('Bob', 'Male', 'Alibaba')
print(p.who()) # I am a Person, my name is Tim
print(s.who()) # I am a Student, my name is Bob
print(t.who()) # I am a Teacher, my name is Alice
print(b.who()) # ==> I am a Person, my name is Bob

这种行为称为多态。从定义上来讲,Student和Teacher都拥有来自父类Person继承的who()方法,以及自己定义的who()方法。但是在实际调用的时候,会首先查找自身的定义,如果自身有定义,则优先使用自己定义的函数;如果没有定义,则顺着继承链向上找。

七、类的特殊方法

1. 类的__str__方法

对于Python的内建对象,比如int、dict、list等,通过str()方法,可以把这些对象转换为字符串对象输出。

num = 12
str(num) # ==> '12'
d = {1: 1, 2: 2}
str(d) # ==> '{1: 1, 2: 2}'
l = [1,2,3,4,5]
str(l) # ==> '[1, 2, 3, 4, 5]'

2. 类的__slots__方法

由于Python是动态语言,任何实例在运行期都可以动态地添加属性。比如:

class Student(object):def __init__(self, name, gender, score):self.name = nameself.gender = genderself.score = score

此时,Student类有三个属性,name、gender、score,由于是动态语言,在运行时,可以随意添加属性。

student = Student('Bob', 'Male', 99)
student.age = 12 # ==> 动态添加年龄age属性

如果要限制添加的属性,例如,Student类只允许添加 name、gender和score 这3个属性,就可以利用Python的一个特殊的__slots__来实现。

class Student(object):__slots__ = ('name', 'gender', 'score')def __init__(self, name, gender, score):self.name = nameself.gender = genderself.score = score
student = Student('Bob', 'Male', 99)
student.age = 12 # AttributeError: 'Student' object has no attribute 'age'

3. 类的其他方法

在Python中,类似于__str__方法的特殊方法还有很多。这些特殊方法通常被称为“魔法方法”或“双下划线方法”。比如:

  • repr:返回一个对象的“官方”字符串表示形式。与__str__不同,__repr__的返回值应该是一个精确的、无歧义的字符串表示形式,用于调试和开发。
  • eq:定义对象的相等性比较操作(例如obj1 == obj2)。该方法应返回一个布尔值,表示两个对象是否相等。
  • iter:使对象成为可迭代的。该方法应返回一个迭代器对象,用于遍历对象的元素。
  • getitem:使得对象支持下标操作(例如obj[index])。该方法用于获取指定索引处的元素。
  • setitem:使得对象支持下标赋值操作(例如obj[index] = value)。该方法用于设置指定索引处的元素值。
  • delitem:使得对象支持下标删除操作(例如del obj[index])。该方法用于删除指定索引处的元素。

八、模块

1. 创建模块

Python语言本身提供了非常多的模块,比如数学模块math、cmath、decimal、statistics;文件模块pathlib、stat、shutil等;除了使用官方模块,有时候也需要自定义模块。

如果我们需要创建一个tools模块,用来实现众多的工具函数,那么我们可以创建一个tools.py的文件,并在这个文件里面实现一些函数,如:say_hello()函数、say_goodbye()函数。

# tools.py
def say_hello():print('hello')def say_goodbye():print('goodbye')

2. 导入模块

(1)导入官方模块

Python使用import语句导入一个模块,导入官方模块,不需要考虑路径的问题,例如,导入系统自带的模块 math,直接导入即可。

import math

导入以后,你就可以认为math是一个指向已导入模块的变量,通过该变量,我们可以访问math模块中所定义的所有公开的函数、变量和类:

# 属性:圆周率
import math
print(math.pi) # 3.141592653589793# 函数:次方
print(math.pow(2, 3)) # 8.0

如果希望导入模块的指定部分属性或函数,那么使用from…import…语句。

# 属性:圆周率
from math import pi
print(pi) # 3.141592653589793

这个时候,由于pow()函数没有导入,所以是不能使用pow()函数的。如果希望导入模块里面的所有内容,那么使用from …import *语句。

from math import *
print(pi) # 3.141592653589793
print(pow(2, 3)) # 8.0

如果从一个模块导入函数,有可能会遇到导入的函数与本文件的函数冲突的情况。例如:本文件定义了一个pow()函数,同时从math模块也导入了一个pow()函数,这种情况下就会引起冲突;事实上,这种冲突的情况经常发生。

有两种方法可以解决这个问题,第一种是直接导入模块,不指定导入模块里面的具体内容;第二种方法就是使用from … import as …语句,as类似重命名,可以把导入的函数或属性重命名为别的名字。

from math import pow as mathpow
print(mathpow(2, 3)) # 8.0
(2)导入自定义模块

在pycharm中,创建了demo.py模块如下:

# demo.py模块
def say_hello():print('say_hello')

假如想要在demo2模块中导入demo模块,但不知道demo在哪个文件夹目录下,此时有2种方法:

  • 使用__file__属性:这个属性可以返回模块文件的路径。但是,这个方法并不总是有效,特别是当模块是内置的或者是在某种特殊的环境中加载的时候。
import demo
print(demo.__file__) # E:\myProject\python_project\pythonProject\demo.py
  • 使用os模块的path.abspath()函数:可以返回给定文件或目录的绝对路径。
import os
import demo
print(os.path.abspath(demo.__file__)) # E:\myProject\python_project\pythonProject\demo.py

这样,我们得到demo.py模块的路径后,就可以再demo2进行导入使用了:

import sys
sys.path.append('E:\\myProject\\python_project\\pythonProject') # 添加模块demo所在的目录到系统路径中 
import demo
demo.say_hello()

九、输入内容

到目前为止,我们编写的程序都是直接运行的,在运行过程中并没有接收程序外部的输入。

如果想向Python程序输入内容,使用input()函数即可接收外部的输入。如:

num = input('please input number: ')
print(num) 
print(type(num))

IDLE运行,效果如下:
在这里插入图片描述
注意:input()函数中,输入的是字符串,有时候需要转型为数字类型,否则会报错。例如:

num = input('please input number: ')
num = int(num) #不转为整形,下面代码将无法运行
for i in range(1,num):print(i)

十、函数式编程

1. map()

map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f依次作用在list的每个元素上,map()函数会返回一个迭代器,可以依次迭代得到原来list的元素被函数f处理后的结果。

例如,对于list [1, 2, 3, 4, 5, 6, 7, 8, 9]。
如果希望把list的每个元素都作平方,就可以利用map()函数。

我们定义需要传入函数f(x)=x*x,就可以利用map()函数完成这个计算:

def f(x):return x*xfor item in map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]):print(item) 
# 结果:[1, 4, 9, 10, 25, 36, 49, 64, 81]

2. reduce()

和map函数一样,reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map() 类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。

例如,编写一个f函数,接收x和y,返回x和y的和:

from functools import reducedef f(x, y):return x + yprint(reduce(f, [1,3,5,7,9])) # ==> 25

得到的结果是25,实际过程是这样的,reduce()函数会做如下计算:

先计算头两个元素:f(1, 3),结果为4;
再把结果和第3个元素计算:f(4, 5),结果为9;
再把结果和第4个元素计算:f(9, 7),结果为16;
再把结果和第5个元素计算:f(16, 9),结果为25;
由于没有更多的元素了,计算结束,返回结果25。

上述计算实际上是对 list 的所有元素求和。虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。
reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:

print(reduce(f, [1, 3, 5, 7, 9], 100)) # ==> 125

结果将变为125,因为第一轮计算是:

计算初始值和第一个元素:f(100, 1),结果为101。

3. filter()

filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,并返回一个迭代器,可以迭代出所有符合条件的元素。

例如,要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数,首先,要编写一个判断奇数的函数:

def is_odd(x):return x % 2 == 1
for item in filter(is_odd, [1, 4, 6, 7, 9, 12, 17]):print(item)

4. sorted()

Python内置的 sorted()函数可对list进行排序:

>>> sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]

可以看到,sorted()函数,默认是由小到大排序列表的元素。

>>> score = [('Alice', 72), ('Candy', 90), ('Bob', 62)]
>>> sorted(score)
[('Alice', 72), ('Bob', 62), ('Candy', 90)]

当list的每一个元素又是一个容器时,则会以第一个元素来排序,比如在score中,每个元素都是包含名字和成绩的一个tuple,sorted()函数则按名字首字母进行了排序并返回。

对于上述排序成绩的情况,默认是按照第一个名字进行排序的,有没有办法让sorted()函数按照成绩来进行排序呢?

如果需要按照成绩高低进行排序,需要指定排序的字段是成绩,sorted接受key参数,用来指定排序的字段,key的值是一个函数,接受待排序列表的元素作为参数,并返回对应需要排序的字段。因此,sorted()函数也是高阶函数。

score = [('Alice', 72), ('Candy', 90), ('Bob', 62)]
def k(item):return item[1] # ==> 按成绩排序,成绩是第二个字段new_socre = sorted(score, key=k)
print(new_socre) # [('Bob', 62), ('Alice', 72), ('Candy', 90)]# 如果需要倒序,指定reverse参数即可
new_socre2 = sorted(score, key=k, reverse=True)
print(new_socre2) # [('Candy', 90), ('Alice', 72), ('Bob', 62)] 

5. range()

在 Python 中,range 是一个用于生成一系列整数的函数。它可以接受一个、两个或三个参数,返回一个表示等差整数序列的可迭代对象。

range 的基本语法是:

range(stop)
range(start, stop)
range(start, stop, step)
  • start: 序列的起始值,默认为0。
  • stop: 序列的结束值,但不包括该值。
  • step: 步长(增量),表示连续数字之间的差。默认为1。

range 生成的序列是左闭右开的,即包括起始值,但不包括结束值。

++ 只有一个参数 (stop):

for i in range(5):print(i)
# 结果:
# 0
# 1
# 2
# 3
# 4

++ 两个参数 (start, stop):

for i in range(2, 8):print(i)
# 结果:
# 2
# 3
# 4
# 5
# 6
# 7

++ 三个参数 (start, stop, step):

for i in range(1, 10, 2):print(i)
# 结果:
# 1
# 3
# 5
# 7
# 9

range 还可以用于创建一个列表:

my_list = list(range(5, 20, 3))
print(my_list) # [5, 8, 11, 14, 17]

案例:找出1到20内的所有质数

for num in range(2, 21):  # 起始值为2,对于范围在2到20的每一个数字for i in range(2, num):  # 对于从2到num-1的每一个数字if num % i == 0:  # 如果num能被i整除break  # 退出内层循环,说明num不是质数else:print(num)  # 如果内层循环完整执行(即未中断),则说明num是质数,打印输出
# 结果:2、3、5、7、11、13、17、19

6. 闭包

在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问:

def g():print('g()...')def f():print('f()...')return g
f() # ==> f()...

将g的定义移入函数 f 内部,防止其他代码调用 g:

def f():print('f()...')def g():print('g()...')return g
f() # ==> f()...

假如,有这么一个 calc_sum 函数:

def calc_sum(list_):def lazy_sum():return sum(list_)return lazy_sum

注意: 发现没法把 lazy_sum 移到 calc_sum 的外部,因为它引用了 calc_sum 的参数 list_。

像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。

闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:

# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():fs = []for i in range(1, 4):def f():return i*ifs.append(f)return fsf1, f2, f3 = count()
print(f1()) #9 【因为f1现在才计算i*i,但现在i的值已经变为3】
print(f2()) #9
print(f3()) #9

你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。

原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时,i的值已经变为3。

因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/224630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年全国职业院校技能大赛信息安全管理与评估赛项正式赛(模块一)GZ032

全国职业院校技能大赛高等职业教育组 信息安全管理与评估 任务书 模块一 网络平台搭建与设备安全防护 极安云科专注技能竞赛&#xff0c;包含网络建设与运维和信息安全管理与评估两大赛项&#xff0c;及各大CTF&#xff0c;基于两大赛项提供全面的系统性培训&#xff0c;拥…

【入坑指南】| OpenCV4.8 + CUDA + 扩展模块支持编译

大家好&#xff0c;今天给大家分享一下最新版本OpenCV4.8如何编译支持CUDA加速&#xff0c;实现深度学习模型部署速度提升。 软件版本支持 CMake3.13 或者以上版本 https://cmake.org/ VS2017专业版或者以上版本 3050ti CUDA11.3 OpenCV4.8源码包 https://github.com/opencv…

三层交换的原理

一.三层交换技术 1.什么是三层交换机 要实现vlan间通信&#xff0c;就需要路由&#xff0c;解决办法要么是二层交换机加路由器形成单臂路由&#xff0c;要么就是直接使用三层交换机。 ①什么是单臂路由&#xff1a; ②单臂路由实现不同vlan间通信的原理&#xff1a; 路由器…

JVM的类的生命周期

目录 前言 1. 加载&#xff08;Loading&#xff09;&#xff1a; 2. 验证&#xff08;Verification&#xff09;&#xff1a; 3. 准备&#xff08;Preparation&#xff09;&#xff1a; 4. 解析&#xff08;Resolution&#xff09;&#xff1a; 5. 初始化&#xff08;Ini…

Ubuntu解决Failed to fetch https://... Could not resolve ‘某个源‘

在我使用sudo apt install subversion的时候遇到报错&#xff1a; 这个报错与Ubuntu操作系统的软件源配置文件有关系。错误提示显示无法解析“mirrors.shanhe.com”地址&#xff0c;这可能是由于更新软件包列表或下载软件包时出现的网络问题。 1.可以先更新一下源试试&#xf…

Vue 子传父 组件传参 defineEmits

defineEmits 属性&#xff1a;用于创建自定义事件&#xff0c;接收子组件传递过来的数据。 注意&#xff1a;如果自定义事件的名称&#xff0c;和原生事件的名称一样&#xff0c;那么只会触发自定义事件。 defineEmits 仅适用于 setup 语法糖&#xff0c;其它写法请见&#x…

SpringBoot+SSM项目实战 苍穹外卖(5)(Redis入门)

继续上一节的内容&#xff0c;本节学习Redis&#xff0c;并实现营业状态设置功能。 目录 Redis环境搭建Redis数据类型Redis常用命令在Java中操作Redis环境搭建java操作常见类型数据 店铺营业状态设置设置营业状态管理端查询营业状态用户端查询营业状态swagger区分管理端和用户端…

CSAPP/ICS 系统级IO笔记

文件描述符&#xff1a;内核&#xff08;kernel&#xff09;利用文件描述符&#xff08;file descriptor&#xff09;来访问文件。文件描述符是非负整数。打开现存文件或新建文件时&#xff0c;内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。 每…

Python移动未标注的图片数据集

Python移动未标注的图片数据集 前言前提条件相关介绍实验环境Python移动未标注的图片数据集情况一&#xff1a;有图&#xff0c;无标注文件代码实现输出结果 情况二&#xff1a;有图&#xff0c;有标注文件&#xff0c;但标注信息为空代码实现输出结果 情况一与情况二同时都考虑…

LabVIEW开发电能质量监测系统

LabVIEW开发电能质量监测系统 本研究基于LabVIEW开发了一个创新的电能质量监测系统&#xff0c;专注于暂态电能质量扰动信号的产生、分析与存储。该系统不仅模拟产生了电压骤降、电压波动、暂态振荡以及电压畸变等关键信号&#xff0c;还能够记录并存储这些扰动信号产生时的波…

Vmware Windows10安装Apache php

文章目录 一、下载必要的软件二、安装Apache三、安装php四、php连接Apache五、测试 一、下载必要的软件 Apache&#xff1a;https://www.apachelounge.com/download/ PHP&#xff1a;http://windows.php.net/download/ 二、安装Apache 将下载的压缩包解压&#xff0c;移动里…

MyBatis中的N+1问题,使用ResultSet来解决,需要存储过程【非常详细】

参考 https://mybatis.org/mybatis-3/zh/sqlmap-xml.html https://mybatis.net.cn/sqlmap-xml.html#Result_Maps 基础表sql 订单表 CREATE TABLE test_order (order_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 订单id,order_name varchar(255) NOT NULL DEFAULT COMME…

KITTI数据集处理为COCO数据集格式

KITTI作为自动驾驶常用数据集&#xff0c;被广泛的应用于自动驾驶目标检测等过程中。 首先是数据集类别合并&#xff0c;原始的KITTI数据集有九个类别&#xff0c;分别是&#xff1a; Car Van Truck Pedestrian Person_sitting Cyclist Tram Misc而我们在使用过程中&#xff0…

GO并发编程综合应用

一.GO并发编程综合应用 1.生产者消费者模式 1.1需求分析 ​ 生产者每秒生产一个商品&#xff0c;并通过物流公司取货 ​ 物流公司将商品运输到商铺 ​ 消费者阻塞等待商铺到货&#xff0c;需要消费10次商品 1.2实现原理 1.3代码实现&#xff1a; package mainimport (&q…

SpringCloud微服务 【实用篇】| Docker启示录

目录 一&#xff1a;Docker启示录 1. Docker启示录 2. Docker和虚拟机的区别 3. Docker架构 4. Centos7安装Docker 4.1. 卸载 4.2. 安装docker 4.3. 启动docker 4.4. 配置镜像加速 前些天突然发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽…

Python之random模块详解

python的random模块 random模块是python中一个生成随机数的模块。 random不是python解释器内置的模块。 导入random模块的方法是&#xff1a; import random 如果只使用random模块中的单个方法的话&#xff0c;也可以使用 from random import method_name 例如&#xff1a; …

蓝牙协议栈学习笔记

蓝牙协议栈学习笔记 蓝牙简介 蓝牙工作在全球通用的 2.4GHz ISM&#xff08;即工业、科学、医学&#xff09;频段&#xff0c;使用 IEEE802.11 协议 蓝牙 4.0 是迄今为止第一个蓝牙综合协议规范&#xff0c;将三种规格集成在一起。其中最重要的变化就是 BLE&#xff08;Blue…

【数学建模】《实战数学建模:例题与讲解》第十三讲-相关分析(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第十三讲-相关分析&#xff08;含Matlab代码&#xff09; 基本概念典型相关分析综合评价模型对应分析因子分析聚类分析 习题10.41. 题目要求2.解题过程3.程序 习题10.51. 题目要求2.解题过程3.程序 习题10.6&#xff08;1&a…

用Excel绘制柱形图

在需要将数据用柱状图表示的时候&#xff0c;可以用Excel进行绘制。不单绘制柱形图&#xff0c;其他数据图也可以用Excel绘制。 接下来用绘制一个销售表的示例演示。 1.将数据输入Excel 数学书 语文书 英语书 一月 80 94 77 二月 95 86 84 三月 130 93 79 四月 …

实用干货:再见ElementPlus,我有更好的了

大家好&#xff0c;我是大澈&#xff01; 本文约1200字&#xff0c;整篇阅读大约需要3分钟。 感谢关注微信公众号&#xff1a;“程序员大澈”&#xff0c;免费领取"面试大礼包"一份&#xff0c;然后免费加入问答群&#xff0c;从此让解决问题的你不再孤单&#xff…