python笔记_第三周

python笔记_第三周

第十天

回调函数

回调函数就是一个被作为参数传递的函数

把函数a当做一个值 赋值给函数b的形参, 在调用函数b的时候  在函数体内 适当的实际调用函数a, 这个函数a就是回调函数

print(1)
# def -- define 定义 声明的意思
# 声明一个函数
def get_first(src_str):
    # 函数体的执行时机:函数被调用的时候
    return src_str[0]

# 调用函数
res = get_first('abc')
print(res)

# 把函数当做一个数据 赋值给f  将对应的功能赋予给了f
f = get_first

f('mean')


# 自己声明一个函数:对列表进行升序排序
'''
key 是接受一个函数:这个函数的返回值是作为排序时比较的标准
'''
def cus_sort(src_list, key=None):
    if key is None: # 要以数据原本的大小进行比较
        for i in range(1, len(src_list)):
            for j in range(len(src_list) - i):
                if src_list[j] > src_list[j+1]:
                    src_list[j], src_list[j+1] = src_list[j+1], src_list[j]
    else: # 按照key对应的函数返回值 作为比较标准
        for i in range(1, len(src_list)):
            for j in range(len(src_list) - i):
                if key(src_list[j]) > key(src_list[j+1]):
                    src_list[j], src_list[j+1] = src_list[j+1], src_list[j]
    return src_list


values = cus_sort(['old_driver','rain','jack','shanshan','peiqi','black_girl', 'rose'])
print(values)

# 根据首字母进行升序排序
# 把获取首字母这个操作封装成一个方法
names = ['old_driver','rain','jack','shanshan','peiqi','black_girl', 'rose']
values = cus_sort(names, key=get_first)#get_first就是回调函数
print(values)

第十一天

1.函数压栈[函数的执行过程]

栈:先进后出

2.形参是可变对象与不可变对象的区别

3.回调函数

被作为参数传递的函数

比如列表中排序函数 sort 有一个形参叫做key --- 这个就是接受一个函数当做值的

在函数的功能体中适当时机进行调用  这个函数就叫做回调函数


4.高阶函数

把回调函数当做形参的

map ---- 映射
	按照指定的需求把序列中的元素通过函数映射成指定的格式
	
	map接受的函数的形参数是由 传递序列数决定的
	
filter -- 筛选器
	按照函数的指定功能对序列中的元素进行筛选
	函数的返回值为布尔类型  True表示保留  False表示过滤掉
	
	这个函数只有一个形参 -- 用于接受进行校验的序列中的元素值
	
functools模块下 reduce ---- 累计器
	根据指定的函数的功能 对序列中的元素进行累计的
	函数需要有两个形参  并且有返回值  返回值是每次累计的结果

sorted --- 类似于列表中的sort方法
	列表中sort方法 只能对列表进行排序  而且影响的是列表本身 没有生成新的数据
	sorted 可以对任意序列的数据进行排序 排序之后的数据存放于列表中的

zip
	把多个序列中相同位置的数据进行组合的

5.递归算法

在声明的函数内部自己调用自己的行为 成为递归

一开始是有1对兔子 从第三个月开始 每个月都生一对兔子, 小兔子长到第三个月开始 同样每个月都生一对小兔子
问8个月之后兔子有多少对

1		2		3		4		5				6
1		1		1+1		1+1+1	1+1+1+1+1       1+1+1+1+1+1+1+1

1       1        2       3        5               8


F(1) = 1
F(2) = 1
F(n) = F(n-1) + F(n-2)  (n>=3)
===》
	n --- 未知项 -- 形参
	F ---- 函数名
	
递归一定要有基例(已知项  递归的一个出口)

6.函数嵌套

在一个函数内部 又声明了一个函数

global关键字
	在函数内部修饰全局变量的
	在函数内部修改或者声明一个全局变量 这个变量就需要使用global进行修饰
nonlocal 关键字
	在内部函数中 修饰外部函数的变量的
	函数有自己的作用域,在函数内部声明的变量仅能作用于函数内部 如果不用关键字修饰 与外界的变量没有任何关系
	
	
闭包(closure):
	在嵌套的函数中 内部函数对外层函数中的变量进行了引用,这个内层函数就叫做闭包
	在闭包中每次运行都能够记住外部函数中变量的值

