Python学习笔记(二)

函数

定义函数

def 函数名(参数):
    代码1
    代码2
    ......

调用函数

函数名(参数)
  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)
  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 参数列表: 表达式
  1. lambda表达式的参数可有可无,函数的参数在lambda表达式中完全使用
  2. 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}
posted @ 2020-12-26 20:08  sxkio  阅读(89)  评论(0编辑  收藏  举报