Python基础语法

Python编程基础环境

Python安装
Python编程我使用的软件是PyCharm,下载该软件之前要先安装Python软件,Python的下载网址是https://www.python.org/,这里更新的版本,我使用的版本是Python3.6.6

PyCharm安装
Python安装好后,接着下载PyCharm,安装地址是https://www.jetbrains.com/pycharm/download/#section=windows,这里的professional 表示专业版,community 是社区版,推荐安装社区版,因为是免费使用的

Python和PyCharm的安装详细教程网上有很多,可以在网上查看

输出格式

格式含义举例
%c字符print(‘a=%c’ % ‘a’)
%s字符串print(‘a=%s’ % ‘aaa’)
%d有符号十进制print(‘a=%d’ % 11)
%u无符号十进制
%o八进制
%x十六进制(小写)
%X十六进制(大写)
%f浮点数
%e科学计数法
%3d :输出数据占3个字符宽度
%03d:数据占3个长度,不够三个时前面补0
%-3d:数据占3个长度,左对齐
%.3d:小数点保留位数3
name = 'Tom'
age = 11
print(f'name: {name} age: {age} score : {99}')
# name: Tom age: 11 score: 99
s = f'name: {name} age: {age} score : {99}'
print(s)
# name: Tom age: 11 score: 99

format格式

print("{0}".format(3))
print("{1},{0}".format(1,2))
print("{0:.2}".format(1.234))
print("{0:s}".format('afweg'))
print("{0:s}".format("asgd\
agre"))
print("{0:s}".format('''agwf
gerg'''))
print("{0:s}".format("""asg
agafwe"""))

# 日期
from datetime import date,time, datetime, timedelta
today = date.today() # 年月日
print(today)  # "{0!s}".format(today)
print(today.year)#.month  .day
print(datetime.today()) # 年月日时分秒
print(date.today()+timedelta(days = -1)) #时间加减days=2 hours=-8 week = -2
print(timedelta(hours=-8).days,timedelta(hours=-8).seconds) #-1 57600   24*3600-8*3600=57600
print(today.strftime('%m/%d/%Y'))  # 08/01/2021
print(today.strftime('%b %d %Y'))  # Aug 01 2021
print(today.strftime('%Y-%m-%d'))  # 2021-08-01
print(today.strftime('%B %d,%Y'))  # August 01,2021

转义字符

\n \t

print('a\nc')
'''
a
c
'''
print('a\nc\td')
'''
a
c   d
'''

函数说明文档

def show():
	'''
	这是说明文档
	'''
help(show)
'''输出如下内容
show
	这是说明文档
'''

三目运算

n = 1
s = '偶数' if n % 2 == 0 else '基数'
print(s)  # 偶数

字符串