7.装饰器

特殊的闭包:把内部函数作为外部函数返回值的一个闭包
作用:在不修改原本功能的基础上,为该功能增加新的内容

装饰器 -- 起的是一个修饰的作用 
声明装饰器的时候 外部函数的需要有一个形参 接受修饰的内容
新增的内容都是在内部函数中写的


怎么使用装饰器修饰功能: @语法糖
在被修饰的功能上面 @装饰器的外层函数

需求:
收藏
点赞
评论

第十二天

1.装饰器

在修饰一个内容的时候 不修改原有内容的代码,额外的增加新的功能

装饰器 --- 本质上就是一个函数嵌套  外层函数的返回值是内层函数

写的时候 会在外层函数设置一个形参 --- 用于接受被装饰的功能

本质上 --- 额外增加的内容是在内部函数中完成的


注意:
	如果这个装饰器对于多个功能有一个相同的标记 这个标记放在全局变量中
	如果这个装饰器只是针对于一个功能被多次调用的限制  这个标记放在外层函数中

练习

功能:	添加学生   删除学生
在进行操作之前校验是不是管理员 如果不是的话 提示没有权限 否则执行对应的操作


root = True

def is_root(func):
    def inner():
        global root
        if root is True:
            func()
        else:
            print('没有管理员权限')
    return inner

@is_root
def add_student():
    print('添加学生')
@is_root
def remove_student():
    print('移除学生')


add_student()
remove_student()

规范化装饰器

# 校验一个功能所执行的时间
import time

def get_time(func):
    '''
    因为被装饰的函数可能有形参 可能没有  可能有1个 也可能有多个,写形参的时候就不确定有多少个
    所以需要使用可变参数*args来操作
    因为传值的时候可以关键字形式传值 但是*args不能接受关键字形式的传值 所以需要使用**kwargs来接受关键字形式的传值
    '''
    def inner(*args,**kwargs):
        # 执行之前获取时间
        start = time.time() # 获取当前时间对应的秒数
        # 原本的功能
        result = func(*args,**kwargs)
        stop = time.time()
        print(f'功能的运行时间是{stop - start}')
        '''
        因为有的函数是有返回值的, 调用函数之后需要把结果返回到调用的位置
        因为装饰之后 本质被调用的是内部函数  需要通过内部函数把真实功能的运行结果返回
        所以需要在inner中设立一个return  把结果返回到调用的位置
        '''
        return result # 通过内部函数把结果返回到调用内部函数的位置
    return inner

@get_time  # add = get_time(func = add)
def add(a, b):
    return a + b

res = add(12, 17)
print(res)

2.包和模块

模块: 
	1.系统模块  time  random  math等等
	2.自定义模块  自己命名的py文件
	3.第三方模块
		第三方模块管理工具 pip
导入模块
	在一个py文件中 要使用其他py文件的内容, 所以需要导入标记
	导入的语法:
		import 模块名
				--- 使用模块下内容的方式 模块名.内容名
		from 模块名 import 内容名, 内容名1...
				--- 直接就使用内容名进行操作即可
		from 模块名 import *
				注意事项
					注意__all__这个字段【前后各两个下划线】
					在from 模块名 import * 这种格式的导入方式下, 如果对应的模块中定义了__all__这个字段,那就表示 咱们导入内容的时候 只能导入这个字段中列出的内容  【如果没有这个字段 那就表示都可以使用】
				__all__中提供的是建议模块中使用的内容是哪些
三方模块
	安装的指令是 pip install 工具名   【这个指令是写在 cmd 或者是 pycharm中 terminal上的】
		爬虫工具 requests
	
	更新pip的下载源 -- 把下载更新为国内下载源
		因为pip下载默认是国外的服务器上下载的 
        
直接在当前用户的目录中创建一个pip目录,如:C:\Users\xx\pip,新建文件pip.ini,内容如下

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

pycharm上也可以进行安装
	File -- settings --- project --- python interpreter   在左下方有个+号
		在下载列表中有一个manage repositorise  可以更新下载源
