python学习笔记

242 阅读17分钟

整理了一下可能容易遗忘的知识点,仅供参考~ 大多数基础知识与其他语言并无两样,因此不做全面整理

python基础

基本数据类型

① 数字(num)

int(有符号整数)、float(浮点型)、bool(布尔值)、complex(复数)

②字符串(str)

③列表(list)

④元组(tuple)

⑤字典(dict)

运算符

---- 算术运算符 ----
    /  : 除法,包含小数
    // : 取整除法,只保留整数
    ** : 指数运算,左边数为底数,右边数为指数
    not: 取反
eg: a = 7, b = 3(也可以一次性定义几个变量,例如 a,b = 7,3 )
a // 3 = 2 
a / b = 2.333333  
a ** b = 343
print(not a > b) # False

bool运算符:False''None会被当作False,其他都为True

---- 关系运算符 ----
    ==      比较两个对象的值是否相等
    !=      比较两个对象的值是否不等
    is      比较两个对象是否为同一对象,比较的是idis not  比较两个对象是否不为同一对象,比较的是id值

---- 逻辑运算符 ----
    and     短路操作,一假则假,遇到False就停止,也就是找False
    or      短路操作,一正则正,遇到True就停止,也就是找True
    not     对符号右侧的值进行非运算
    
"""   
补充1. 逻辑运算符还能连着使用
    print(10 < 20 > 15)  # 相当于 20 > 10 and 20 > 15,结果为True
补充2. 当对非布尔值进行与或运算时,python会将其当作布尔值运算,最终会返回原值
    print(1 and 2)  # 前面是True,由于是and继续往后找,后面不管是True还是False直接返回原值2
    print(0 and 1)  # 前面是False,由于是and不再继续往后找,返回原值0
    print(None and 0)  # 前面是False,由于是and不再继续往后找,返回原值None
"""
False and print("这里的内容不会打印") # 前面是False,由于是and不再继续往后走,不会打印
True and print("这里的内容会打印")  # 前面是True,由于是and继续往后走,打印出print的内容

流程控制结构(if-else结构、while循环、for循环)

image.png

输出结果:

image.png

字符串操作:切片

语法:[开始位置:结束位置:步长]

注:包含开始位置,不包含结束位置

image.png

列表、元组

列表 list[] 中的数据可以是任意类型的组合,是一种有序的数据集合,支持增删改查等功能;元组 tuple() 中的数据也可以是任意类型的组合,但是在创建之后不能做任何修改,当元组中只有一个元素的时候,要加上逗号

  • list.append(data):末尾添加
  • list.insert(index,data):指定位置插入
  • list.extend(iterable):末尾追加可迭代序列

  • del list[index]:根据下标删除指定元素
  • del list[start:end]:根据区域删除指定原色
  • list.remove(data):删除指定元素
  • list.pop(index):根据下标删除移除指定元素

  • list[index] = data
  • list[start:end:step] = [data1,data2,...]

查:切片

image.png

# 当元组不是空元组时,括号可以省略
tupleA = 10,  # 只有一个元素时,需要加上逗号
my_tuple = 10, 20, 30
# 解包操作
a, b, c = my_tuple
print(a)  # 10
print(b)  # 20
print(c)  # 30
a, *b = my_tuple
print(a)  # 10
print(b)  # [20,30]
*a, b = my_tuple
print(a)  # [10,20]
print(b)  # 30

字典

字典 dict{} 是键值对的形式,字典的键不能重复且只能是不可变类型,如数字、字符串、元组,值可以重复

"""
    字典(小结)
        创建
            {}直接创建 :这种创建方式key需要是str形式
            dict()的形式创建:这种创建方式key不为str形式
        删除
            del dictA[key]:根据key删除,key不存在会报错
            result = dictA.pop(key,defaultValue):根据key移除,key不存在返回默认值
            result = dictA.popitem():移除最后一个item,返回结果为删除的键值对组成的元组
            dictA.clear():字典清空
        获取
            result= dictA[key] : key不存在会报错
            result = dictA.get(key,defaultValue):key不存在返回默认值
        修改
            dictA[key] = value:key存在则修改,key不存在则添加
            result = dictA.setdefault(key,value):key存在则返回原value,不修改原字典;key不存在则添加并返回该value,修改原字典进行添加
            dictA.update(dictB):如果字典里存在键重复,则后面的会覆盖前面
        遍历
            dictA.keys():获取键集合,可通过键集合获取值
            dictA.values():仅可获取值集合
            dictA.items():获取键值对集合
                for k.v in dictA.items()
                    print(k,"=",v)
"""