s为字符串含义说明
字符串查找find找不到返回-1,index找不到则报错,用法和find一样
s.find(‘o’)返回第一个位置
s.find(‘world’)返回第一个位置
s.find(‘world’, 6)从第6个位置开始找
s.find(‘world’, 6, 20)从第6找到第20
s.index(‘world’, 6, 20)从第6找到第20
rfind rindex都是从后往前找,用法同上
s.rfind(‘o’)后往前第一个
s.rindex(‘o’)后往前第一个
字符串替换
s.replace(‘world’, ‘aaa’)替换匹配的第一个,替换后原字符串不变
s.replace(‘o’, ‘a’, 2)替换两个o
字符串统计
s.count(‘h’)多少个h
按字符分隔s = 'hello world and hello word'
s.split()[‘hello’, ‘world’, ‘and’, ‘hello’, ‘word’]
s.split(’ ')以空格分隔 同上
s.split(’ ', 2)分隔两次[‘hello’, ‘world’, ‘and hello word’]
s = 'hello\tworld and\t\n hello\n word'
s.splitlines()按行分隔[‘hello\tworld and\t’, ’ hello’, ’ word’]
s = 'hellohahaHahellohellohahaHahello'
s.partition(‘ha’)按分隔条件将字符串分隔三部分,分隔条件前,分隔条件,分隔条件后(‘hello’, ‘ha’, ‘haHahellohellohahaHahello’)
s.rpartition(‘ha’)从后往前(‘hellohahaHahellohelloha’, ‘ha’, ‘Hahello’)
字符串合并
s = 'hello world aaa'
‘-’.join(s)# h-e-l-l-o- -w-o-r-l-d- -a-a-a
ss=['hello', 'world', 'aaa']
‘-’.join(ss)hello-world-aaa
‘’.join(ss)helloworldaaa
字符串判断
‘123456’.startswith(‘123’)是否以123开头
‘123456’.endswith(‘123’)是否以123结尾
‘hel’.isupper()是否都为大写
‘hwl’.islower()是否都为小写
‘123abc’.isalpha()是否都为字母
‘1223gew’.isalnum()是否都为数字或字母
‘1234’.isdigit()是否都为数字
‘\n’.isspace()是否是空白字符,包括空格,换行符\n,制表符\t
字符转大小写
a.upper()全转大写
a.lower()全转小写
print(a.title()将每个单词首字符转大写
print(a.capitalize()将地体格单词首字母转大写
字符串对齐
a.center(11)按给定宽度居中对其
a.center(11,‘_’)空白部分用_填充
a.rjust(11)左对齐
a.ljust(11)右对齐
去除空格
a.strip()去除两边空白
a.lstrip()去除左侧空白
a.rstrip()去除右侧空白

函数

def add(a, b):
    c = a+b
    return c

a = 5
b = 2
d = add(a, b)
print(d)

返回多个值

def ad():
	a = 0
	b = 1
	return a, b

print(ad())
# (0,1) 

不定长参数

def ad(*args):
    s = 0
    for i in args:
        s += i
    print(s, args)

ad(1, 2)      # 3 (1, 2)
ad(1, 2, 3)   # 6 (1, 2, 3)
ad(1,2,3,4)   # 10 (1, 2, 3, 4)

当定义函数时,如果函数的参数想接收任意类型和个数,需要如下格式

def ad(*args, **kwargs):

混合参数

def ad(a, b, *args, **kwargs):

不定长参数二次传递

def ad(*args):
    print(*args) #1 2 3 4
    print(args) # (1, 2, 3, 4)
    dis(*args) # *args手动解包


def dis(a, b, c, d):
    print(a, b, c, d)  # 1 2 3 4

ad(1,2,3,4)

函数名作为数据赋值给另一个变量

def ad():
    print('hello')

ad()
# 将一个函数的引用赋值给另一个变量
a = ad     # hello
print(a)   # <function ad at 0x000001E0DD3504A0>
print(ad)  # <function ad at 0x000001E0DD3504A0>
a()        # hello
def ad():
    print('hello')

def display():
    print('display')
# 实现一个可以调用另一个函数的函数
def call_function(func):
    func()

call_function(ad)       # hello
call_function(display)  # display

lambda匿名函数

函数中只能写简单的函数,不能使用return,if,while,for-in,可以使用if实现三目运算。一般不能实现复杂的功能,只能实现简单的功能,使用时一般用于一次性使用的场景

func = lambda: 1+1
print(func) #<function <lambda> at 0x00000215B83B04A0>
print(func()) # 2

func = lambda x: print(x ** 10)
func(2) # 1024

func = lambda x, y: x if x > y else y
print(func(1, 2)) # 2

高阶函数(map,reduce)

高阶函数map
第一个参数一参数系列调用function函数,返回每次function函数返回值的新列表

a = [1,2,3,4]
def ad(x):
    return x ** 2

result = map(ad, a)
print(result, list(result))
# <map object at 0x000002BCFE1697B0> [1, 4, 9, 16]
a = [1,2,3,4]
result = map(lambda n: n ** 4, a)
print(list(result)) # [1, 16, 81, 256]

reduce函数对序列中元素进行累计

import functools

a = ['h', 'e', 'l', 'l', 'o']
result = functools.reduce(lambda s1, s2: s1 + s2, a)
print(result) # hello

a = [1, 2, 3, 4, 5]
result = functools.reduce(lambda s1, s2: s1 + s2, a)
print(result) # 15

filter过滤序列

a = [1, 2, 3, 4, 5, 6]
def ad(x):
    return x % 2 == 0

result = filter(ad, a)
print(list(result)) # [2, 4, 6]
a = ['124', '34t', 'aqweg', '1234', '23ga']

# 过滤出所有数字字符串
num = filter(lambda s: s.isdigit(), a)
print(list(num)) # ['124', '1234']

文件

参数类型
r只读方式打开,指针在文件开头。默认方式
rb二进制只读方式打开,指针在文件开头
r+读写,指针在开头
rb+二进制读写,指针在开头
w写入,存在则覆盖,不存在则创建
wb二进制写入,存在则覆盖,不存在则创建
w+读写,存在则覆盖,不存在则创建
wb+二进制读写,存在则覆盖,不存在则创建
a追加,存在则指针方末尾,不存在则创建
ab二进制追加,存在则指针方末尾,不存在则创建
a+读写,存在则指针方末尾,不存在则创建
ab+二进制追加,存在则指针方末尾,不存在则创建

打开关闭文件

# 打开文件
file = open('a.txt','r')
# 关闭文件
file.close()

# 打开文件
file = open('a.txt','r')
print(file.read()) # 读取整个文件
print(file.read(5)) # 读取文件前5个字节
# 一字节一字节的读
while True:
	content = file.read(1)
	if content == '':
		break
	print(content, end='')
	
print(f.readline().strip()) # 读取第一行
print(f.readline().strip()) # 读取第二行
print(f.readlines())  # 读取所有,以列表形式,一行为一元素
for a in file:
    print(a.strip())  # 一行一行的读
# 关闭文件
file.close()

file = open('a.txt','w')
file.write("aaf\nferg")  # /n输入多行
file.close()

with open('a.txt','w') as f:
    f.write("af\n")
    f.write("qtw")
    f.close()

常用文件和文件夹操作(os模块)

import os
# 文件重命名
os.rename("a.txt", "new.txt")
# 删除文件
os.remove("new.txt")
# 创建文件夹
os.mkdir("a")
# 获取当前目录
os.getcwd()
# 改变默认目录
os.chdir("../")
# 获取目录列表
os.listdir("./")
# 删除文件夹
os.rmdir("a")

class Aaaa:
    def aa(self):
        print('hello')

class Bbbb():
    def ad(self):
        print('hello')

class Cccc(object):
    def ad(self):
        print('hello')

实例化对象

class Person(object):
    def aa(self, b):
        print(b)

t = Person()
print(t)  # <__main__.Person object at 0x00000143A07852D0>
t.aa(5)   # 5

动态绑定
实例化对象后,为该对象添加一个属性
动态为对象绑定属性时,给哪个对象绑定了属性,只能对哪个对象有该属性,其他对象没有该属性
如果在方法中引用了该属性,那么没有该属性的对象调用这个方法时会报错

class Person(object):
    def aa(self, b):
        print(self.name, b)

t = Person()
t.name = 'A ='
print(t)  # <__main__.Person object at 0x00000262203F5190>
t.aa(5)   # A = 5

__init__方法:该方法会在创建对象的时候自动执行,用于初始化对象

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

t = Person('Tom', 24)
print(t.name, t.age) # Tom 24

__str__方法:格式化对象,返回一个字符串值

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

    # 默认没有实现__str__方法,那么print(t)打印对象会打印  <__main__.Person object at 0x000002C506609590>
    # 如果想按自己的格式显示,需要在类中实现该方法
    def __str__(self):
        # 实例化后,print(t)就会运行这里面的打印,打印如下内容,而实际的打印内容为空,这里返回的是空
        print(self.name, self.age)
        # 该函数一定要返回字符串

        # 可以不在这里输出,格式化之后返回个字符串,然后再外面输出
        # s = self.name.ljust(10) + str(self.age.ljust(5))
        # return s

        return ''

t = Person('Tom', 24)
# 上面有str方法,下面打印就不是<__main__.Person object at 0x000002C506609590>
# 而是按str里面的格式输出,即 Tom 24
# 这输出的Tom 24实际上是str里面的输出
# 下面的语句打印实际上是空的,上面返回的是空字符串
# 可以参数print('|'+str(t))看出来
# 上面可以格式化字符串然后返回s,下面的语句就会有输出
print('|'+ str(t) +  '|')
'''
Tom 24
||
'''

__del__方法:销毁对象,回收释放资源

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

    def __del__(self):
        print('del run ...')

t = Person('Tom', 24)
# 执行下面代码会自动调用del方法删除对象,释放资源
del t

类的复合:在设立一个类的时候,类中包含其他类的对象

# 设计两个类
class Car(object):
    def __init__(self, name):
        self.name = name
    def bark(self,n):
        print('buy '+str(n))

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

    # 为人添加一个拥有车的方法
    def add_car(self, car):
        self.car = car

    def buy_car(self, n):
        self.car.bark(n)

tom = Person('Tom', 20)
tom.add_car(Car('car'))
tom.buy_car(3)  # buy 3

类属性

公有属性

'''
public 公有
private 私有
protected 保护

定义属性时没有定义则为公有
如果属性或方法前加两个下划线前缀,则认为是私有
'''
class Account(object):
    def __init__(self, name, balance):
        self.name = name
        self.balance = balance
    def show_info(self):
        print(str(self.name) + '有' + str(self.balance) + '元')

jack = Account('Jack', 1000)
print(jack.name, jack.balance) # Jack 1000
jack.show_info() # Jack有1000元**加粗样式**

私有属性:只能在类的内部使用,可以通过父类的公有方法调用

class Account(object):
    def __init__(self, name, balance):
        self.__name = name
        self.__balance = balance
    def show_info(self):
        print(str(self.__name) + '有' + str(self.__balance) + '元')
    def get_name(self):
        return self.__name

jack = Account('Jack', 1000)
# 这里不能调用私有属性,只能通过公有方法调用
# print(jack.name, jack.balance)
print(jack.get_name())  # Jack
jack.show_info() # Jack有1000元

私有方法:只能在类的内部使用,或在外部通过共有方法间接使用

class Account(object):
    def __init__(self, name, balance):
        self.__name = name
        self.__balance = balance
    # 属性或方法前加两个下划线前缀,则认为是私有
    def __show_info(self):
        return str(self.__name) + '有' + str(self.__balance) + '元'
    def get_name(self):
        return self.__show_info()

jack = Account('Jack', 1000)
# 私有方法不能调用,只能通过公有方法调用
# jack.show_info()
print(jack.get_name())  # Jack有1000元

继承

继承:子类不能使用父类的私有属性和私有方法

# 父类
class A(object):
    def __init__(self):
        self.num = 10

    def print_num(self):
        print(self.num)

# 子类
class B(A):
    def ad(self):
        print('hello')

cc = B()
# 继承父类方法
cc.print_num() # 10
# 子类方法
cc.ad()  # hello

子类提供init方法后,在使用子类实例化对象时,就会调用子类自己的init初始化方法,就不会调用父类的init方法,这时没有父类的属性,如果想要得到父类的属性,需要执行父类的init方法(父类名.init())

# 父类
class A(object):
    def __init__(self, num):
        self.num = num

    def print_num(self):
        print(self.num)

# 子类
class B(A):
    def __init__(self, name, num):
        A.__init__(self, num)
        self.name = name
    def ad(self):
        print('hello')

cc = B('Tom', 1000)
# 继承父类方法
cc.print_num() # 1000
# 子类方法
cc.ad()  # hello

重写父类方法及强制调用父类方法

# 父类
class A(object):
    def __init__(self, num):
        self.num = num

    def print_num(self):
        print('hello')

# 子类
class B(A):
    def print_num(self):
        A.print_num(self)
        print('world')

cc = B(1000)
# 继承父类方法
cc.print_num()

多层继承

# 父类
class A(object):
    def __init__(self):
        print('a class')

# 子类
class B(A):
    def __init__(self):
        A.__init__(self)
        print('b class')

class C(B):
    def __init__(self):
        B.__init__(self)
        print('c class')

# c等调用A类和B类的属性和方法
c = C()
'''
a class
b class
c class
'''

多继承

# 父类
class A(object):
    def __init__(self):
        print('a class')

# 子类
class B(A):
    def __init__(self):
        A.__init__(self)
        print('b class')

class C(A):
    def __init__(self):
        A.__init__(self)
        print('c class')

class D(B, C):
    def __init__(self):
        B.__init__(self)
        C.__init__(self)
        print('d class')

# d拥有A类B类和C类的属性和方法
# 这里A类输出会打印多次,这个问题可以在super方法解决
d = D()
'''
a class
b class
a class
c class
d class
'''

super方法,减少父类多次初始化(多个传参可以利用*args简化)(super可简化括号内不带参数)

# 父类
class A(object):
    def __init__(self):
        print('a class')

# 子类
class B(A):
    def __init__(self):
        super(B, self).__init__()
        # super可简化为如下
        # super().__init__()
        print('b class')

class C(A):
    def __init__(self):
        super(C, self).__init__()
        # super().__init__()
        print('c class')

class D(B, C):
    def __init__(self):
    	# 如果要传参数,细节在__init__的括号里
    	# super(D, self).__init__(name, **args)
        super(D, self).__init__()
        # super().__init__()
        print('d class')

# d拥有A类B类和C类的属性和方法
# 这里A类输出会打印多次,这个问题可以在super方法解决
d = D()
'''
a class
c class
b class
d class
'''

类的继承书写顺序会影响mro顺序

# 父类
class A(object):
    pass

# 子类
class B(A):
    pass

class C(A):
    pass

# class D(B, C): # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
#     pass

class D(C, B):
    pass

print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

多重多继承时,方法的查找顺序也参考MRO

# 父类
class A(object):
    def show(self):
        print('A show')

    def info(self):
        print('A info')

# 子类
class B(A):
    def show(self):
        print('B show')
    def info(self):
        print('B info')

class C(A):
    def show(self):
        print('C show')

class D(C, B):
    def show(self):
        print('D show')

d = D()
# 优先找D里面的,如果没有,则找C里面,如果没有,再找B里面,都没有,则找A里面
d.show() # D show
# 优先找D里面的,如果没有,则找C里面,如果没有,再找B里面,都没有,则找A里面
d.info() # B info

'''
# 如果要在找完C之后直接找A,可以在C类里面添加内容
class C(A):
    def show(self):
        super().info() # 或A.info()
        print('C show')
'''

多态、类属性、类方法

多态:调用一个方法时,得到的结果不同,多态是由继承类实现的(闯入参数不同,输出不同)

class A(object):
    def show(self):
        print('A show')

class B(object):
    def show(self):
        print('B show')

class C(object):
    def info(self, a):
        a.show()

c = C()
c.info(A())  # A show
c.info(B())  # B show

类属性
实例属性和实例方法只能由实例对象调用(对象名.xxx)。
类属性可以使用实例对象来引用,但不能修改(修改的只是实例对象的)
一般情况,类属性只使用类对象来调用(可以在外部修改)(类对象.类属性)

# 当定义类属性时,相当于这个类中的全局变量
# 该类所有对象都可以调用该属性
class A(object):
    aa = 'aaa'

a = A()
print(a.aa) # aaa
# 修改
A.aa = 'bbb'

对象保存的内容

class A(object):
    def __init__(self, name):
        self.name = name
        self.__age = 1

    def public_method(self):
        print('公有方法')

    def __pricate_method(self):
        print('私有方法')

tom = A('Tom')
# __dict__用来保存当前对象的所有成员
print(A.__dict__)
# {'__module__': '__main__', '__init__': <function A.__init__ at 0x000001E6F2C90860>, 'public_method': <function A.public_method at 0x000001E6F2C90900>, '_A__pricate_method': <function A.__pricate_method at 0x000001E6F2CC94E0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
print(tom.__dict__)
# {'name': 'Tom', '_A__age': 1}

tom.public_method()
# 公有方法
A.public_method(tom)
# 公有方法

类方法:类方法中不能使用self,但可以使用cls(用来表示当前类对象,这个参数是自动传递的,可用于类属性)。一般设计类的时候,如果有类方法,这个类一般不会实例化对象,直接使用类对象来操作(如:数学函数类),一般用来定义工具类的使用

class MyMath(object):
    # 定义类属性
    n = 10
    # 标准格式
    @classmethod  # 这是一个修饰器,用来表示下面的方法是一个类方法
    def sum(cls, *args):
        # print(cls.n)
        m = 0
        for i in args:
            m += i
        return m

    def show(cls):
        print('hello')

# 执行类方法
print(MyMath.sum(1, 2, 3))
m = MyMath()
print(m.sum(1, 2, 3))

'''
上面show前面没有@classmethod,使用MyMath.show()会报错
只能使用MyMath.show(MyMath)
'''

静态方法:不接收任何默认参数(实例对象或类对象),静态方法其实就是对普通方法使用类进行整合(普通函数一样,只是在类内)

class MyMath(object):
    # 定义类属性
    n = 10
    # 标准格式
    @staticmethod
    def sum(data):
        print(MyMath.n, data)

a = MyMath()
a.sum('abc')  # 10 abc
MyMath.sum('abc')  # 10 abc

模块

模块:一个py文件就是一个模块,当在一个py文件中要使用另一个py文件时,需要在这个py文件里面导入另一个py文件(即导入模块)

自定义模块函数test.py

n = 1
def show():
    print('show')

class Cat(object):
    def show(self):
        print('Cat show')

main.py使用import导入自定义模块

# 导入模块式会执行模块内的所有代码
import test

test.show() # show

a = test.Cat()
a.show()  # Cat show

或者在main.py中使用from import导入自定义模块

# 导入模块式会执行模块内的所有代码
from test import n
from test import Cat
from test import show
# from test import show as sh
# from test import *

print(n)  # 1
show()
a = Cat()  # show
a.show()   # Cat show

导入模块常见问题
test.py

a = 1   # 全局变量,模块间的公有变量
_b = 2  # 私有变量,文件内的私有变量
__c = 3 # 私有变量,一般出现在类中

main.py中按如下方式导入可以输出

import test

print(test.a)
print(test._b)
print(test.__c)

如果使用下面方法,则会报错无法输出私有成员

from test import *

print(a)
# print(_b)  # 报错
# print(__c)  # 报错

可以使用__all__修改from import导入规则,但是公有的会报错

# 一般不会在这里使用__all__属性
__all__ = ['_b', '__c']

a = 1
_b = 2
__c = 3
from test import *

# print(a)  # 报错
print(_b)
print(__c)

命名冲突问题
test.py

a = 1

main.py

from test import *

def a():
    print('hello')
    return 0

# 这里调用的是这里的a函数,而不是test类中的变量a
# 谁最后写谁生效
print(a)

'''
# 可以使用import解决冲突
import test

def a():
    print('hello')
    return 0
    
print(test.a)
'''

__name__方法:在获取模块名时,会有两种效果,如果当前模块式主动执行的,__name__得到的结果是字符串__main__,如果是被其他函数调用执行的,__name__得到的结果是当前模块文件的文件名

# name一般用来表示程序入口
print(__name__)

if __name__ == 'main':
    print('程序入口')

使用包中的模块
包:文件夹,即,模块在文件夹中
在direc目录里面有文件a.py,内容如下

m = 1

main.py文件内容如下

# 导入direc中的a模块
import direc.a

print(direc.a.m)

'''
或者使用下面的方法导入
from direc import a
print(a.m)
或者
from direc.a import m
print(m)
或者
from direc.a import *
'''

导入模块的时候,但如果只导到包的位置(包的目录),这个包去找模块时会报错,应为不确定要导入哪个模块,需要在包中的__init__.py中高数解释器在导入包的时候应该导入那些模块
如,导入cn/itcast/web/a.py(只有一行代码m=1),和cn/itcast/web/b.py(只有一行代码m=1),下面方法会报错

# 只导到了包的目录web
import cn.itcast.web as web
print(web.a.m)  # 报错

在cn/itcast/web/__init__.py做如下修改,上面的web.a.m就不会报错

from . import a, b

'''
或者使用all方法,该方法不通用
__all__ = ['a', 'b']  # a.py  b.py
但是这方法不通用,只能用from import调用,不能用import调用
from cn.itcast.web import *
print(a.m)
'''

异常处理

NameError:没有定义变量直接使用异常
TypeError:类型异常
ValueError:
AttributeError:属性异常
SyntaxError:语法错误异常
IndexError:索引异常
try:
    可能出现异常的代码
except Exception:
    当发生异常时,处理异常代码
s = 'hello'
try:
    # 这句代码查找不到,异常,不执行
    print(s.index('0'))
except ValueError:
    # 上面异常,执行下面语句
    print('发生错误')
try:	
    print('可能出现异常的代码')
    f = open('a.txt', 'r')
except Exception as e:
    print('发生异常时执行')
    print(e)
else:
    print('当没有出现异常时执行')
    print(f.read())
finally:
    print('无论是否出现异常,都会执行')
    # 这个模块一般用于资料关闭或回收,如文件关闭,网络连接关闭,数据库关闭
    f.close()

自定义抛出异常类
test.py

# 自定义异常类
class PhoneNumberNotDigitError(Exception):
    pass

# 定义一个用来判断手机号位数是否合法的异常类
class PhoneNumberLengthError(Exception):
    def __init__(self, msg):
        self.__msg = msg

    def __str__(self):
        return self.__msg

def get_phone_number():
    pn = input('请输入手机号')
    if pn.isdigit() == False:
        # 抛出异常
        raise PhoneNumberNotDigitError()
    elif len(pn) != 11:
        raise PhoneNumberLengthError('手机号位数不对')

    print('输入的手机号合法')

main.py

from test import *
try:
    num = get_phone_number()
except (PhoneNumberLengthError, PhoneNumberNotDigitError) as e:
    print(e)
else:
    print(num)

闭包

闭包:闭包可以保存外部函数内的变量,不会随着外部函数调用完而销毁。由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。闭包就是内函数的引用+外函数的执行环境

闭包条件

在函数嵌套(函数里面再定义函数)的前提下
内部函数使用了外部函数的变量(还包括外部函数的参数)
外部函数返回了内部函数

# 像下面代码,如果函数内部的变量在函数外面不能使用,只能通过函数调用才能使用

# def show():
#     n = 1
#     print(n)
#
# show()
# print(n)

闭包的定义格式

def show():
    n = 1
    def in_show():
        print(n)

    # 在外函数返回内函数的引用时,不能带括号
    return in_show

ret = show()
print(ret)
ret()

闭包的使用(和类对比)
类的方式实现

class Person(object):
    def __init__(self, name):
        self.name = name
    def say(self, msg):
        print(self.name + ' Say: ' + msg)

tom = Person('tom')
jack = Person('jack')
tom.say('Hello')
jack.say('World')

闭包方式实现:比类更轻量

def person(name):
    def say(msg):
        print(name + " Say: "+ msg)
    return say

tom = person('Tom')
jack = person('Jack')
tom('Hello')
jack('World')

修改闭包内使用外部变量

错误方法:这种方式修改没用,不能真正修改外部n的值

# 这种方式修改没用,不能真正修改外部n的值
def show():
    n = 1
    def inner():
        n = n + 10
        
    return inner

func = show()
func()

正确方法:如果不声明会报未知边界错误,如果当在内函数中要修改外函数的变量时,需要使用 nonlocal声明一下,使用的变量是一个外函数定义的变量

def show():
    n = 1
    def inner():
        nonlocal n
        n = n + 10
        print(n)
    return inner

func = show()
func()
func()

装饰器

装饰器就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数

装饰器的功能特点:

1不修改已有函数的源代码
2不修改已有函数的调用方式
3.给已有函数增加额外的功能

案例:比如对一个函数进行计时看需要运行多久,通常我们在前面后面加个计时,如果多个函数需要计时,那多个函数都需要添加,这样也不符合装饰器要求,通常编写的方式如下

'''
# 源代码
def show():
    n = 0
    for i in range(10000000):
        n = n + i
'''

# 添加计时方式一
import time
def show():
    n = 0
    start = time.time()
    for i in range(10000000):
        n = n + i
    end = time.time()
    print(end-start)

show()

'''
# 添加计时方式二

import time
def show():
    n = 0
    for i in range(10000000):
        n = n + i

def count_time(func):
    start = time.time()
    func()
    end = time.time()
    print(end - start)

count_time(show)

'''

方式三:使用闭包方式

import time


def show():
    n = 0
    for i in range(10000000):
        n = n + i
    print(n)


def count_time(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(end-start)
    return inner


# 装饰器在装饰函数时的原理
show = count_time(show)   # show -> inner
# 下面的代码是使用者写的,并没有改变原有的调用方式
show()

闭包的简写方式(标准格式):像上面闭包方式书写,每次都要编写show = count_time(show),Python提供了一个简单的书写格式:@装饰器名称,代码如下:

import time


def count_time(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print('时间: ', end-start)
    return inner


@count_time  # show = count_time(show)
def show():
    n = 0
    for i in range(10000000):
        n = n + i
    print(n)

@count_time   # ad =count_time(ad)
def ad():
    print('Hello World')

# 下面的代码是使用者写的,并没有改变原有的调用方式
show()
ad()

通用装饰器:上面的不通用,如果有参数的时候就会出错。因为装饰器在装饰函数时,需要根据被装饰的函数定义的格式来适当的接收参数和返回值所以闭包函数中的内函数也要相应的接收数据和返回数据

通用方式:可以任意个参数

# 可以装饰任意函数
def other(func):
    def inner(*args, **kwargs):
        print('装饰1')
        ret = func(*args, **kwargs)
        print('装饰2')
        return ret
    return inner


@other
def show(msg):
    return 'Hello World...'+msg

print(show('Show'))
'''
装饰1
装饰2
Hello World...Show
'''

多个装饰器装饰一个函数:从下到上装饰,从上到下执行

# 第一个闭包
def other1(func):
    def inner(*args, **kwargs):
        return '<div>' + func(*args, **kwargs) + '</div>'
    return inner

# 第二个闭包
def other2(func):
    def inner(*args, **kwargs):
        return '<p>' + func(*args, **kwargs) + '</p>'
    return inner

# 从下到上装饰,从上到下执行
@other1
@other2
def show():
    return "Hello World"


print(show())
'''
<div><p>Hello World</p></div>
'''

多个装饰器过程

# 第一个闭包
def other1(func):
    def inner(*args, **kwargs):
        print("装饰器1-1")
        func(*args, **kwargs)
        print("装饰器1-2")
    return inner

# 第二个闭包
def other2(func):
    def inner(*args, **kwargs):
        print("装饰器2-1")
        func(*args, **kwargs)
        print("装饰器2-2")
    return inner

# 从下到上装饰,从上到下执行
@other1
@other2
def show():
    print('内容')


show()
'''
装饰器1-1
装饰器2-1
内容
装饰器2-2
装饰器1-2
'''

类装饰器

class Person():
    def __init__(self, func):
        self.func = func
    # 当一个类中实现了下面的call函数
    # 那么该类的实例对象就变成了可调用对象,也就是说,实例对象后面可以加()
    def __call__(self, *args, **kwargs):
        print('装饰1')
        ret = self.func(*args, **kwargs)
        print('装饰2')
        return ret


@Person
def show():
    print('Hello World')
show()

带参数的装饰器

def set_args(msg):
    def set_func(func):
        def inner():
            print('装饰1 '+msg)
            func()
            print('装饰2 ')
        return inner
    return set_func


@set_args('HelloWorld!!!')
def show():
    print('Hello World')

show()
'''
装饰1 HelloWorld!!!
Hello World
装饰2 
'''

案例:通过参数由路径找到对应资源

# 路由表字典,运行程序会自动更新路由
router_table = {}

#定义一个用来进行自动维护路由的装饰器,(带参)
def router(url):
    def wrapper(func):
        def inner():
            print('inner - ', func)
            func()
        # 在这里来维护路由表
        router_table[url] = inner
        return inner
    return wrapper

@router('index.html')
def index():
    print('首页')

@router('center.html')
def center():
    print('个人中心')

def error():
    print('不存在')


def request_url(url):
    # 先指定指向错误函数
    func = error
    # 判断url是否在字典中
    if url in router_table:
        func = router_table[url]
    # 执行函数
    func()

print(router_table)
request_url('index.html')
request_url('center.html')
request_url('aaa.html')

日志

DEBUG:程序调试bug时使用
INFO:程序正常运行时使用
WARNING:程序未按期运行时使用,但并不是错误,如:用户登录密码错误
ERROR:程序出错误时使用,如:lO操作失败
CRITICAL:特别严重的问题,导致程序不能再继续运行时使用,如:磁盘空间为空,一般很少使用
默认的是WARNING等级,当在WARNING或WARNING之上等级的才记录日志信息
日志等级从低到高的顺序是: DEBUG<INFO<WARNING<ERROR<CRITICAL

import logging

logging.debug('Debug...')
logging.info('Info...')
logging.warning('Warning...')
logging.error('Error...')
logging.critical('Critical...')
'''
WARNING:root:Warning...
ERROR:root:Error...
CRITICAL:root:Critical...
'''

利用函数logging.basicConfig可以设置输出等级,也可以将输出保存至文件,然后每天输入,输出的内容都在文件中
logging.basicConfig(level=logging.INFO, format='%(levelname)s-%(filename)s-%(lineno)d-%(asctime)s-%(message)s', filename='log.txt', filemode='w')

lecel:输出等级
format:格式,%(levelname)s名称,%(filename)s程序名,%(lineno)d当前行号,%(asctime)s打印日志时间,%(message)s打印日志信息
filename:输出到某文件
filemode:打开文件格式,w写,a追加

import logging

# 设置记录日志的级别,默认warning级别,低级的没有输出
logging.basicConfig(level=logging.INFO, 
                    format='%(levelname)s-%(filename)s-%(lineno)d-%(asctime)s-%(message)s', 
                    filename='log.txt', 
                    filemode='w')
logging.debug('Debug...')
logging.info('Info...')
logging.warning('Warning...')
logging.error('Error...')
logging.critical('Critical...')

log.txt输出文件如下

INFO-main.py-6-2023-03-29 15:42:34,333-Info…
WARNING-main.py-7-2023-03-29 15:42:34,333-Warning…
ERROR-main.py-8-2023-03-29 15:42:34,333-Error…
CRITICAL-main.py-9-2023-03-29 15:42:34,333-Critical…

property属性

property属性就是负责把一个方法当做属性进行使用,这样做可以简化代码使用,定义property属性有两种方式:装饰器方式、类属性方式

类属性方式简化属性操作:可以使用属性的方式间接访问类的私有属性,简化操作(property

class Person(object):
    def __init__(self):
        self.__age = 0
        self.__name = 'Jack'

    # 当获取age属性的时候会执行该方法
    def get_age(self):
        return self.__age

    # 当设置age属性的时候会执行该方法
    def set_age(self, new_age):
        self.__age = new_age
    
    def set_name(self):
        pass
    def get_name(self):
        pass
    
    # 类属性方式的property属性
    age = property(get_age, set_age)
    name = property(get_name, set_name)

p = Person()
print(p.age)  # 0
p.age = 20
print(p.age)  # 20

装饰器方式:如果使用装饰器形式来简化属性操作时,@property 只能用来装饰 get 方法,被装饰的属性方法前面不需要在使用 set 或 get 做为前缀了
property一定写在对应的setter前面,否则报错

class Person(object):
    def __init__(self):
        self.__age = 0
        self.__name = 'Jack'

    # 当获取age属性的时候会执行该方法
    @property
    def age(self):
        return self.__age

    # 当设置age属性的时候会执行该方法
    @age.setter
    def age(self, new_age):
        self.__age = new_age

    @property
    def name(self):
        return self.__name
    
    @name.setter
    def name(self, username):
        self.__name = username


p = Person()
print(p.age)  # 0
p.age = 20
print(p.age)  # 20
p.name = 'Jack'
print(p.name)

with读写文件

with读写文件:向文件中写入数据的示例代码,文件使用完后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的

# 1、以写的方式打开文件
f = open("1.txt", "w")
# 2、写入文件内容
f.write("hello world")
# 3、关闭文件
f.close()

这种写法可能出现一定的安全隐患,比如以读模式打开,然后写入输入

# 1、以写的方式打开文件
f = open("1.txt", "r")
# 2、写入文件内容
f.write("hello world")
# 3、关闭文件
f.close()

由于文件读写时都有可能产生IOError,一旦出错,后面的f.close0就不会调用,为了保证无论是否出错都能正确地关闭文件,我们可以使用try … finally来解决

try:
    # 1、以写的方式打开文件
    f = open("1.txt", "r")
    # 2、写入文件内容
    f.write("hello world")
except IOError as e:
    print("文件操作出错:", e)
finally:
    # 3、关闭文件
    f.close()

这种方法虽然代码运行良好,但是缺点就是代码过于冗长并且需要添加try-except-finally语句,不是很方便。在这种情况下Python提供了 with 语句的这种写法,既简单又安全,并且 with 语句执行完成以后自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作。

with open("1.txt", "w") as f:
    f.write("Hello World")

上下文:自定义上下文管理器

enter:表示上文方法,需要返回一个操作文件对象
exit:表示下文方法,with语句执行完成会自动执行,即使出现异常也会执行该方法。

class Myopen(object):
    def __init__(self, file, mode):
        self.file = file
        self.mode = mode

    def __enter__(self):
        # 这个方法是用来进入上下文环境的文件,用来做初始化的准备工作
        self.file_handle = open(self.file, self.mode)
        return self.file_handle

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 这个方法是在退出上下文环境时,一般用来做资源的回收
        self.file_handle.close()
        if exc_type:
            print('有异常发生')
        # 该函数默认返回 False,将异常抛出,如果不想抛出异常,可以将返回值改成 True,可以在该函数中处理异常
        return True


with Myopen('1.txt', 'w') as f:
    f.write('Hello World')

生成器

生成器:根据程序员制定的规则循环生成数据,当条件不成立时则生成数据结束。数据不是一次性全部生成出来,而是使用一个,再生成一个,可以节约大量的内存。创建生成器的方式:生成器推导式、yield 关键字

生成器推导式

# 列表推导式
c_list = [i for i in range(10)]
print(c_list)
print(type(c_list))

# 生成器
# 生成器用来实现惰性求值,什么时候用,什么时候生成
c_generator = (i for i in range(10))
print(c_generator)
print(type(c_generator))

# 循环输出值,最后一个之后会出现异常,用try处理
# while True:
#     try:
#         value = next(c_generator)
#         print(value, end=' ')
#     except Exception as e:
#         print(e)
#         break
# 循环输出值,自动处理异常
for i in c_generator:
    print(i, end=' ')

yield 关键字:只要在def函数里面看到有 yield 关键字那么就是生成器

def get_value(n):
    for i in range(n):
        # yield 关键字的作用是将这个函数变成一个生成器对象
        # 执行时,解释器遇到 yield 后会中断代码的执行,并返回yield后的数据,下一次再执行时,会恢复前面yield中断的状态,继续执行
        yield i


g = get_value(10)
print(g)
print(type(g))


# 循环输出值,最后一个之后会出现异常,用try处理
# while True:
#     try:
#         value = next(g)
#         print(value, end=' ')
#     except Exception as e:
#         print(e)
#         break
# 循环输出值,自动处理异常
for i in g:
    print(i, end=' ')

实例:输出前一个数是前两个数的和(斐波那契数列:0 1 1 2 3 5 8 13 21 34 …)

def fibonacci(n):
    a = 0
    b = 1
    current_index = 0
    while current_index < n:
        result = a
        a, b = b, a+b
        current_index += 1
        yield result


g = fibonacci(10)
for i in g:
    print(i, end=' ')

深拷贝、浅拷贝

对于可变对象来说,浅拷贝只拷贝第一层数据,深拷贝会逐层进行拷贝;对于不变对象来说,无论深浅拷贝,都不会进行拷贝,只是引用的赋值

浅拷贝使用copy.copy()
深拷贝使用copy.deepcopy()

# 当对不可变对象对象进行赋值时,实际并不会改变原值空间的内容,会开辟一个新空间来保存新数据并指向
# 引用的赋值
a = 1
b = a
print(a, b)  # 1 1
# 地址都是一样的
print(id(a), id(b), id(1))  # 140704504275752 140704504275752 140704504275752

a = 2
print(a, b)  # 2 1
# 地址都是一样的
print(id(2), id(a), id(b), id(1))  # 140704504275784 140704504275784 140704504275752 140704504275752

不可变对象:无论深浅拷贝,都属于是引用的赋值

import copy

a = 1
b = copy.copy(a)   # 浅拷贝
print(id(1), id(a), id(b))  # 140704504275752 140704504275752 140704504275752

c = copy.deepcopy(a)
print(id(1), id(a), id(c))  # 140704504275752 140704504275752 140704504275752

可变对象的拷贝

浅拷贝:值不变,地址相同
深拷贝:值不变,地址不同

# 浅拷贝
cl1 = [1, 2, 3, 'a', 'b']
cl2 = copy.copy(cl1)
# 如果拷贝成功: 1.值相同,2.地址不同
print(cl1)   # [1, 2, 3, 'a', 'b']
print(cl2)   # [1, 2, 3, 'a', 'b']
print(id(cl1))   # 2662025924096
print(id(cl2))   # 2662025929728

cl1[0] = 111
print(cl1)   # [111, 2, 3, 'a', 'b']
print(cl2)   # [1, 2, 3, 'a', 'b']
print(id(cl1))   # 2662025924096
print(id(cl2))   # 2662025929728



# 深拷贝
cl1 = [1, 2, 3, 'a', 'b']
cl2 = copy.deepcopy(cl1)
# 如果拷贝成功: 1.值相同,2.地址不同
print(cl1)   # [1, 2, 3, 'a', 'b']
print(cl2)   # [1, 2, 3, 'a', 'b']
print(id(cl1))   # 1412063366656
print(id(cl2))   # 1412063372288

cl1[0] = 111
print(cl1)   # [111, 2, 3, 'a', 'b']
print(cl2)   # [1, 2, 3, 'a', 'b']
print(id(cl1))   # 1412063366656
print(id(cl2))   # 1412063372288

可变对象中保存可变数据

# 浅拷贝
a = [1, 2]
cl1 = [a, 3, 'a', 'b']
cl2 = copy.copy(cl1)
# 如果拷贝成功: 1.值相同,2.地址不同
print(cl1)   # [[1, 2], 3, 'a', 'b']
print(cl2)   # [[1, 2], 3, 'a', 'b']
print(id(cl1))   # 2425115059200
print(id(cl2))   # 2425115053440

cl1[0][0] = 111
print(cl1)   # [[111, 2], 3, 'a', 'b']
print(cl2)   # [[111, 2], 3, 'a', 'b']
print(id(cl1))   # 2425115059200
print(id(cl2))   # 2425115053440


# 深拷贝
a = [1, 2]
cl1 = [a, 3, 'a', 'b']
cl2 = copy.deepcopy(cl1)
# 如果拷贝成功: 1.值相同,2.地址不同
print(cl1)   # [[1, 2], 3, 'a', 'b']
print(cl2)   # [[1, 2], 3, 'a', 'b']
print(id(cl1))   # 2425115059200
print(id(cl2))   # 2425115053440

cl1[0][0] = 111
print(cl1)   # [[111, 2], 3, 'a', 'b']
print(cl2)   # [[1, 2], 3, 'a', 'b']
print(id(cl1))   # 2425115059200
print(id(cl2))   # 2425115053440

python中默认的拷贝方式是浅拷贝,拷贝速度快,效率高,空间少

import copy


def func1():
    a = [1, 2]
    cl1 = [a, 3]
    cl2 = copy.copy(cl1)
    print(cl1)   # [[1, 2], 3]
    print(cl2)   # [[1, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440
    cl1[0][0] = 111
    print(cl1)   # [[111, 2], 3]
    print(cl2)   # [[111, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440

def func2():
    a = [1, 2]
    cl1 = [a, 3]
    cl2 = cl1.copy()
    print(cl1)   # [[1, 2], 3]
    print(cl2)   # [[1, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440
    cl1[0][0] = 111
    print(cl1)   # [[111, 2], 3]
    print(cl2)   # [[111, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440

def func3():
    a = [1, 2]
    cl1 = [a, 3]
    cl2 = list(cl1)
    print(cl1)   # [[1, 2], 3]
    print(cl2)   # [[1, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440
    cl1[0][0] = 111
    print(cl1)   # [[111, 2], 3]
    print(cl2)   # [[111, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440

def func4():
    a = [1, 2]
    cl1 = [a, 3]
    cl2 = cl1[:]
    print(cl1)   # [[1, 2], 3]
    print(cl2)   # [[1, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440
    cl1[0][0] = 111
    print(cl1)   # [[111, 2], 3]
    print(cl2)   # [[111, 2], 3]
    print(id(cl1))   # 2425115059200
    print(id(cl2))   # 2425115053440


if __name__ == '__main__':
    func1()
    func2()
    func3()
    func4()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值