包
	1.增加模块的命名空间
		a.txt
			a文件夹下
			b文件夹下
	2.对模块进行分类管理
	
	类似于文件系统中的文件夹
	
	如何创建包
		在创建包的位置 右键 new -- python package
		包名的命名规范:
			遵守标识符规范
			英文都是小写的  单词和单词之间使用下划线隔开
		创建出来的包下面有一个__init__.py文件, 作用来简化包下模块内容导入的操作的
			单纯的导包的时候 就把包的所有模块的内容都导入
				import 包名 --- 其实导入的包下的__init__.py文件
	
	有了包之后 如何导入包下模块
		import 包名.包名1.模块名
				--- 使用模块下内容的方式 包名.包名1.模块名.内容名
		from 包名.包名1.模块名 import 内容名, 内容名1...
				--- 直接就使用内容名进行操作即可
		from 包名.包名1.模块名 import *
	
	起别名 as 
		import 包名.包名1.模块名 as 别名
				--- 使用模块下内容的方式 别名.内容名
		from 包名.包名1.模块名 import 内容名 as 别名
				--- 直接就使用别名进行操作即可
		

3.常用的模块

随机模块random
数学模块 math
时间模块 time / datetime
文件操作系统模块 os

第十三天

1.常用的模块

random模块
import random

# 1.choice -- 在指定的序列中随机选择一个元素
print(random.choice('qwertyuiopasdfghjklzxcvbnm'))

# 2.choices --- 在指定的序列中 选择指定个数k个可重复的随机元素
print(random.choices('qwertyuiopasdfghjklzxcvbnm', k=5))

# 3.sample --- 在指定的序列中 选择指定个数不重复的随机元素
print(random.sample('1234567890qwertyuioasdfghjklzxcvbnm', k=5))

# 4.shuffle -- 打乱指定序列的顺序
nums = list('1234567890')
print(nums) # ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']
random.shuffle(nums)
print(nums)


# 5.获取数值random - 在[0.0, 1.0)之间随机获取一个小数
print(random.random())

# 6. randint  -- 在[start, stop]这个区间中随机选择一个整数
print(random.randint(12, 100))

# 7. randrange 在[start, stop) 这个区间中随机选择一个整数
# randrange(start, stop, step) ===> choice(range(start, stop, step))
print(random.choice(range(1, 10, 2))) # 在1-10中步长为2的等差序列中随机生成一个整数 在1 3 5 7 9中随机选择一个
print(random.randrange(1, 10, 2)) # 和上面choice是等价的

print(random.choice(range(1, 100)))
print(random.randrange(1, 100)) # 这两个是等价的
math模块
import math

# 1. 圆周率
print(math.pi)

# 2. 自然常数e
print(math.e)

# 3. 向上求整
print(math.ceil(17.3)) # 18
print(math.ceil(-17.3)) # -17

# 4. 向下求整
print(math.floor(17.5)) # 17
print(math.floor(-17.5)) # -18

# 5. 绝对值
print(math.fabs(-100))

# 6.阶乘
print(math.factorial(5))

# 7. 幂数
print(math.pow(3, 3))

# 8.求对数
print(math.log2(8)) # 3.0
print(math.log10(1000)) # 3.0

# 9. 三角函数
print(math.sin(math.pi / 6)) # 0.49999999999999994

# print(0.1 + 0.2)

print(math.cos(math.pi / 3)) # 0.5000000000000001

print(math.tan(math.pi / 4)) # 0.9999999999999999

# 10. 弧度转化为角度
print(math.degrees(math.pi / 2)) # 90.0

# 11. 角度转化为弧度
print(math.radians(45)) # 0.7853981633974483

# 13. 求指定序列中元素的累乘
# print(math.prod([12, 3, 4]))   # python3.8的功能
string模块
import string
'''
whitespace = ' \t\n\r\v\f'
ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
ascii_letters = ascii_lowercase + ascii_uppercase
digits = '0123456789'
hexdigits = digits + 'abcdef' + 'ABCDEF'
octdigits = '01234567'
punctuation = r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
printable = digits + ascii_letters + punctuation + whitespace
'''
import random
# 生成验证码
code_list = random.choices(string.ascii_letters + string.digits, k=5)
code = ''.join(code_list)
print(code)
time模块
'''
time
    用于时间戳(指定的时间到1970年1月1日经历的秒数)
    跟时间戳交互的 使用time模块
datetime
    可以针对于时间进行运算 --- 计算时间差 使用datetime模块

calendar 日历模块
'''