# 创建字典的三种方式
dictA = {'name': '张三', 'age': 18}
dictB = dict(name='张三', age=18)  # 键默认是str
dictC = dict([('name', '张三'), ('age', 18), ('gender', '男')])  # 可以将一个包含有双值子序列的序列转换为字典

# 获取字典中的值
print(dictA.get('hello', 'defaultValue'))  # >>>defaultValue【不存在返回】
print(dictA['name'])  # >>>张三【如果不存在就报错 KeyError】

# 修改字典,存在就修改,不存在就添加
dictA['name'] = '李四'  # 修改key为name的value为李四
dictA['gender'] = '男'  # 原字典不存在该key,添加
print(dictA)  # >>> {'name': '李四', 'age': 18, 'gender': '男'}
result = dictA.setdefault('name', '王五')  # >>>李四【如果key存在,直接返回原key的值,即不更新字典】
result2 = dictA.setdefault('country', 'china')  # >>>china【如果key不存在,则向字典中添加这个key,同时返回这个value】

d = {'a': 1, 'b': 2}
d2 = {'c': 3, 'a': 4}
d.update(d2)
print(d)  # >>>{'a': 4, 'b': 2, 'c': 3}

# 删除
del d['a']  # 如果键不存在会报错
print(d.popitem())  # >>>('c', 3)
print(d.pop('d', '默认值'))  # >>>默认值【key不存在】
d.clear()  # 清空

# len()查看字典中键值对的个数
print(len(dictB))  # >>>2
# in 检查字典中是否包含指定的键
print('hello' in dictA)  # >>>False

集合set

不支持索引和切片,是一个无序且不重复的容器。类似于字典,但是只有key,没有value

# 创建集合
s = {1, 2, 3, 4}
s = set()  # 创建空集合不能用{}--这个是表示字典
print(set([1, 2, 3, 4, 5, 3, 2, 1]))  # >>> {1, 2, 3, 4, 5}【将序列转换为集合】
print(set({'a': 1, 'b': 2, 'c': 3}))  # >>> {'a', 'c', 'b'}【将字典转换为集合,只会包含键】
# 添加
s.add(10)
s.update([1, 2, 3, 4])
print(s)  # >>>{1, 2, 3, 4, 10}
# 删除
s.remove(10)
s.pop()  # 随机删除并返回一个集合中的元素
s.discard(2)
print(s)  # >>>{3, 4}
交集 &        并集 |        差集 -
异或集 ^      是否子集 <=     是否真子集 <

默认参数

# 默认参数,可以不传入值【注:只能放在最后】
def funA(a, b=20, c=30):
    print(a + b + c)
funA(10, 40)  # >>>80

位置可选参数(*args)

"""
    可变参数是个元组类型
    可变参数不一定要放在最后,但是带*参数之后的所有参数都必须以关键字参数的形式传递(也就是【参数=值】的形式)
"""
def funA(a, *nums, c):
    print(f'a={a}')  # >>>a=10
    print(f'num={nums}')  # >>>num=(20,)
    print(f'c={c}')  # c=30
funA(10, 20, c=30)

def funB(*nums, a):
    print(f'num={nums}')  # >>>num=(10,20,30)
    print(f'a={a}')  # >>>a=40
funB(10, 20, 30, a=40) # a必须是关键字参数的形式

# 要求所有参数都必须以关键字参数的形式传递
def funC(*, a, b):
    print(f'a={a}')  # >>>a=30
    print(f'b={b}')  # >>>b=40
funC(a=30, b=40) # a,b都必须是关键字参数的形式

关键字可选参数(**kwargs)

"""
    关键字可变参数是字典类型,只能存在一个且必须写在所有参数的最后
    参数内容会保存到字典中【没有匹配到参数的都会存储到字典中】
"""
def funD(a, b, **c):
    print(f'a={a}')
    print(f'b={b}')
    print(f'c={c}')
funD(d=10, e=20, b=30, a=40)  # >>a=40,b=30,c={'d': 10, 'e': 20}
dictA = {'f': 50, 'g': 60}
listA = [10,20]
# 如果以字典的形式传入,需要加上**(解包操作)
# 如果以列表/元组的形式传入,需要加上*(解包操作)
funD(*listA, **dictA)  # a=10,b=20,c={'f': 50, 'g': 60}

