Python学习笔记(二)
函数
定义函数
def 函数名(参数):
代码1
代码2
......
调用函数
函数名(参数)
- 参数可有可无
- 函数必须先定义后使用
函数的说明文档
定义函数的说明文档
def 函数名(参数):
"""说明文档的位置"""
代码
......
查看函数的说明文档
help(函数名)
def num(a, b):
"""
求和
:param a: 参数1
:param b: 参数2
:return: 返回值
"""
res = a + b
return res
help(num)
输出:
num(a, b)
求和
:param a: 参数1
:param b: 参数2
:return: 返回值
修改全局变量
a = 100
def test():
a = 200
test()
print(a) # 100
a = 100
def test2():
global a
a = 200
test2()
print(a) # 200
返回值
def test1():
return 1, 2
print(test1()) # (1, 2)
- 返回多个数据的时候,默认是元组类型
- return 后面可以连接列表、元组或字典,以返回多个值
函数的参数
一、位置参数
def user_info(name, age, gender):
print(f"您的名字是{name}, 年龄是{age}, 性别是{gender}")
user_info("Tom", 20, "男")
二、关键字参数
函数调用通过“键=值”形式加以指定。清晰、容易,清除了参数的顺序需求
def user_info(name, age, gender):
print(f"您的名字是{name}, 年龄是{age}, 性别是{gender}")
user_info("Tom", age=20, gender="男")
user_info("Jerry", gender="男", age=16)
注意:函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字之间不存在先后顺序
三、缺省参数
也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)
def user_info(name, age, gender="男"):
print(f"您的名字是{name}, 年龄是{age}, 性别是{gender}")
user_info("TOM", 20)
user_info("Rose", 18, "女")
四、不定长参数
也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。
包裹位置传递
def user_info(*args):
print(args)
user_info("TOM") # ('TOM',)
user_info("TOM", 18) # ('TOM', 18)
传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型
包裹关键字传递
def user_info(**kwargs):
print(kwargs)
user_info(name="TOM", age=18, gender="男")
# {'name': 'TOM', 'age': 18, 'gender': '男'}
合并为一个字典
拆包与交换变量
元组拆包
def return_num():
return 100, 200
num1, num2 = return_num()
print(num1) # 100
print(num2) # 200
字典拆包
dict1 = {"name": "TOM", "age": 18}
a, b = dict1
print(a) # name
print(b) # age
print(dict1[a]) # TOM
print(dict1[b]) # 18
交换变量
方法一:定义中间变量
方法二:
a, b = 1, 2
a, b = b, a
print(a) # 2
print(b) # 1
引用
在Python中,值是靠引用来传递的
id() 获取地址
可变类型:列表、字典、集合
不可变类型:整形、浮点型、字符串、元组
(数据能否直接修改,能直接修改就是可变、否则是不可变)
引用当做实参
def test1(c):
print(c)
print(id(c))
c += c
print(c)
print(id(c))
a = 100
test1(100)
100
140728557835008
200
140728557838208
b = [1, 2]
test1()
[1, 2]
2156910280832
[1, 2, 1, 2]
2156910280832
lambda
lambda 参数列表: 表达式
- lambda表达式的参数可有可无,函数的参数在lambda表达式中完全使用
- lambda表达式能接收任何数量的参数但只能返回一个表达式的值
计算a+b
fn1 = lambda a, b: a + b
print(fn1(1, 2)) # 3
参数形式
无参数
fn1 = lambda: 100
print(fn1())
一个参数
fn1 = lambda a: a
print(fn1("hello world"))
默认参数
fn1 = lambda a, b, c=100: a + b +c
print(fn1(10, 20))
可变参数 *agrs
fn1 = lambda *args: args
print(fn1(1, 2, 3)) # 返回值为元组
可变参数 **kwargs
fn1 = lambda **kwargs: kwargs
print(fn1(name="Tom", age=20)) # {'name': 'Tom', 'age': 20}
应用
判断
fn1 = lambda a, b: a if a > b else b
print(fn1(100, 99))
列表数据按字典key的值排序
students = [
{"name": "TOM", "age": 20},
{"name": "ROSE", "age": 19},
{"name": "JACK", "age": 22},
]
# 按age值升序排列
students.sort(key=lambda x: x["age"])
print(students)
# 按age值降序排列
students.sort(key=lambda x: x["age"], reverse=True)
print(students)
高阶函数
abs() 取绝对值
round() 四舍五入
def sum_num(a, b, f):
return f(a) + f(b)
res = sum_num(-1, 2, abs)
print(res) # 3
res = sum_num(1.4, 2.5, round)
print(res) # 4
内置高阶函数
map()
map(func, lst), 将传入的函数变量func作用到lst变量的每个元素中,并将结果组成新的列表(Python2) / 迭代器(Python3)返回。
计算list1序列中各个数字的2次方
list1 = [1, 2, 3, 4, 5]
def func(x):
return x ** 2
res = map(func, list1) # res是迭代器
print(res) # <map object at 0x000002839775C070>
print(list(res)) # [1, 4, 9, 16, 25]
reduce()
reduce(func, lst), 其中func必须有两个参数。每次func计算的结果继续和序列的下一个元素做累计计算。
计算list1序列中各个数字的累加和
import functools
list1 = [1, 2, 3, 4, 5]
def func(a, b):
return a + b
res = functools.reduce(func, list1)
print(res) # 15
filter()
filter(func, lst) 函数用于过滤序列,过滤掉不符合条件的元素,返回一个filter对象。如果要转换为列表,可以使用list() 来转换
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def func(x):
return x % 2 == 0
res = filter(func, list1)
print(res) # <filter object at 0x000002A29F1C6B80>
print(list(res)) # [2, 4, 6, 8, 10]
文件操作
打开
open(name, mode) # 打开一个已存在的文件,或创建一个新的文件
name: 目标文件名的字符串(可以包含文件所在的具体路径)
mode: 访问模式(只读、写入、追加...)
f = open("text.txt", "w")
f.write("abc")
f.close()
访问模式
r :只读;如果文件不存在,报错;文件指针在开头(默认访问模式)
rb:以二进制格式打开
r+:可读可写
rb:二进制,读写
w : 只写;如果文件不存在,新建;文件指针在开头
wb :
w+ :
wb+ :
a 追加;如果文件不存在,新建;文件指针在结尾
ab:
a+:
ab+:
读
read()
文件对象.read(num) num表示读取的长度,省略则读取全部
readlines()
整行读取,返回是列表,其中每一行的数据为一个元素
readline()
一次读取一行内容
seek() 移动文件指针
文件对象.seek(偏移量, 起始位置)
起始位置
0:文件开头
1:当前位置
2:文件结尾
文件备份
old_name = input("请输入您要备份的文件名:")
index = old_name.rfind(".")
if index > 0:
postfix = old_name[index:]
new_name = old_name[:index] + "[备份]" + postfix
print(new_name)
old_f = open(old_name, "rb")
new_f = open(new_name, "wb")
while True:
con = old_f.read(1024)
if len(con) == 0:
break
new_f.write(con)
old_f.close()
new_f.close()
文件和文件夹操作
import os
重命名文件/文件夹
os.rename("text.txt", "text2.txt")
删除文件
os.remove("text[备份].txt")
创建文件夹
os.mkdir("aa")
删除文件夹
os.rmdir("aa")
获取当前目录
print(os.getcwd()) # D:\pycharm\hello
改变默认目录
os.chdir("aa")
print(os.getcwd()) # D:\pycharm\hello\aa
获取某个文件夹下的所有文件,返回一个列表,无参则返回当前目录下的所有文件夹
print(os.listdir("aa"))
实例:批量修改文件名
import os
flag = 1
file_list = os.listdir()
print(file_list)
for i in file_list:
if flag == 1: # 添加Python_前缀
new_name = "Python_" + i
elif flag == 2: # 删除Python_前缀
num = len("Python_")
new_name = i[num:]
os.rename(i, new_name)
面向对象
定义类
class 类名():
代码
......
注意:类名要满足标识符命名规则,同时遵循大驼峰命名习惯
class Washer():
def wash(self):
print("洗衣服")
print(self)
haier1 = Washer()
haier1.wash()
洗衣服
<__main__.Washer object at 0x000002DCD8DAA430>
haier2 = Washer()
haier2.wash()
洗衣服
<__main__.Washer object at 0x000002DCDA8A55B0>
添加和获取对象属性
类外面添加和获取对象属性
对象名.属性名 = 值
haier1.width = 500
haier1.height = 800
print(haier1.width) # 500
类里面获取对象属性
class Washer():
def wash(self):
print("洗衣服")
def print_info(self):
print(self.width)
haier1 = Washer()
haier1.width = 500
haier1.print_info()
魔法方法
在Python中,_xx_() 的函数叫做魔法方法,指的是具有特殊功能的函数
_init_() 初始化对象
class Washer():
def __init__(self):
self.width = 500
self.height = 800
def wash(self):
print("洗衣服")
def print_info(self):
print(f"洗衣机的宽度是{self.width},高度是{self.height}")
haier1 = Washer()
haier1.width = 501
haier1.print_info() # 洗衣机的宽度是501,高度是800
带参数
class Washer():
def __init__(self, width, height):
self.width = width
self.height = height
def wash(self):
print("洗衣服")
def print_info(self):
print(f"洗衣机的宽度是{self.width},高度是{self.height}")
haier1 = Washer(500, 800)
haier1.print_info()
注意:
_init_() 方法,在创建一个对象时默认被调用,不需要手动调用
_inti_(self)中的self参数,不需要开发者传递,Python解释器会自动把当前的对象引用传递过去
_str_()
当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了_str_方法,那么就会打印从这个方法中return的数据
class Washer():
def __str__(self):
return "这是洗衣机的说明书"
haier1 = Washer()
print(haier1) # 这是洗衣机的说明书
_del_()
当删除对象时,Python解释器也会默认调用_del_()方法
def __del__(self):
print(f"{self}对象已被删除")
继承
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(A):
pass
res = B()
res.info_print() # 1
在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。
单继承
多继承
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(object):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
class C(A, B):
pass
res = C()
print(res.num) # 1
res.info_print() # 1
当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法
子类重写父类同名属性和方法
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(object):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
class C(A, B):
def __init__(self):
self.num = 3
def info_print(self):
print(self.num)
res = C()
print(res.num) # 3
res.info_print() # 3
_mro_ 查看继承关系
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
子类调用父类同名方法和属性
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(object):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
class C(A, B):
def __init__(self):
self.num = 3
def info_print(self):
# 如果先调用了父类,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
self.__init__()
print(self.num)
def info_print_a(self):
A.__init__(self) # 同理
A.info_print(self)
def info_print_b(self):
B.__init__(self)
B.info_print(self)
res = C()
print(res.num) # 3
res.info_print() # 3
res.info_print_a() # 1
res.info_print() # 3
super()
super() 函数是用于调用父类(超类)的一个方法。
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
class B(A):
def __init__(self):
self.num = 2
def info_print(self):
print(self.num)
# 有参写法
# super(B, self).__init__()
# super(B, self).info_print()
# 无参写法
super().__init__()
super().info_print()
class C(B):
def __init__(self):
self.num = 3
def info_print(self):
self.__init__()
print(self.num)
# 同时调用A和B
def info_print_ab(self):
# super(C, self).__init__()
# super(C, self).info_print()
super().__init__()
super().info_print()
res = C()
res.info_print_ab() # 2 1
私有权限
设置某个实例属性或实例方法不继承给子类
class A(object):
def __init__(self):
self.num = 1
self.__money = 200
def __info_print(self):
print("私有")
class B(A):
pass
res = B()
print(res.money) # AttributeError: 'B' object has no attribute 'money'
res.info_print() # AttributeError: 'B' object has no attribute 'info_print'
获取和修改私有属性值
一般定义 get_xx()、set_xx()
class A(object):
def __init__(self):
self.num = 1
self.__money = 200
def get_money(self):
return self.__money
def set_money(self, val):
self.__money = val
def __info_print(self):
print("私有")
class B(A):
pass
res = B()
print(res.get_money()) # 200
res.set_money(500)
print(res.get_money()) # 500
多态
class Dog(object):
def work(self):
print("指哪打哪")
class ArmyDog(Dog):
def work(self):
print("追击敌人")
class DrugDog(Dog):
def work(self):
print("追查毒品")
class Person(object):
def work_with_dog(self, dog):
dog.work()
ad = ArmyDog()
dd = DrugDog()
daqiu = Person()
daqiu.work_with_dog(ad) # 追击敌人
daqiu.work_with_dog(dd) # 追查毒品
类属性和实例属性
类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有
类属性可以使用类对象或实例对象访问
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
print(Dog.tooth) # 10
print(wangcai.tooth) # 10
print(xiaohei.tooth) # 10
类属性的优点
记录的某项数据始终保持一致时,则定义类属性
实例属性要求每个对象为其单独开辟一份内存空间来记录数据,而类属性为全类所共有,仅占用一份内存,更加节省内存空间
修改类属性
类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个实例属性
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
# 修改类属性
Dog.tooth = 12
print(Dog.tooth) # 12
print(wangcai.tooth) # 12
print(xiaohei.tooth) # 12
# 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性
wangcai.tooth = 20
print(Dog.tooth) # 12
print(wangcai.tooth) # 20
print(xiaohei.tooth) # 12
类方法和静态方法
类方法
需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数
使用场景
当方法中需要使用类对象(如访问私有类属性等)时,定义类方法
类方法一般和类属性配合使用
class Dog(object):
__tooth = 10
@classmethod
def get_tooth(cls):
return cls.__tooth
wangcai = Dog()
print(wangcai.get_tooth()) # 10
静态方法
需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)
静态方法也能够通过实例对象和类对象去访问
使用场景
当方法中既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象(如类属性、类方法、创建实例等)时,定义静态方法
取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
class Dog(object):
__tooth = 10
@staticmethod
def info_print():
print("创建狗实例")
wangcai = Dog()
# 静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print() # 创建狗实例
Dog.info_print() # 创建狗实例
异常
try:
可能发生错误的代码
except:
如果出现异常执行的代码
try:
f = open("test.txt", "r")
except:
f = open("text.txt", "w")
捕获指定异常
try:
可能发生错误的代码
except 异常类型:
如果捕获到该异常类型执行的代码
try:
print(num)
except NameError:
print("有错误")
一般尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常
一般try下方只放一行尝试执行的代码
捕获多个指定异常
try:
print(1/0)
except (NameError, ZeroDivisionError): # 元组的方式
print("有错误")
捕获异常描述信息
try:
print(num)
except (NameError, ZeroDivisionError) as result:
print(result) # name 'num' is not defined
捕获所有异常
Exception是所有程序异常类的父类
try:
print(num)
except Exception as result:
print(result) # name 'num' is not defined
异常的else
else表示的是如果没有异常要执行的代码
try:
print(1) # 1
except Exception as result:
print(result)
else:
print("没有异常") # 没有异常
异常的finally
finally表示的是无论是否异常都要执行的代码
try:
f = open("test.txt", "r")
except Exception as result:
f = open("text.txt", "w")
else:
print("没有异常")
finally:
f.close()
异常的传递
import time
try:
f = open("text2.txt", "r")
try:
while True:
con = f.readline()
if len(con) == 0:
break
time.sleep(2) # 每隔两秒
print(con)
except:
print("读取数据被终止")
finally:
f.close()
print("关闭文件")
except:
print("打开失败")
自定义异常
raise 异常类对象
class ShortInputError(Exception): # 继承Exception类
def __init__(self, length, min_len):
self.length = length
self.min_len = min_len
# 设置抛出异常的描述信息
def __str__(self):
return f"你输入的长度是{self.length},不能少于{self.min_len}个字符"
def main():
try:
con = input("请输入密码:")
if len(con) < 3:
raise ShortInputError(len(con), 3)
except Exception as result:
print(result)
else:
print("密码输入完成")
main()
模块
Python模块(Module),是一个Python文件,以.py结尾,包含了Python对象定义和Python语句
导入模块
- import 模块名
- from 模块名 import 功能名
- form 模块名 import *
- import 模块名 as 别名
- from 模块名 import 功能名 as 别名
import 模块名
import 模块名1, 模块名2...
import math
math.sqrt(9) # 3.0
from 模块名 import 功能1,功能2......
from math import sqrt
print(sqrt(9))
from 模块名 import *
from math import *
print(sqrt(9))
as定义别名
# 模块别名
import time as tt
tt.sleep(2)
print("hello")
# 功能别名
from time import sleep as sl
sl(2)
print("hello")
制作模块
在当前文件中调用该函数
print(_name_) # _main_
调用其他导入的文件
print(_name_) # 导入的文件名
模块定义顺序
自己的文件名不要和已有模块名重复,否则导致模块功能无法使用
使用from 模块名 import 功能 的时候,如果功能名字重复,调用到的是最后定义或导入的功能
__all__ 列表
如果一个模块文件中有__all__变量,当使用from xxx import *导入时,只能导入这个列表中的元素
__all__ = ["testA"]
def testA():
print("testA")
def testB():
print("testB")
包
新建包
[new]--->[Python Package]
导入包
法一
import 包名.模块名
包名.模块名.目标
法二
必须在_init_.py文件中添加__all__ = [] 控制允许导入的模块列表
from 包名 import *
模块名.目标
__dict__
class A(object):
a = 0
def __init__(self):
self.b = 1
aa = A()
# 返回类内部所有属性和方法对应的字典
print(A.__dict__)
{'__module__': '__main__', 'a': 0, '__init__': <function A.__init__ at 0x000001B38BC191F0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
# 返回实例属性和值组成的字典
print(aa.__dict__)
{'b': 1}