import time

# 1. 获取当前时间 -- 时间元组格式
cur = time.localtime()
print(cur) # time.struct_time(tm_year=2021, tm_mon=3, tm_mday=31, tm_hour=9, tm_min=33, tm_sec=15, tm_wday=2, tm_yday=90, tm_isdst=0)

# 2. 获取年
year = cur[0]
print(year)

# 也可以通过字段的形式获取
month = cur.tm_mon
print(month)


# 3. 获取当前时间对应的时间戳
time_code = time.time()
print(time_code) # 1617154603.9369783

# 4.把时间戳转化为时间 --- 把时间戳转化为时间元组
date = time.localtime(time_code)
print(date)

# 5.把时间元组 转换为时间戳
time_code = time.mktime(cur)
print(time_code)

# 6.时间格式化  按照指定格式把时间元组进行格式化
# time.strftime('格式化的格式', 时间元组)
'''
    %Y  Year with century as a decimal number.  --- 年
    %m  Month as a decimal number [01,12].  --- 月
    %d  Day of the month as a decimal number [01,31]. --- 日
    %H  Hour (24-hour clock) as a decimal number [00,23]. --- 24小时制的时
    %M  Minute as a decimal number [00,59]. ---- 分
    %S  Second as a decimal number [00,61]. --- 秒
    %z  Time zone offset from UTC.  --- 时区
    %a  Locale's abbreviated weekday name. --- 星期英文简写
    %A  Locale's full weekday name. ---- 星期的英文全称
    %b  Locale's abbreviated month name. --- 月份英文简写
    %B  Locale's full month name. --- 月份的英文全称
    %c  Locale's appropriate date and time representation.
    %I  Hour (12-hour clock) as a decimal number [01,12]. --- 12小时制的时
    %p  Locale's equivalent of either AM or PM. 
    %w  星期几 
    
    注意:格式化的内容中不允许出现汉字
'''
format_time_str = time.strftime('%Y/%m/%d %H:%M:%S %w %z', cur)
print(format_time_str) # 2021/03/31 09:45:46

format_time_str = time.strftime('%c', cur)
print(format_time_str) # Wed Mar 31 09:47:08 2021


# 7. 解时间的格式化 --- 把格式化的时间转化为时间元组
# time_tuple = time.strptime('字符串格式的时间', '字符串格式的时间的格式')
time_tuple = time.strptime('2020-12-31 13:24:56', '%Y-%m-%d %H:%M:%S')
print(time_tuple)
# time.struct_time(tm_year=2020, tm_mon=12, tm_mday=31, tm_hour=13, tm_min=24, tm_sec=56, tm_wday=3, tm_yday=366, tm_isdst=-1)

# 把这个时间转化为时间戳
time_code = time.mktime(time_tuple)
print(time_code)

# 9.时间休眠
time.sleep(2)

print('睡醒了')

'''
练习:
    获取2020年12月23日 三天后的时间
'''
str_time = '2020-12-23'
# 获取其对应的时间元组
time_tuple = time.strptime(str_time, '%Y-%m-%d')
print(time_tuple)
# time.struct_time(tm_year=2020, tm_mon=12, tm_mday=23, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=358, tm_isdst=-1)
# 转化为时间戳
time_code = time.mktime(time_tuple)
print(time_code)

# 在这个时间戳(秒数) + 三天对应的秒数
three_time_code = time_code + 24 * 60 * 60 * 3
# 再把时间戳转化为时间元组
time_tuple1 = time.localtime(three_time_code)
# 格式化
format_time_str = time.strftime('%Y-%m-%d',time_tuple1)
print(format_time_str) # 2020-12-26
datetime模块
'''
在datetime这个模块中包含四种类型
    datetime类 --- 描述年月日 时分秒的这种时间的
    time类 --- 描述时分秒的时间的
    date类 --- 来描述年月日的
    timedelta类 -- 来描述时间差的
'''
import datetime