混合使用【可选参数】【关键字可变参数】

注:可选参数必须放在关键字可变参数之前

image.png

文档字符串(函数注释)

"""
    在定义函数时,可以在函数内部编写文档字符串(函数注释)
    文档字符串可以是单引号【''】双引号【""】三引号【'''】三双引号
    但是一般注释内容较多,都用三引号和三双引号
"""

# 简写版,不推荐写法
def sumA(a, b):
    return a + b

# 完整版写法,这里虽然指定了参数a、b和返回值类型都为int,但是不进行检查
def sumB(a: int, b: int) -> int:
    """
    :param a: 输入参数a,int值
    :param b: 输入参数b,int值
    :return: 返回两个参数的和
    """
    return a + b
print(sumB('hello','world'))# >>>helloworld
# 查看python中函数的用法
help(sumB)

global 关键字

在函数局部修改全局变量,需要使用 global 关键字

image.png

递归

"""
    检查是否是回文字符串,如abcba\abcdedcba
    检查流程:
        先看第一个和最后一个是否一致,不一致则不是回文字符串
            如果一致,则看剩余部分是否是回文字符串(递归)
        检查abcdedcba是否回文
            检查bcdedcb是否回文
                检查cdedc是否回文
                    检查ded是否回文
                        检查e是否回文
"""
def hui_wen(s):
    if len(s) < 2: # 只剩一个单词或者没有单词时,表示查找完毕
        return True
    elif s[0] != s[-1]: # 如果第一个和最后一个不一致,直接退出
        return False
    return hui_wen(s[1:-1]) # 递归查找
print(hui_wen('abcdefedcba'))  # >>>True
print(hui_wen('hello'))  # >>>False

命名空间

image.png

匿名函数

"""
    用lambda关键字创建,语法:lambda 参数1,参数2... : 表达式
"""
# 返回的是一个lambda对象,一般不这么操作
sum = lambda x, y: x + y
print(sum(12, 25))
# 简化版,也可以声明完直接调用,一般也不这么操作
result = (lambda x, y: x + y)(12, 25)
print(result)
# 更多情况是作为函数参数进行调用
l = [1, 2, 3, 4]
r = map(lambda i: i + 1, l)  # >>>[2, 3, 4, 5]
print(list(r)) # 返回的r是个lambda对象

三元运算符

a = 20
if a > 10:
    print("a大于10")
else:
    print("a不大于10")
# 简化版,三元运算符
print("a大于10" if a > 10 else "a不大于10")

三元运算符与匿名函数结合

getMax = lambda x, y: x if x > y else y
print(getMax(12, 25)) # 25

sort 和 sorted

"""
    sort(): 只能应用在list上,在原先的集合上进行排序
    sorted():对所有的可迭代对象都能进行排序操作,返回一个新集合
    以上两个方法都可以接受一个关键字参数key(对元素进行排序的指定函数),key的参数是一个函数对象
"""
l = ['aa', 'ddd', 'b', 'gggggg']
# 使用len函数对l进行排序,在原集合上进行排序,无返回值
result = l.sort(key=len)
print(l, result)  # >>>['b', 'aa', 'ddd', 'gggggg'] None

l = [2, 5, '1', '3', 4, 55]
result = sorted(l, key=int)  # 转换为int进行比较
print(l)  # >>>[2, 5, '1', '3', 4, 55] 不改变原集合
print(result)  # >>>['1', 2, '3', 4, 5, 55] 返回一个新集合 

闭包

"""
    闭包:函数嵌套并且将内部函数作为返回值返回
        【当有些数据需要藏起来不被外部访问时,可以使用闭包】
    形成闭包的条件:
        1 函数嵌套
        2 将内部函数对象作为返回值返回
        3 内部函数必须使用到外部函数定义的变量
"""
def make_averager():
    nums = []
    def averager(n):
        nums.append(n) # 内部函数使用到外部函数定义的变量
        return sum(nums) / len(nums)
    return averager
# 如果不使用闭包,外部就能使用到nums数组
avg = make_averager()
print(avg(10))  # >>>10.0
print(avg(20))  # >>>15.0

其他常见python函数

range

语法:range(start,end,step)【创建一个整数列表,步长为step】
range(5)=range(0,5),包前不包后,即[0,1,2,3,4]

eval

"""
    eval()函数用来执行一个【字符串表达式!!!】并返回表达式的值
"""
a, b, c = 1, 2, 3
print(eval("a+b+c"))  # >>>6
def fun():
    print("fun函数执行")