# 获取当前时间
# datetime模块下 有datetime类 这个类下有now这个方法
now = datetime.datetime.now()
print(now, type(now)) # 2021-03-31 10:44:17.738320 <class 'datetime.datetime'>

# 自定义时间
# 最少赋值年月日
cus_time = datetime.datetime(year=2021, month=1, day=10)
print(cus_time) # 2021-01-10 00:00:00

# 计算时间差 -- 获取2020-12-23日三天后的时间
start_time = datetime.datetime(2020, 12, 23)
print(start_time) # 2020-12-23 00:00:00
after_three_days = start_time + datetime.timedelta(days=3)
print(after_three_days) # 2020-12-26 00:00:00

# 3个小时后的时间
after_three_hour = start_time + datetime.timedelta(hours=3)
print(after_three_hour) # 2020-12-23 03:00:00

# 3小时前的时间
before_three_hour = start_time - datetime.timedelta(hours=3)
print(before_three_hour) # 2020-12-22 21:00:00


# 格式化时间 --- 按照指定格式把时间格式化为字符串
# 时间.strftime(格式化格式)
format_str = before_three_hour.strftime('%Y/%m/%d')
print(format_str) # 2020/12/22

# 反格式化  把字符串格式的时间转化为datetime类型的
date_time = datetime.datetime.strptime(format_str, '%Y/%m/%d')
print(date_time) # 2020-12-22 00:00:00

# 计算两个时间的时间差
'''
2020-11-15 08:00:00
2021-01-14  14:00:00
'''
time1 = '2020-11-15 08:00:00'
time2 = '2021-01-16  14:00:00'
datetime1 = datetime.datetime.strptime(time1, '%Y-%m-%d %H:%M:%S')
datetime2 = datetime.datetime.strptime(time2, '%Y-%m-%d %H:%M:%S')
date_diff = (datetime2 - datetime1) if (datetime2 > datetime1) else (datetime1 - datetime2)
print(date_diff, type(date_diff)) # -61 days, 18:00:00 <class 'datetime.timedelta'>

# 获取差的数据
# 1. 获取相差的天数
days = abs(date_diff.days)
print(days)
# 2. 减去天数之后剩余的秒数
seconds = date_diff.seconds
print(seconds) # 64800
# print(64800 // 3600)