eval("fun()")  # >>>fun函数执行

enumerate

"""
    enumerate(sequence[,start]):用于将一个可遍历的数据对象(如列表、元组或者字符串)组合成一个索引序列
    同时列出数据和数据下表,一般用于for循环中,start表示下标起始位置
"""
l = [1, 2, 3]
for index, item in enumerate(l):
    print(f"下标{index} -> 数据{item}")
# >>> 下标0 -> 数据1
# >>> 下标1 -> 数据2
# >>> 下标2 -> 数据3
seasons = ['spring', 'summer', 'autumn', 'winter']
print(list(enumerate(seasons)))  # >>>[(0, 'spring'), (1, 'summer'), (2, 'autumn'), (3, 'winter')]
print(list(enumerate(seasons, start=2)))  # >>>[(2, 'spring'), (3, 'summer'), (4, 'autumn'), (5, 'winter')]

all、any

"""
    all():所有的元素都为True才返回True,类似 and【有假则假】
    any(): 只要有一个元素为True就返回True,类似 or【有真则真】
    注:对象中的元素除了0、空、False都为True,空列表和空元组返回值为True
"""
l = [1, 2, 3]
l2 = [0, None, False]
l3 = [0, 1]
print(all(l))  # >>>True
print(all(l3))  # >>>False
print(any(l2))  # >>>False
print(any(l3))  # >>>True

面向对象

1. 类属性

在类内部定义的变量,可以通过实例对象或类对象直接进行访问。

注:修改的话只能通过【类名.类属性】的方式,无法通过【实例对象.类属性】进行修改

2. 实例属性

在构造方法(__ init __ 方法)内部定义的变量,通过【self.变量名】的方式声明只能通过实例对象访问

3. 实例方法

在类的内部,使用def关键字定义且第一个参数必须是self(可以不用写成self,任何名字都可以,但必须是第一个参数)可以通过类对象和实例对象访问。

注:实例方法就是它所属的权利归实例所有,任何创建的实例都能直接调用。

4. 类方法

用@classmethod修饰的方法,可以访问类属性。类方法的第一个参数必须是类对象cls(约定俗成的命名),可以通过类对象和实例对象访问。

5. 静态方法

用@staticmethod修饰的方法,主要用来存放逻辑性的代码,本身与类和实例对象没有交互,也尽量不要和类中的属性和方法进行交互(一般静态方法都抽取到工具类吧)。可以通过类对象和实例对象访问,但是通过实例对象访问本身没有意义,所以一般都是通过类对象调用

小结:除了实例属性(4)除外,其他四个都可以通过类和实例进行访问

# 类属性 实例属性 实例方法 类方法 静态方法
class Person:
    name = '张三'  # 类属性
    def __init__(self, age):
        self.age = age  # 实例属性
    # 实例方法:在类的内部,通过def关键字定义的方法,且方法的第一个参数是self(约定成俗为self,可自定义命名)
    def funA(self):
        print("实体方法调用~~")
    # 类方法:通过 @classmethod 修饰的方法,且方法的第一个参数是类对象cls(约定成俗为cls,可自定义命名)
    @classmethod
    def classMethod(cls):
        print("类方法调用~~")
    # 静态方法:通过 @staticmethod 修饰的方法,可以不用接受参数
    @staticmethod
    def staticMethod():
        print("静态方法调用~~")
p = Person(20)

print(p.name)                                    # >>> 张三【类属性:实例对象调用】
print(Person.name)                               # >>> 张三【类属性:类对象调用】

print(p.age)                                     # >>> 20【实例属性:只能实例对象调用】

p.funA()                                         # >>> 实体方法调用~~【实例方法:实例对象调用】
Person.funA(p)                                   # >>> 实体方法调用~~【实例方法:类对象调用(❌)】

Person.classMethod()                             # >>> 类方法调用~~【类方法:类名调用】
p.classMethod()                                  # >>> 类方法调用~~【类方法:实例对象调用(❌)】

Person.staticMethod()                            # >>> 静态方法调用~~【静态方法:类名调用】
p.staticMethod()                                 # >>> 静态方法调用~~【静态方法:实例对象调用(❌)】

继承

"""
    1. 父类中的所有方法都会被子类继承,包括特殊方法__init__
    2. python中支持多继承,多个父类通过逗号隔开。但是不建议这么做
    3. 可以通过 【类名.__mro__】 查看继承结构,通过【类名.bases__】查看当前类的所有父类
"""
class Animal:
    def __init__(self, name):
        self.name = name