# 3. 包含天在内的时间差对应的秒数
total_seconds = abs(date_diff.total_seconds())
print(total_seconds)
print(total_seconds // 3600 // 24)
calendar模块
import calendar

year_calendar = calendar.calendar(2021)
print(year_calendar)

# 获取某一年 某个月份的日历
month_calendar = calendar.month(2021, 4)
print(month_calendar)

# 判断某一年是否是闰年
print(calendar.isleap(2020))

# 星期几
print(calendar.weekday(2021, 3, 30)) # 1 注意 星期是从星期一开始的 星期一是0

# 制定年 指定月中每个星期对应的日期
values = calendar.monthcalendar(2021, 1)
print(values)

for index, sublist in enumerate(values[:]):
    if index == 0:
        sublist.insert(0, 0)
        last_ele = sublist.pop()
        if sublist[-1] == 0:
            values.remove(sublist)
    else:
        sublist.insert(0, last_ele)
        last_ele = sublist.pop()
        if index == len(values) - 1:
            if last_ele != 0:
                new_sublist = [last_ele] + [0] * 6
                values.append(new_sublist)
print(values)


'''
0   0   0   0   0   0   0  
1 2   3   4   5   6   7   8


24 25 26 27 28 29 30 
31 0 0 0 
'''
os模块

获取指定目录下的所有文件

删除指定的目录

深度遍历以及广度遍历

深度遍历
	把一个分支解决完 再去解决另一个分支
	
	栈数据结构
		先进后出
		使用列表模拟栈
	
广度遍历
	把同一级别的解决  再去解决下一个同一级别
	队列数据结构
		队列先进先出

3.文件操作

读取内容
open()

注意程序和文件之间的断开操作
	如果没有断开  程序运行着 就表示这个程序占用着文件

第十四天

1.听写

1.递归遍历指定目录下的 后缀名为.py的所有文件

import os

def get_file(dir):
	# 获取这个文件夹下直接的子文件名
	filenames = os.listdir(dir)
	# 遍历
	for file_name in filenames:
		# 拼接
		join_path = os.path.join(dir, file_name)
		# 判断是不是文件夹
		if os.path.isdir(join_path):
			# 重复上面的步骤 再去遍历获取
			get_file(join_path)
		else:
			#if join_path.endswith('.py'):
			#if join_path[-3:] == '.py':
			if os.path.splitext(join_path)[-1] == '.py':
				print(join_path)

面试题

1.list0 = [1,2,5,7,9]
把列表的顺序打乱

import random
random.shuffle(list0)
print(list0)


2.dict0 = {'a':24, 'm':71, 'z':65, 'k':33}
按照value 值进行降序排序
sorted(dict0.items(), key=lambda item: item[-1], reverse=True)

3.两个列表 listA  和 listB  找出A和B中相同的元素  与 A和B中不同的元素
listA = [12, 17, 28]
listB = [18, 21, 17]

set(listA) & set(listB)
set(listA) ^  set(listB)

文件操作

open(文件的路径,操作文件的模式,encoding='文件的编码方式')
什么情况下不用设置文件的编码方式 --- 以字节的形式操作的时候 不用设置

读取内容

read() --- 表示全部读取出来
read(10)

readline() --- 读取一行
readlines() --- 按行读取全部 结果是一个列表  列表中的元素每一行的内容
readlines(hint=30) -- 安装读取 到这个30个字节、字符所在的行

向文件中写入内容
write(字符串/内容对应的字节数据)
writelines(列表)  列表中的元素就是要写入的内容

文件拷贝
	拷贝的是文件的内容
	源文件
	
	目的文件

面向对象编程

编程思想
接触过两种
面向过程 
	注重的怎么做
	根据需求 分成任务 把每个任务通过对应的代码完成对应的需求
	这种情况很容易造成代码重复
面向函数 
	注重的怎么做
	根据需求 分成对应的任务 把重复操作功能封装成函数
	按照逻辑要求顺序的调用对应的函数 最终实现需求
	万年历
面向对象
	注重的是 谁来做
	会把需求进行分析  分析出来对应的任务  按照不同对应的职责 领取对应的任务
	对象之间互相’配合‘ 最后完成需求
	
	现实生活为例:
		你要买电脑 -- 不懂电脑的情况下 会找一个懂电脑的人 帮助自己实现买电脑这件事
类和对象
类,就是类型 是一个抽象的名词 --- 是来对具有共同特征或者行为的事物进行抽象描述。
对象 --- 这一类事物中具体存在的实体

现实中举例
	人类 --- 类型
	 于波 --- 对象
	
	电脑 ---- 类型
	正在玩的电脑 -- 对象

程序中
	int --- 类
	10 --- 对象

在程序中得先有类 再有对象

类分为两种:
	系统类型
		int  float  bool  str  list  tuple  ....
	自定义类型
		根据生活实际需求 系统类型满足不了类型的描述 所以出现了自定义类型
自定义类型的格式
声明类的时候 需要包含特征(属性) 和 行为(方法)

class 类名():
	# 设置对象的属性值 -- 特征初始值的方法
	def __init__(self, 特征值对应的形参)
		# self  --- 表示的是要进行初始化的对象  【因为一个类有很多对象 给哪个对象进行初始化 使用self】
		# 设置对象的特征值  使用点语法 给对象添加属性
		self.特征名 = 特征值对应的形参名
	
	# 在类中定义方法 就是对象的行为
	def 行为名(self):
		pass

解读:
	class --- 声明类的关键字
	类名 --- 符合标识符规范的自定义名字  采用的大驼峰命名法 每个单词首字母大写
	__init__ --- 这个是这个类中给对象的特征进行初始化的方法
	self --- 【因为一个类有很多对象 给哪个对象进行初始化 使用self】
	def 行为名(self) --- 来定义对象的行为的
姓名  年龄  毕业院校 --- 属性信息
吃饭  跑步  打羽毛球  唱歌 ---- 行为
创建对象
类名(特征对应的具体值)
注意: self 不用手动传值   传值的时候只需要考虑那些特征的值即可
self这一块解释器会自行传值:会把对象的地址赋给self的
名词提炼对象
小明在跑步

对象:
	小明

根据语意提取对象的特征的 行为的信息

特征信息:
	名字
行为信息
	跑步

练习

小明 身高180cm  体重65kg
小红 身高165cm  体重45kg
小明经常跑步锻炼   小红经常逛街

class Person():
    def __init__(self,names, p_height, p_weight):
        self.name   = names
        self.height = p_height
        self.weight = p_weight

    def run(self):
        print(f'{self.name}身高{self.height}体重{self.weight},{self.name}经常跑步')
    def shopping(self):
        print(f'{self.name}身高{self.height}体重{self.weight},{self.name}经常逛街')

m = Person('小明','180','65')
m.run()

h = Person('小红','165','45')
h.shopping()

类和类的关系
is a   谁是谁
	学生类 是 人类 --- 体现的继承
has a  谁拥有谁
	体现是谁是谁的属性
		人类有姓名(字符串类型的数据)

小明穿着李宁牌白色的运动鞋在跑步

对象:
	小明 --- 人类
	鞋 --- 鞋类
类型
	人类
		特征:
			姓名
			鞋
		行为:
			跑步
	鞋类
		特征:
			品牌
			颜色
			种类

练习

小红牵着金毛旺财在散步

对象的属性时容器类型
学生类:
	特征:学号 姓名 年龄 成绩 
教室类:
	特征:教室名称  教室编号  最大容量  众多学生【可变的容器】
	行为: 添加学生  查询学生

__str____repr__

当打印对象时 默认呈现出来的是对象的地址, 但是想看到的是对象的属性信息,这种情况下 咱们可以在对象对应的类中写__str__这个方法 【print(对象)打印对象时 默认调用的方法】

__repr__
不是直接打印对象 而是透过容器看对象, 比如学生对象放在列表中  打印列表的时候 看学生的信息时  这个时候默认调用的__repr__。想看到的是对象的属性信 而不是对象的地址 需要在对应的类中将__repr__写一下

魔术方法
系统提供的  前后都有两个下划线
这种方法不用咱们手动调用  会恰当的时机触发 然后进行调用

__new__
__init__
	类名()

__str__
	print(对象)

第十五天

1.变量的分类和析构方法

全局变量 --- 作用于全局的 --- 程序什么时候终止 它什么时候释放
局部变量 --- 作用于其所在的函数 --- 存在栈中的  当函数执行完成 即被释放
成员变量 --- 就是对象的属性
		--- 跟随这对象的创建 给对象属性赋值的时候 在堆区产生  当对象被释放的时候 这个对象的属性也就被释放了
		--- 内存管理: 通过引用计数来管理内存 【看对象的地址被几个变量同时使用  引用计数就是几】
		--- 当对象的引用计数为0的时候 对象在内存中被释放

__new__ 新建对象的方法 【构造方法】
__init__ 初始化方法
__del__ 析构方法  【当这个对象被释放的时候调用】
变量的分类练习
class Person():
    def __init__(self, name, age):
        # 为self对应的对象 添加了一个name特征  并进行初始化
        self.name = name
        self.age = age

    # 析构方法
    def __del__(self):
        print(f'{self.name}被释放了')


p = Person('孟九', 18)

p1 = p

i = 0
while True:
    i += 1
    print(i)
    if i == 20:
        p = None

    elif i == 60:
        p1 = None

2.对象的属性是可以被动态增加的

对象.特征名 = 值 # 就可以给对象添加一个属性

class Person():
    def __init__(self, name, age):
        # 为self对应的对象 添加了一个name特征  并进行初始化
        self.name = name
        self.age = age


p = Person('沅沅', 18)

# 给对象增加属性
p.gender = '女'  # 这种添加只适合与当前对象

# __dict__ 这是对象调用的字段  可以以字典的形式显示对象的属性名及其对应的值
print(p.__dict__) # {'name': '沅沅', 'age': 18, 'gender': '女'}

p1 = Person('小雪', 18)
print(p1.__dict__) # {'name': '小雪', 'age': 18}

3.限制对象动态增加属性

生成类的时候 已经根据这一类的特征把属性都描述出来了, 对象自己不能在额外的增加属性了, 如何进行限制
在对象对应的类中 添加一个字段 __slots__ 他是一个元组类型的数据, 元组中的元素存放的是对象的特征名

注意: 当使用了__slots__ 之后  对象就不再有__dict__这个属性了
练习:
class Person():
    __slots__ = ('name', 'age')
    def __init__(self, name, age):
        # 为self对应的对象 添加了一个name特征  并进行初始化
        self.name = name
        self.age = age

p = Person('沅沅', 18)

# p.gender = '女'
# AttributeError: 'Person' object has no attribute 'gender'

# 注意点 也不能使用__dict__
# print(p.__dict__) # AttributeError: 'Person' object has no attribute '__dict__'

4.面向对象的三大特征:封装 继承 多态

封装
把不需要对外公开或者不能让外界随意修改的属性或者方法进行私有化,如果外界有需要取获取属性 可以提供对外的开放方式

人类Person  name  age

age -- 年龄
	不能被随便赋值  --- 私有化

在特征名、方法名前添加 两个下滑线 __ 就把对应的内容进行私有化了

提供获取的方法
	命名规范
		def get_特征名(self):
			return self.__特征名
提供修改值(赋值)的方法
	命名规范
		def set_特征名(self, 形参):
			满足逻辑条件的情况下 给
			self.__特征名 = 形参

写个人
	name(姓名) age(年龄)  gender(性别)  只能赋予男或者女  默认值男

私有化的属性只能在当前类中使用
练习:
class Person():
    __slots__ = ('name', '__age')
    def __init__(self, name, age):
        # 为self对应的对象 添加了一个name特征  并进行初始化
        self.name = name
        # 不能被随意赋值 私有化
        # self.__age = age
        # 初始化赋值也是赋值 赋值的时候就得添加逻辑判断
        self.set_age(age)

    # 提供获取方式
    def get_age(self):
        return self.__age

    # 提供赋值方法
    def set_age(self, age):
        if age > 0:
            self.__age = age
        else:
            self.__age = 1


p = Person('沅沅', -18)
# print(p.__age)

print(p.get_age())

# 新的一年 涨了一岁 修改值

#p.__age = 19 # 是因为给对象增加了一个叫__age的属性
# AttributeError: 'Person' object has no attribute '__age'

p.set_age(19)

print(p.get_age())
在Python中没有真正的私有化【了解】
self.__特征名 进行私有化的时候  解释器解释代码在计算机中存储的时候  把这个存储成了 _类名__特征名 这种形式的名字  
方法属性化
使用方法就像使用属性一样去取值  去使用等号赋值

get方法的属性化
	在get方法上添加装饰器 @property
set方法的属性化
	这个装饰器是在get方法的基础上衍生来的
		@get方法名.setter
继承
从两个或者两个以上的相关类中提取共同的属性和行为,存放到一个共通类中,通过一种格式 相关类可以从共通类中获取这些属性和方法,这个操作就是继承

学生类
	特征: 学号  姓名  年龄 成绩
	行为:吃饭 学习 睡觉
工人类
	特征:工号 姓名 年龄 工龄 工资
	行为:吃饭  工作  睡觉

人类  is a
	特征:姓名  年龄  
	行为:吃饭  睡觉

共通类 -- 父类 超类  基类
相关的类 - 子类

子类继承自父类  父类派生出子类

子类可以直接使用父类中可见的属性和方法

私有化的内容仅在当前类中可以使用, 即是是子类也不可以直接使用  只能通过对外访问的方式使用
方法的重写override
在继承中体现的,方法重写的场景:
父类中的功能无法满足子类,子类可以对这个方法进行重写
	1.重写部分 -- 有一部分和父类的一样 但是又有自己的扩展
	2.全部重写 --- 跟父类中的完全不一样
重写的时候注意:子类重写的父类方法的声明部分(def 函数名(形参):) 必须和父类一模一样

愤怒的小鸟
	鸟类
	红色鸟类
		攻击:死撞
	蓝色鸟类
		攻击: 分身 -- 死撞
	黑鸟
		攻击:爆炸


当子类重写了父类的方法 相对于子类对象来说 父类的方法就被它重写的给覆盖掉了, 子类对象再来调用的时候 只能调用的自己重写的
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值