class Dog(Animal):
    def __init__(self, name, age):
        # Animal.__init__(self, name, age)  # 显示指定,耦合性过强不推荐。需要传入self
        super().__init__(name)  # 自动找,推荐。不需要传入self
        # 子类中可以拓展其他属性
        self.age = age

    def __str__(self):
        return "%s%d岁了" % (self.name, self.age)
dog = Dog("柯基", 3)
print(dog)  # 默认调用__str__

多态

python崇尚‘鸭子类型’(duck typing),它是动态类型的一种风格。在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。“当看到一只鸟走起来像鸭子、游泳起来像鸭子,那么这只鸟就可以被称为鸭子”。

image.png 注:只要对象具有say()方法,就认为这些对象是“鸭子”--只关注使用

私有化属性、私有化方法

与java的private一样,属性或方法私有之后只能在类内部访问。
事实上隐藏属性在python内部仅仅是改了一个名字【_类名_属性名】
外部仍可以通过 【_类名_属性名】 的方式进行访问与修改。
所以一般私有属性用单下划线开头即可,表示该属性为私有属性,修改权仍交由调用者。

私有化属性语法:在属性名前面直接加双下划线 __
私有化方法语法:在方法名前面直接加双下划线 __

装饰器和property属性函数

使用 gettersetter 的方式操作私有化属性,给调用者的感觉就是调用一个方法而不是访问属性。
如何做到让调用者直接以访问属性的方式,而且我们又能控制的方式提供给调用者?

方式1. 装饰器

  • getter方法的装饰器:使用@property装饰,方法名任意但是一般和属性名一致
  • setter方法的装饰器:@属性名.setter,方法名任意但是一般和属性名一致

image.png

方式2. property属性函数

image.png

错误与异常处理

语法(和java一样,只不过语法和关键字不一样):
try:
    可能出错的代码块
except [异常类型,可不写,默认为Exception]:
    出错之后执行的代码块
else:
    没有出错执行的代码块
finally:
    不管有没有出错都执行的代码块

image.png

image.png

常见的异常: image.png

自定义异常

跟java的自定义异常一样,创建一个自定义异常类继承Exception即可。
抛出异常关键字为 raise
class MyException(Exception):
    ... #代码区

抛出异常: raise MyExcetpion() # 抛出自定义异常

魔术方法(__ ×× __ )

1.__ init __ :类比Java的构造方法

__ init __ (self)方法:初始化方法,实例化对象的时候自动调用,完成一些初始化设置

self是什么:类比Java的this,self和对象指向同一个内存地址,可以认为self就是对象的引用

2.__ new __ :创建并返回一个实例对象

  • __ new __ 是对象实例化时调用的第一个方法
  • 必须要有第一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供,其他的参数是用来直接传递给 __ init __ 方法
  • __ new __ 决定是否要使用 __ init __ 方法,因为 __ new __ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __ new __ 没有返回实例对象,则 __ init __ 不会被调用

image.png

image.png

单例模式

image.png

image.png

image.png

3.__ del __ :析构方法

当整个程序执行完毕或者手动销毁时自动调用,用于资源回收。也可以手动删除【del 实例化对象】

4. __ call __ 和 __ str __ :

__ call __ :实例对象以函数的形式调用时,python解释器自动调用

__ str __ :打印实例对象时,python解释器自动调用

image.png

5. __ slots __

  • python是动态语言,在运行的时候可以动态添加属性。如果想要防止其他人在调用类的时候胡乱添加属性,可以通过一个特殊的__slots__变量进行限制。只有在__slots__中声明的属性才能在外部动态添加。__slots__属性子类不会继承,只在当前类中生效。只有当子类也声明了__slots__属性时,才会继承

  • python中所有的属性都会存放在__dict__函数中,用__slots__的话只会存储变量名到其中,节约内存空间

image.png

image.png

动态绑定属性和方法

image.png

动态绑定实例方法

1.import types(导包)
2.定义动态实例方法(def关键字定义方法)
3.定义并创建实例对象(class定义类,类名()创建实例对象)
4.通过【实例对象名.自定义方法名】= types.MethodType(动态方法名,实例对象名) 的方式即可绑定实例方法
5.调用动态绑定的实例方法

image.png

动态绑定类方法和静态方法

image.png