Python

Python

基础语法

1.跨平台 面向对象 解释型编程语言

​ python是解释型语言,但为了提高运行速度,使用了一种编译的方法。编译之后得到pyc文件,存储了字节码(特定于Python的表现形式,不是机器码)。

​ 源代码 – 编译 --> 字节码 – 解释 --> 机器码

​ |————1次———|

1.    由源代码转变成机器码的过程分成两类:编译和解释。
2.    编译:在程序运行之前,通过编译器将源代码变成机器码,例如:C语言。
	-- 优点:运行速度快
	-- 缺点:开发效率低,不能跨平台。
3.    解释:在程序运行之时,通过解释器对程序逐行翻译,然后执行。例如Javascript
	-- 优点:开发效率高,可以跨平台;
	-- 缺点:运行速度慢。
  1. 模块单导入,行结尾不加分好

  2. 命名规范:组件小写,类骆驼,常量名大写,类的属性和方法小写

    1.项目名称
    首字母大写+大写式驼峰,
    ProjectName
    
    2.模块名和包名
    全部小写+下划线驼峰
    module_name  package_name
    
    3.类名称,异常
    首字母大写+大写式驼峰,
    class ClassName:   ,ExceptionName
    
    4.全局变量、常量
    全部使用大写字母+下划线驼峰
    GLOBAL_VAR_NAME,CONSTANT_NAME
    
    5.方法名,函数名,其余变量,参数,实例
    全部小写+下划线驼峰
    method_name,function_name,instance_var_name, function_parameter_name, local_var_name
    
    6.处理计数器外,不使用单字母命名
    
  3. 使用下划线“_”开头的模块变量和函数是受保护的,不能变量导入,表示不能直接访问的类属性

  4. 使用双下划綫“__”的变量和方法是类私有的,是类的私有成员

  5. 以双下划綫开头和结尾是Python的专用标识 __init__()标识构造函数

注释

​ #

​ ‘’‘……’‘’

​ ‘’‘‘’‘……’‘’’‘’

变量

变量命名

​ 慎用小写字母l和大写字母O

​ 允许多个变量指向同一个值(享元,节约内存,和C#中string 类似)

#在Python中,整数和短小的字符(不含空格),Python都会缓存这些对象,以便重复使用
True
a = 1
b = 1
print(a is b)

# True
a = "good"
b = "good"
print(a is b)

# False
a = "very good morning"
b = "very good morning"
print(a is b)

# False
a = []
b = []
print(a is b)

1、Python缓存了整数和短字符串,因此每个对象在内存中只存有一份,引用所指对象就是相同的,即使使用赋值语句,也只是创造新的引用,而不是对象本身;
  2、python对于字符串来说,如果不包含空格的字符串,则不会重新分配对象空间,对于包含空格的字符串则会重新分配

数字类型(整数,浮点数,复数)

​ 不可变性(和C# string 类似);当给一个数字类型修改变量时,先开辟一个内存空间,放置这个值,然后再讲这个数字变量指向这个内存地址

整数:位数无限制,数比较大时会在数字后自动加上l或L(2.x版本),十进制不能以0开头,0除外

​ 八进制数:以 0o开头 或 0O开头(3.x),在 2.x可以以 0 开头

​ 十六进制:0x 或 0X开头

字符串:

​ 不可变性

​ 用’’,"",’’’ ‘’’,""" “”"包含

​ 转义字符 \

取消\转义 r或者R,和C# @类似

布尔

​ 所有对象都可以进行真值测试

运算符

​ // 取整 7//2 为3

​ ** 幂 2**4 为16

逻辑运算符 用and or not ,位运算和C# 一样

条件表达式(没有括号,有冒号)
if a<b:
	...
else:
	...

while none:
	...

for a in range(1,10,2):  		# 和C# foreach类似,还可以遍历字符串,用来输出字符

	print(i,end='-')  #表示按一行输出1-3-5-7-9; #end='' 用来定义分隔符 Python 3.x;python 2.x 用 print(i, )表示

continue ,break 和c#用法一致

pass 是一个占位符,不做任何事情,可留做以后做修改

eg:

for i in range(1,10):
		if i%2==0:
			print(i,end=' ')
		else
			pass      #占位符,不做任何处理,方便以后对不是偶数的数进行处理
类似三元运算符
gender = 1 if input('请输入性别\n') == '男' else 0   # 类似三元运算符
迭代器

要实现迭代,则必须要有如下方法

__iter__()
list01 = [10,20,15,76,28]
# for item in list01:
#     print(item)

#原理:
#通过__iter__获取迭代器对象(10,20,15,76,28)
iterator = list01.__iter__()
while True:
    #如果迭代器中没有可以继续__next__的值
    #会抛出"停止迭代" 异常
    try:
        item = iterator.__next__()#StopIteration
        print(item)
    except StopIteration:
        break


for item in iterator:
    print(item)
#一个迭代器只能使用一次
for item in iterator:
    print(item)

自定义迭代器

from collections import Iterable, Iterator


class Person:
    def __init__(self, persion_list):
        self.persion_list = persion_list

    def __iter__(self):
        return Myiterator(self.persion_list)  # 调用我们重写的迭代器方法       


class Myiterator(Iterator):  # 继承Iterator 就不需要写__iter__,直接调用父类的.
    def __init__(self, persion_list):
        self.persion_list = persion_list
        self.index = 0  # 由于iterator 是没有index 的,这个要我们手动添加

    def __next__(self):  # 这个就是迭代器的取值逻辑
        while True:  # 当为false 的时候结束循环
            try:
                word = self.persion_list[self.index]  # 取值动作
            except IndexError:  # index 当变得超出persion_list 会报错的 ,先抓住这个异常
                raise StopIteration  # 迭代到没有值要用这异常,咱们把异常做个转化
            self.index = self.index + 1  # 递增我们的index
            return word  # 返回取到的值


body = Person(["Xiuwu", "Adny", "Maggie"])

a = iter(body)  # 调用我们自定义的迭代器方法
print(a)  # <__main__.Myiterator object at 0x00000000022399B0>
# 从打印结果看说明我们自定义的迭代器方法生效了,已经返回一个迭代器

print(next(a))  # Xiuwu
# 从打印结果我们判断出 __next__生效,如果想循环输出,自己试试for 循环.

for item in body:
    print(item)
class SkillManager:
    """
        技能管理器     可迭代对象
    """
    def __init__(self):
        self.__skills = []

    def add_skill(self,str_skill):
        self.__skills.append(str_skill)

    def __iter__(self):
        # return SkillIterator(self.__skills)

        # 执行过程:
        # 1. 调用__iter__()不执行
        # 2. 调用__next__()才执行当前代码
        # 3. 执行到yield语句暂时离开
        # 4. 再次调用__next__()继续执行
        # ....

        # yield作用:标记着下列代码会自动转换为迭代器代码.
        # 转换大致过程:
        # 1. 将yield关键字以前的代码,放到next方法中。
        # 2. 将yield关键字后面的数据,作为next返回值.

        # print("准备数据:")
        # yield "降龙十八掌"
        #
        # print("准备数据:")
        # yield "黑虎掏心"
        #
        # print("准备数据:")
        # yield "六脉神剑"

        for item in self.__skills:
            yield item


manager = SkillManager()
manager.add_skill("降龙十八掌")
manager.add_skill("黑虎掏心")
manager.add_skill("六脉神剑")


for item in manager:
    print(item)

iterator = manager.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break
迭代
    可迭代对象:__iter__()  可以for
    迭代器:__next__()  可以迭代(取元素)

class 迭代器:
    def __next__():
        pass

class 自定义类:
    def __iter__():
        return 迭代器()

for item in 自定义类():
    pass

生成器
    价值:惰性/延迟操作(省内存)
    生成器函数
        def 函数名():
            yield 数据

     yield:返回多个数据
     return:返回一个数据

    生成器表达式
        for item in (变量 for 变量 in 可迭代对象 if 条件):
            ...

class 生成器本质:
    def __iter__():
        return self

    def __next__():
        pass

序列

​ 连续内存空间,按一定顺序排列,每一元素分配一个索引

​ 含:列表,元组,集合,字典,字符串。集合和字典不支持索引,切片,相加和相乘

序列运算

**索引 **

可以为负数,表示 从右 至左,负数起始值为 -1 ,表示最后一个元素。从左至右,起始值为0**

**切片 **

​ 表示获取一定范围内的元素 sname[start : end : step]** #包含start,不包含end

strarr=["abc0","def1","dgd2","dsgs3","sdf4","dffas5","cgs6","ujy7","jhkf8"] 
a1=strarr[2]  
a2=strarr[-1] 
	 print(a1) #dgd2
	 print(a2)  #jhkf8
for s in strarr[1:7:2]: 
	print(s,end=' ') 	#输出def1 dsgs3 dffas5  
print('\n') 
for s in strarr[:8:3]: 
	print(s,end='-')  #输出abc0-dsgs3-cgs6- 
print('\n')        
asfs=strarr[:] #表示复制整个序列
 for s in asfs:
	 print(s,end=',')  #输出abc0,def1,dgd2,dsgs3,sdf4,dffas5,cgs6,ujy7,jhkf8, 

list01=[['A','B'],'哪吒','c']
list02 = list01[::-1] #表示按倒序赋值
print(list02)  # ['c','哪吒',['A','B']]
序列相加:

将俩个 相同类型 序列合并,不会去除重复项,相同类型是指同为列表,元组,字符串,而不是指元素类型相同

​ arr1=arr2+arr3

 strarr1=[1,2,3]
 print(strarr+strarr1)  
 #输出abc0,def1,dgd2,dsgs3,sdf4,dffas5,cgs6,ujy7,jhkf8,['abc0', 'def1', 'dgd2', 'dsgs3', 'sdf4', 'dffas5', 'cgs6', 'ujy7', 'jhkf8', 1, 2, 3] 
序列乘法:

示将其中的元素再依次重复出现多少次,可用于初始化序列长度

序列赋值

name,age = ['shibw',18]
print(name,age) #shibw 18
判断包含 in

​ print(“testin” in strarr1) #false

​ print(“testin” not in strarr1) #true

​ len(strarr1) 获取长度

​ max(strarr1) 最大值,元素要同类型

​ min(strarr1)最小值

​ sum(整数序列)求和

​ str(),list() 序列类型转换

​ sorted(strarr1),reversed(strarr1):正序和倒序

​ enumerate() 将序列组合为一个索引序列,多用在for循环中

​ arr=[“sdf”,“ewr”,“Rty”]

​ for index,item in enumerate(strarr1):

​ print(index,item) # eg: 0 sdf ……

列表[]

添加,修改,删除列表元素

​ strarr1.apend(“abc”) strarr1.insert(1,“abc”) strarr1.extend(arr) strarr1.pop()

​ 添加

​ apend表示在末尾添加,

​ insert 在指定索引处添加,效率没apend高,一般不推荐使用。

​ extend 和序列+运算一样,将一个列表全部添加进去,.pop表示弹出最后一个元素。

​ 修改

​ 直接用=重新赋值

​ 删除

​ del strarr1[1] 删除指定索引的元素

​ del strarr1删除整个列表,一般不用,自带垃圾回收

​ strarr1.remove(“abc”),删除值为abc的元素,如果不存在会报错,通常用strarr1.count(“abc”)>0判断是否存在

del使用场景:使用del删除指定位置元素,变量,而无法删除数据

remove使用场景:使用remove()删除指定值,如果不确定或不关心元素在列表中的位置,可以使用remove()根据指定的值来删除元素。

pop使用场景:使用pop()获取并删除指定位置元素。使用pop()同样可以获取列表中指定位置的元素,但在获取完成之后,该元素会自动被删除。如果为pop(off)指定了偏移量,它会返回偏移量对应位置的元素。如果不指定,则默认使用-1(即默认删除末位元素)。因此pop(0)将返回头元素,而pop()或pop(-1)则会返回列表的尾元素

clear() 清空所有数据 ,返回None

列表其它计算

​ strarr1.count(“abc”)>0 #返回true 表示abc在strarr1中

​ strarr1.index(“abc”) #返回首次出现的索引

​ sum(listname[,start]) #计算数值列表的和,start表示统计结果从哪个数开始,默认为0 ,相当于是listname的和加上start的值

​ sort(key=none,reverse=false) key提取的比较键,reverse表示是否倒序.中文排序不支持

arr=[1,3,4,2,45]	
s1=sum(arr)
s2=sum(arr,2)
print(s1,s2)  # 55 57

char=['cat','Tome','Angela','pet']
char.pop() #弹出最后一个元素
schar=char.sort()   #sort 无返回,列表顺序变化
print(schar,char)   #None ['Angela', 'Tome', 'cat', 'pet']
char.sort(key=str.lower,reverse=True)
print(char)		#['Tome', 'pet', 'cat', 'Angela']
print(sorted(char,key=str.lower,reverse=False)) 
#sorted有返回一个排序后的副本,不会改变原列表 ['Angela', 'cat', 'pet', 'Tome']
print(char)		#['Tome', 'pet', 'cat', 'Angela']

list01 = [0,1,2]
list01[1:2] = ['A','B']#[0,'A','B',2]
列表推导式

newlist=[expresion for var in list]

any = [random.randint(10, 100) for i in range(10)]
print(any)
newchar=[x+"test" for x in char]
print(newchar)
newfilter=[x for x in char if len(x)>3]
print(newfilter)

元组(,)

​ 有序,不可变

​ 和列表相比,元组是不可变序列,元素不可以单独修改;列表是可变序列,元素可随意修改;

​ 元组用()定义,也可以省略,每个元素用,隔开;列表用[]定义,不可省略。若元组只有一个元素,则这个元素要跟一个“,”,不然会被解析成字符串

import random
char = ['cat', 'Tome', 'Angela', 'pet']
char.pop() #弹出最后一个元素
print(char)
schar = char.sort()  # sort 无返回
print(schar, char)  # None ['Angela', 'Tome', 'cat', 'pet']
char.sort(key=str.lower, reverse=True)
print(char)
any = (random.randint(10, 100) for i in range(10))
print(any)
newchar=(x+"test" for x in char)
print(newchar)
newfilter=(x for x in char if len(x)>3)
print(newfilter)

元组比列表的访问和处理速度快

列表不能作为字典的键,而元组可以

字典{key:name,key1:name1}

​ 可变,键值对,键不可变,任意类型,任意嵌套,无序

dictionary = {'name': 'kcs', 'age': 30, 'sex': '男', "address": "深圳"}  # 创建字典
print(dictionary['name'])	#kcs
dicEmpty = {}  # 空字典创建
dicEmpty1 = dict()
print(dicEmpty, dicEmpty1) 	#{} {}

listname = ['A', 'B', 'C']
listshow = ('s', 'd', 'e')
zipt = zip(listname, listshow)  
# zip 将俩个列表或元组,组合成元组,并返回包含这些对象的zip对象,可用tuple转化为元组
print(zipt)		# <zip object at 0x000000000253E800>
print(zip(listname, listshow))		# <zip object at 0x00000000024F2900> !主要这俩个对象不一样需回头了解原因
print(tuple(zipt))	(('A', 's'), ('B', 'd'), ('C', 'e'))
dic = dict(zipt)  # dict和zip配合生成字典,
print(dic)		# {}	!需回头了解原因
print(dict(zipt))	#	{}	
print(dict(zip(listname, listshow)))	# {'A': 's', 'B': 'd', 'C': 'e'}
print(dic)	

#通过函数创建字典
dict02 = dict([['name','shibw'],['age',30]])    # 列表 元组中的只能由一对
print(dict02)## {'name': 'shibw', 'age': 30}
dict02 = dict([['name','shibw'],('age',20)])
print(dict02)#{'name': 'shibw', 'age': 20}

dictdemo = dict(a='1', b=2)  # 键不用引号
print(dictdemo) #	{'a': '1', 'b': 2}

lst = ['tp', 'sd']
dicnone = dict.fromkeys(lst)  # dict.fromkeys创建值为none的字典
print(dicnone)	#{'tp': None, 'sd': None}

tstuple = ('asf', 'asf', 'test')
listDemo = ["sf", "rte", "te"]
dicTtt = {tstuple: listDemo}
print(dicTtt)	#	{('asf', 'asf', 'test'): ['sf', 'rte', 'te']}
print(dicTtt[tstuple]) 	#	['sf', 'rte', 'te']

dictionaryDemo = {'name': 'kcs', 'age': 30, 'sex': '男', "address": "深圳"}
if 'name' in dictionaryDemo:	# 键是否存在于字典
    print(dictionaryDemo.get('name'))  # Python推荐用get	kcs
    print(dictionaryDemo['name'])	#	kcs
a = dictionaryDemo.pop('age')  # 删除指定键,并返回值

#同get 但是键不存在时 会添加键值对
print(dictionaryDemo.setdefault('address','beijing'))

print(a)	# 30
dictionaryDemo.popitem()  # 删除最后一项
del dictdemo
dicTtt.clear()
print(dicTtt)	#	{}
dictFor = {'name': 'kcs', 'age': 30, 'sex': '男', "address": "深圳"}


for item in dictFor:
    print(item,end=" ")  # 输出键值 name age sex address
for item in dictFor.items():
    print(item,end='')  
	# 输出键值对('name', 'kcs') ('age', 30) ('sex', '男') ('address', '深圳')
for index, value in dictFor.items():
    print(index, value,end=' ')  # 输出键和value name kcs age 30	sex 男 address 深圳

dictFor["tel"]=1856566  #添加
dictFor["address"]="szlg"   #修改
del dictFor['age']  #删除,不存在时报错
print(dictFor)	# {'name': 'kcs', 'sex': '男', 'address': 'szlg', 'tel': 1856566}

dict01 = {'name':'shibw','age':20}
dict02 = {'name':'laowang','address':'北京'}
#使用02更新字典01 如果02中的键在01中不存在 添加
#如果02的键在01中存在 使用02的值
dict01.update(dict02)
print(dict01)   #{'name': 'laowang', 'age': 20, 'address': '北京'}


dict01 = {1:"1.0",2:"2.0"}
print(dict01)
dict01 = {(1,2,3):3,(1,2,3,4):4}
print(dict01)
#可变类型无法通过哈希算法运算
#所以字典的键都是不可变类型
dict01 = {[1,2,3]:3}#TypeError
print(dict01)
字典推导式
dicRandom={i:random.randint(10,100) for i in range(1,5)}

print(dicRandom)	#	{1: 82, 2: 40, 3: 46, 4: 10}

name=['a','b','c']

age=[12,23,34]

dicZip={i:str(j)+"岁" for i,j in zip(name,age)}

print(dicZip)	#	{'a': '12岁', 'b': '23岁', 'c': '34岁'}
dicIf = {i: j for i, j in dicZip.items() if j == '23岁'}
print(dicIf)	#	{'b': '23岁'}

集合{a,b,c}

​ 不重复 可变集合&不可变集合

setDemo = {1, 2, 3, 5, 1, 5, 23}
print(setDemo)  # {1, 2, 3, 5, 23}

setDemo1 = set("集合测试")
print(setDemo1) #{'测', '试', '集', '合'}
print(set())  # 不能用{}表示空集合,{}表示空字典  #set()
tupleDemo=('asdf', 'fd', 'ert')
set1=set(tupleDemo)
print(set1)  #{'ert', 'fd', 'asdf'}
set1.add("add")
print(set1) #{'ert', 'add', 'fd', 'asdf'}
set1.remove('asdf')
print(set1)     #{'ert', 'add', 'fd'}
set1.pop()
print(set1) #{'add', 'fd'}
set1.clear()
print(set1) #set()

set1={'ert', 'add', 'fd', 'asdf'}
set2={'add','muti'}
print(set1&set2)    #{'add'}
print(set1-set2)    #{'ert', 'fd', 'asdf'}
print(set1|set2)    #{'add', 'muti', 'ert', 'fd', 'asdf'}
print(set1^set2)    #{'muti', 'ert', 'fd', 'asdf'}

s1 = {1,2,3}
s2 = {1,2}
#子集
#< 判断一个集合所有元素是否完全在另一个集合中
#如果s1中包含了s2的全部元素 我们就把s2称为s1的子集
print(s2<s1)#True
#超集(super)
#> 判断一个集合是否包含另一个集合的所有元素
#如果s1中包含了s2的全部元素 我们就把s1称为s2的超集
print(s1>s2)#True

类型总结

#任意数据类型 可变序列
#元组  tuple()
#任意数据类型 不可变序列

#序列的通用操作
# + 拼接两个序列
# * 生成重复的序列
# += *=
# 索引 / 切片

#字典  dict()
#键必须是不可变类型 值可以为任意对象
#可变散列对象
#集合 set()
#只能包含不可变类型 可变散列对象
#固定集合  frozenset() 不可变散列对象

# None
# int float bool complex str list tuple dict set
#可变 list dict set
#不可变 数字 str tuple

浅拷贝 /深拷贝

浅拷贝

list01 = ['三丰','翠山','无忌']
#把list01中储存的地址赋值给list02
list02 = list01
list01[0] = '张三丰'
print(list02[0])#张三丰

list01 = [800, 900, 1000]
list02 = list01
list03 = list01
list01[0] = '八百'
print(list02[0])  # '八百'
list03[1] = '九百'
print(list02)  # ['八百', '九百', 1000]
print(id(list03))
list03 = '九九百'	# 这里直接改变了类型和引用
print(id(list03))
print(list03)
print(list02)  # ['八百', '九百', 1000]

#
#
list01 = [800, 900, 1000]
list02 = list01[:]  # list01[:] 第一层引用是深拷贝
list01[0] = '八百'
print(list02)  # [800, 900, 1000]


a = [1,2,3, [3,4,5]]
b=a[:]
a.append('a')
b.append('b')
print(a)    # [1, 2, 3, [3, 4, 5], 'a']
print(b)    # [1, 2, 3, [3, 4, 5], 'b']
a[3].append('aa')   
b[3].append('bb')   
print(a)    # [1, 2, 3, [3, 4, 5, 'aa', 'bb'], 'a']
print(b)    # [1, 2, 3, [3, 4, 5, 'aa', 'bb'], 'b']

深拷贝

import copy

list01 = [100, [200, 300]]
# 深拷贝 划清界限 拷贝前的对象和拷贝后的对象互不影响
# 注意 深拷贝可能会占用大量内存
list02 = copy.deepcopy(list01)
list01[1][0] = 500
print(list01)  # [100, [500, 300]]
print(list02)  # [100, [200, 300]]

内置高阶函数 filter map max sorted(lambda,类似委托,linq)

import ListHelper

class Enemy:
    def __init__(self, name, hp,atk=None, defense=None):
        self.name = name
        self.hp = hp
        self.atk = atk
        self.defense = defense

enemy_list = [
    Enemy('玄冥二老',86,80,120),
    Enemy('成昆',0,0,150),
    Enemy('谢逊',120,50,150),
    Enemy('灭霸',0,0,999)
]
# 1. 在敌人列表中查找所有死人
for item in filter(lambda item:item.hp == 0,enemy_list):
    print(item.name)
for item in ListHelper.find_all(enemy_list,lambda item:item.hp == 0):
    print(item.name)
# 2.在敌人列表中查找所有敌人的名称
for item in map(lambda item:item.name,enemy_list):
    print(item)
for item in ListHelper.select(enemy_list,lambda item:item.name):
    print(item)

# 3. 获取攻击力最大的敌人
re = max(enemy_list,key = lambda item:item.atk )
print(re.name)
re1=ListHelper.get_max(enemy_list,lambda item:item.atk )
print(re1.name)

# 4. 对敌人列表根据攻击力升序排列
# sorted 返回排好序的数据
for item in sorted(enemy_list,key = lambda item:item.atk):
    print(item.atk)

# 对敌人列表根据攻击力降序排列
# sorted 返回排好序的数据
for item in sorted(enemy_list,key = lambda item:item.atk,reverse=True):
    print(item.atk)

for item in ListHelper.order_by(enemy_list,lambda item:item.atk):
    print(item.atk)

ListHelper 如下,自定义扩展和上述高阶函数做对比

"""
    定义项目中所有对容器的操作。
"""


class ListHelper:
    """
        列表助手类
    """
    @staticmethod
    def find_all(iterable_target,func_condition):
        """
            在可迭代对象中,查找满足条件的所有元素。
        :param iterable_target:可迭代对象
        :param func_condition:所有条件
        :return:生成器对象
        """
        for item in iterable_target:
            if func_condition(item):
                yield item

    @staticmethod
    def find_single(iterable_target,func_condition):
        """
            在可迭代对象中,查找满足条件的单个元素。
        :param iterable_target:可迭代对象
        :param func_condition:所有条件
        :return:元素
        """
        for item in iterable_target:
            if func_condition(item):
                return item

    @staticmethod
    def sum(iterable_target,func_condition):
        """
            在可迭代对象中,根据条件求和。
        :param iterable_target:可迭代对象
        :param func_condition:求和条件
        :return:求和的数值
        """
        sum_value = 0
        for item in iterable_target:
            sum_value += func_condition(item)
        return sum_value

    @staticmethod
    def select(iterable_target,func_condition):
        """
             在可迭代对象中,根据条件选择属性。
            :param iterable_target:可迭代对象
            :param func_condition:筛选条件
            :return:生成器对象
         """
        for item in iterable_target:
            yield func_condition(item)

    @staticmethod
    def get_max(iterable_target,func_condition):
        """
             在可迭代对象中,根据条件获取最大元素。
            :param iterable_target:可迭代对象
            :param func_condition:获取条件
            :return:最大元素
        """
        max_value = iterable_target[0]
        for i in range(1,len(iterable_target)):
            # if max_value.atk < iterable_target[i].atk:
            if func_condition(max_value) < func_condition(iterable_target[i]):
                max_value = iterable_target[i]
        return max_value

    @staticmethod
    def order_by(iterable_target,func_condition):
        """
            对可迭代对象, 根据任意条件进行升序排列
        :param iterable_target: 可迭代对象
        :param func_condition: 排序条件
        """
        for r in range(len(iterable_target)-1):
            for c in range(r+1,len(iterable_target)):
                # if iterable_target[r].atk > iterable_target[c].atk:
                if func_condition(iterable_target[r]) > func_condition(iterable_target[c]):
                    iterable_target[r],iterable_target[c] =  iterable_target[c],iterable_target[r]

内存管理

可变类型,不可变类型

可变类型的地址不一样,但是其中的元素内存地址又是一致的

可变数据类型的意思就是说对一个变量进行操作时,其值是可变的,值的变化并不会引起新建对象,即地址是不会变的,只是地址中的内容变化了或者地址得到了扩充。

对可变数据类型的操作不能是直接进行新的赋值操作,比如说a = [1, 2, 3, 4, 5, 6, 7],这样的操作就不是改变值了,而是新建了一个新的对象


list01=[['A','B'],'哪吒','c']

list02 = list01[::-1]
print(list02)  # ['c','哪吒',['A','B']]
print(list01 is list02)  # False
print(id(list01))  # 41801472
print(id(list02))  # 41622848
#
list02.insert(0,5)
print(list02)   # [5, 'c', '哪吒', ['A', 'B']]
print(id(list01[0]))  # 41931904
print(id(list02[-1]))  # 41931904
print(id(list01[1]))  # 39551600
print(id(list02[-2]))  # 39551600
print(list01[0] is list02[-1])  # True
# # 可变类型的地址不一样,但是其中的元素内存地址又是一致的
# # 可变数据类型的意思就是说对一个变量进行操作时,其值是可变的,值的变化并不会引起新建对象,即地址是不会变的,只是地址中的内容变化了或者地址得到了扩充。
# # 对可变数据类型的操作不能是直接进行新的赋值操作,比如说a = [1, 2, 3, 4, 5, 6, 7],这样的操作就不是改变值了,而是新建了一个新的对象
说明

**Python中的变量都是指针,这确实和之前学过的强类型语言是有不同的。**因为变量是指针,所以所有的变量无类型限制,可以指向任意对象。

指针的内存空间大小是与类型无关的,其内存空间只是保存了所指向数据的内存地址。

Python 的所有**变量其实都是指向内存中的对象的一个指针,所有的变量都是!此外,对象还分两类:一类是可修改的,一类是不可修改的。我的理解是把不可修改(mutable)的类型叫做值类型,值传递,可修改(immutable)类型叫,地址不变,按引用传递,比做引用类型。**

对象=确定内存空间+存储在这块内存空间中的值。

在Python中,数值(整型,浮点型),布尔型,字符串,元组属于值类型,本身(内存地址)不允许被修改(不可变类型),数值的修改实际上是让变量指向了一个新的对象(新创建的对象),所以不会发生共享内存问题。 这种方式同Java的不可变对象(String)实现方式相同 。

  1. Python在底层做了一定的优化,对于使用过小整数以及短字符串都会被缓存起来。Python中会为匿名列表对象匿名字典对象以及短字符串创建缓存区

  2. 之所以采用这种优化的方式,是因为python中数字和字符串一经创建都是不可修改的。所以不会出现,因使用了缓存的对象值造成“脏读”的问题

fd = 3.12
print(type(fd))
fd1 = 3.12
print(id(fd), id(fd1))  # 41491216 41491216
tuple1 = ('sdf', 23, 43)
tuple2 = ('sdf', 23, 43)
print(id(tuple1), id(tuple2))  # 40848768 40848768
# 不可变类型的享元,如上所示,相同值是共享同一内存地址的.
# 不可变类型的值是不可变的,是指其内存地址不可变,但如果改变不可变对象其中子对象的值,其子对象元素的地址没有变化,则是合法的,如下
tuple3= ('adf', 234, 54, ['asf', 34])
#tuple3[0]='34'  # 改变了地址: 'tuple' object does not support item assignment
tuple3[3].append('test')
print(tuple3)   #('adf', 234, 54, ['asf', 34, 'test'])

list01 = ['a', 'b', 'c']
list01[0] = ['A', 'B']
print(list01)  # [['A','B'],'b','c']
# 将右边列表的值赋值给list01的第一个位置
print(list01[1:3])
list01[1:2] = ['哪吒']
# 序列赋值
# name,age = ['shibw',18]
# print(name,age)
print(list01)  # [['A','B'],'哪吒','c']

list02 = list01[::-1]
print(list02)  # ['c','哪吒',['A','B']]
print(list01 is list02)  # False
print(id(list01))  # 41801472
print(id(list02))  # 41622848

list02.insert(0,5)
print(list02)   # [5, 'c', '哪吒', ['A', 'B']]
print(id(list01[0]))  # 41931904
print(id(list02[-1]))  # 41931904
print(id(list01[1]))  # 39551600
print(id(list02[-2]))  # 39551600
print(list01[0] is list02[-1])  # True
# 可变类型的地址不一样,但是其中的元素内存地址又是一致的
# 可变数据类型的意思就是说对一个变量进行操作时,其值是可变的,值的变化并不会引起新建对象,即地址是不会变的,只是地址中的内容变化了或者地址得到了扩充。
# 对可变数据类型的操作不能是直接进行新的赋值操作,比如说a = [1, 2, 3, 4, 5, 6, 7],这样的操作就不是改变值了,而是新建了一个新的对象
list3=[True,2,['df','ty',45],'tr']
list4=['tr',['df','ty',45],2,True]
print(id(list3[0]),id(list4[-1]))   # 8790904592208 8790904592208   # 序列中元素每一个元素指向一个地址,不可变对象值相同,指向的地址相同,可变的对象,代表不同的地址,不共享内存
print(id(list3[2]),id(list4[-3]))   # 41873856 41867328             

list3[2]=list4[-3]
print(id(list3[0]),id(list4[-1]))   # 8790904592208 8790904592208  
print(id(list3[2]),id(list4[-3]))   # 41867328 41867328              #   可变对象赋值后聚有类似引用特性的性质

list3[2][0]=123
print(list4)    # ['tr', [123, 'ty', 45], 2, '1']

tuple4=(True,2,['df','ty',45],'tr')
tuple5=(True,2,['df','ty',45],'tr')
print(tuple4==tuple5)   #true
print(id(tuple4),id(tuple5)) #39015824 38971568		因为含有不可变对象,所以指针不同

tuple6=(True,2,('df','ty',45),'tr')
tuple7=(True,2,('df','ty',45),'tr')
print(tuple6==tuple7)   #true
print(id(tuple6),id(tuple7)) #40720960 40720960		全是不可变对象,所以指针相同

变量是指针,变量赋值,实际是指针变更 。如上验证,相同值(不含可变类型)的不可变类型,在内存中只会存在一份,不会重复保存 。有这么一种机制,但是在测试的时候,也有可能出现数值大于256,id不一样的情况.

这里并没有出现长度限制,有说法是pycharm做了优化,但是有通过IDEL 执行py文件生成相同的结果,能肯定的是,python对不可变类型存在优化策略。需深入了解。。。

fd = 3.12
print(type(fd))
fd1 = 3.12
print(id(fd), id(fd1))  # 41491216 41491216
tuple1 = ('sdf', 23, 43)
tuple2 = ('sdf', 23, 43)
print(id(tuple1), id(tuple2))  # 40848768 40848768
# 不可变类型的享元,如上所示,相同值是共享同一内存地址的.
# 不可变类型的值是不可变的,是指其内存地址不可变,但如果改变不可变对象其中子对象的值,其子对象元素的地址没有变化,则是合法的,如下
tuple3= ('adf', 234, 54, ['asf', 34])
#tuple3[0]='34'  # 改变了地址: 'tuple' object does not support item assignment
tuple3[3].append('test')
print(tuple3)   #('adf', 234, 54, ['asf', 34, 'test'])
# 在Python中会为匿名列表对象和匿名字典对象以及短字符串创建缓存区
# 列表和字典这种可变对象当为匿名对象是会向外暴露一个内存地址,不论里面的内容怎么变,该地址不变,所以下面的地址都一样
# '''
# print(id([1, 2, 3]) == id([4, 5, 6])) # True
# print(id([1]) == id([1, 2, 3, 4, 5, 6]))  # True
# print(id({1: 1, 2: 2}) == id({3: 3, 4: 4}))  # True
# '''
# 但是如果存在对象的引用,即非匿名对象,上面的结果都是False,如下
# '''
# a = [1, 2, 3]
# b = [4, 5, 6]
# c = {1: 1, 2:5}
# d = {3: 3, 4: 4}
# print(id(a) == id(b) ) # Fasle
# print(id(c) == id(d) ) # Fasle
数据比较

id 比较的是对象的内存地址是否相等

== 比较的是对象的值是否相等

is 比较的是对象的内存地址和值是否相等

字符串

在Python中 常用的俩种字符串类型 str 和 bytes,通过encode()和decode()进行转换,转换时的默认编码格式为UTF-8。Python中str在内存中已Unicode表示

编码
# str.encode([encoding="UTF-8"][,errors="strict"])
# encoding 可省,编码方式
# errors 可省,异常处理方式  strict 非法字符抛异常  ignore 忽略非法字符  replace 用“?”替代非法字符 xmlcharrefreplace 使用xml字符引用
ver = "野渡无人舟自横"
verByte = ver.encode(encoding='UTF-8', errors="strict")
print(verByte)  # b  '\xe9\x87\x8e\xe6\xb8\xa1\xe6\x97\xa0\xe4\xba\xba\xe8\x88\x9f\xe8\x87\xaa\xe6\xa8\xaa'
verBack = verByte.decode(encoding="UTF-8", errors="strict")
print(verBack)
verGB = ver.encode("GBK")
verGBBack = verGB.decode("GBK")
print(verGB)  # b  '\xd2\xb0\xb6\xc9\xce\xde\xc8\xcb\xd6\xdb\xd7\xd4\xba\xe1'
print(verGBBack)
拼接,截取等
# 拼接 +
print("sfsf"+"---"+"sfas")	#sfsf---sfas
# str.encode([encoding="UTF-8"][,errors="strict"])
# encoding 可省
# errors 异常处理方式  strict 非法字符抛异常  ignore 忽略非法字符  replace 用“?”替代非法字符 xmlcharrefreplace 使用xml字符引用
ver = "野渡无人舟自横"
verByte = ver.encode(encoding='UTF-8', errors="strict")
verByte1 = ver.encode()
print(verByte, verByte1)  # b  '\xe9\x87\x8e\xe6\xb8\xa1\xe6\x97\xa0\xe4\xba\xba\xe8\x88\x9f\xe8\x87\xaa\xe6\xa8\xaa'
verBack = verByte.decode(encoding="UTF-8", errors="strict")
print(verBack)
verGB = ver.encode("GBK")
verGBBack = verGB.decode("GBK")
print(verGB)  # b  '\xd2\xb0\xb6\xc9\xce\xde\xc8\xcb\xd6\xdb\xd7\xd4\xba\xe1'
print(verGBBack)

print("sfsf" + "---" + "sfas")
str = "野渡无人舟自横。test"
print(len(str))  # 12
print(len(str.encode()))  # 28 UTF-8中文3个字节
print(len(str.encode("gbk")))  # 20 GBK中文俩个字节

# 截取 string[start:end:step] 截取字符串,start:end:step 都可省 ,string表示要处理的字符串
# 分割 str.split(sep,maxsplit) sep表示分隔符,可省,默认为None(包含空格,换行'\n' 制表符 ‘\t’ 等 );maxsplit表示分割的次数,分割的后的集合元素个数为maxsplit+1,-1或省略,则全部分割
print("渡无_人_舟自_横".split('_', 2))  # ['渡无', '人', '舟自_横']
# 合并 strnew= stringchar.join(iterable) stringchar表示用来合并连接iterable元素的字符,iterable表示可迭代对象,如列表,元组
lst = ["test", "测试", "kcs"]
print("".join(lst))  # test测试kcs
print("@" + "@".join(lst))  # @test@测试@kcs
# 计数 substr在str中出现的个数,start和end描述检索范围,可省略
str.count(substr[start[,end]])
# 首次 substr在str中首次出现的索引,不存在为-1。rfind表示从右边开始查找
str.find(substr[start[,end]])
# 首次索引  substr在str中首次出现的索引, 不存在时抛异常。rindex表示从右边开始查找
str.index(substr[start[,end]])
# 开始 str检索范围是否以str开头,start和end描述检索范围,可省略
str.startswith(substr[start[,end]])
# 结尾  str检索范围是否以str开头,start和end描述检索范围,可省略
str.endswith(substr[start[,end]])
#  小大写转换
str.lower()  str.upper()  str1.swapcase() #小写转大写 大写转小写
# 去除特殊字符 str.strip([chars]) 表示去除字符串str左右俩边的字符  lstrip表示去掉左边的,rstrip表示去掉右边的
#判断字符串中是不是全都为空白
print(str1.isspace())
#判断字符串中是不是全都为数字类型
num_str = '123456'
print(num_str.isdigit())
#修改
#替换 将旧的字符串替换成新的字符串
str1 = 'this is a test string'
print(str1.replace('is','are'))
#替换 最多换1次
print(str1.replace('is','are',1))
#如果指定的旧的字符串不存在 就什么都不做
print(str1.replace('there','that'))

str = " @ssfa . "
print(str.strip('@.'))  # " @ssfa . "
print(str.strip('@. '))  # "ssfa"   去掉左右俩边的“@"和”.“和空字符
print(str.strip())  # "@ssfa ."   默认去掉左右俩边的空字符和 制表符\t 换行\n 回车符\r等特殊字符等


字符串格式化
# 格式化

# 格式化  方式1:  ’%[-][+][0][m][.n]格式化字符‘%exp   说明:  -|+|0 可选参数 分别表示左、右、右对齐,并为无符号数添加符号 m表示占有的宽度 n表示小数点位  exp 要转换的项,多个用元组表示,不能用列表

# 常用 格式化字符 :   %s 字符串str   %c 单个字符    %d %i 十进制整数  %f %F 浮点数  %r字符串repr %% 字符%   %x 十六进制  %o 八进制  %e %E指数

strMoban = "姓名:%s 年龄:%03d  身高:%02.2f 米 "
pinfo = ('kcs', 30, 1.65)
strAll = strMoban % pinfo
print(strAll)  # 姓名:kcs 年龄:030  身高:1.65 米

# 方式2 使用format 推荐方式   str.format(args)  str:模板  args 要转换并替换占位的字符,多个用,隔开 模板定义  {[index][:[[fill]align][sign][#][

# width][.precision][type]]} index 表示占位符在参数列表的起始位置,默认0 ,  fill表示空白处填充字符 align 对齐方式用< > = ^分别表示左 右 右 居中对齐

# sign 用于给无符号数添加符号 用 + - 空格 表示  # 表示是否给数据加上进制标识 width占用宽度 precision 小数位 type 指定类型   S:字符串 D:十进制数  C:将十进制自动转换为Unicode字符

# b:将十进制转换为2进制 o:十转八  x X:十转十六  f F 浮点数   %显示百分比   e E 转为科学计数  g G:自动在e f ,E F中切换

strMb = "姓名:{:-<9s} 年龄:{:0<+#3d} 身高:{:0< 3.2f}米 鞋码:{:0<o} newage:{:0>b}"
strRet = strMb.format(" k c s", 30, 1.65, 39, 30)
print(strRet, "test")   #   姓名: k c s--- 年龄:+30 身高: 1.65米 鞋码:47 newage:11110 test

strMb = "姓名:{0:-<9s} 年龄:{2:0<+#3d} 身高:{1:0< 3.2f}米 鞋码:{3:0<o} newage:{4:0>b}"
strRet = strMb.format(" k c s",1.65, 30,  39, 30)
print(strRet, "test")   #   姓名: k c s--- 年龄:+30 身高: 1.65米 鞋码:47 newage:11110 test
时间函数
import time

#获取当前时间戳  从1970年1月1日到现在的总秒数
print(time.time())          #1592551864.3892887
#获取当前的时间元组
#(年 月 日 时 分 秒 一周的第几天(0 1 2...) 一年的第几天 夏令时)
print(time.localtime()) #time.struct_time(tm_year=2020, tm_mon=6, tm_mday=19, tm_hour=15, tm_min=31, tm_sec=4, tm_wday=4, tm_yday=171, tm_isdst=0)
#获取指定时间戳的时间元组
print(time.localtime(12345678)) #time.struct_time(tm_year=1970, tm_mon=5, tm_mday=24, tm_hour=5, tm_min=21, tm_sec=18, tm_wday=6, tm_yday=144, tm_isdst=0)
time_tuple = time.localtime()
#将时间元组变成时间戳
print(time.mktime(time_tuple))  #1592551864.0

print(time.struct_time.tm_year) #<member 'tm_year' of 'time.struct_time' objects> 取不到其值
for item in time_tuple:
    print(item,end=';') # 2020;7;8;14;21;35;2;190;0;
print('\n')
#将时间元组转换成时间字符串
print(time.strftime('%y/%m/%d %H:%M:%S',time_tuple))    #20/06/19 15:31:04
print(time.strftime('%Y-%m-%d %H:%M:%S',time_tuple))    #2020-06-19 15:31:04

#将日期字符串转换为时间元组
print(time.strptime("19/08/21 11:31:30", '%y/%m/%d %H:%M:%S'))  #time.struct_time(tm_year=2019, tm_mon=8, tm_mday=21, tm_hour=11, tm_min=31, tm_sec=30, tm_wday=2, tm_yday=233, tm_isdst=-1)
print(time.strptime("2019/08/21 11:31:30", '%Y/%m/%d %H:%M:%S'))    #time.struct_time(tm_year=2019, tm_mon=8, tm_mday=21, tm_hour=11, tm_min=31, tm_sec=30, tm_wday=2, tm_yday=233, tm_isdst=-1)

print('开始运行')
time.sleep(5)   #等待5秒
print('程序结束')

正则表达式

规则和C#几乎一致 用r R替代@取消\转义

. \w \s \d \b ^ $

? + * {n} {n,} {n,m}

​ 模块名re ,需引入 import re

re.match(pattern,string[,flags])

​ re.match(pattern,string[,flag]) 返回match 对象: flag : A或ASCII 只进行ASCII匹配 ; I 或 IGNORECASE 忽略大小写 ; M或MUTILINE ; S 或 DOTAIL 表示.匹配任意字符,包含换行符 ; X或VERBOSE 忽略模式字符字符串中未转义的空格和注释

re.search(pattern,string[,flags])
re.findall(pattern,string[,flags])
re.sub(pattern,repl,string,count,flags)
re.split(pattern,string,[maxsplit],[flags])

!和C#不同是从头开始匹配,如果开头不匹配,则直接返回none,没有迭代过程

import re

strDemo = "阿sdf_sflweSDF344#SFasfasf%sf7e"
strPt = r"_sf\w+?#"
strPts=r"\w+?_sf\w+?#"
matchRet = re.match(strPt, strDemo, re.I)
matchRet1 = re.match(strPts, strDemo, re.I)  #从头匹配的第一个
print(matchRet,matchRet1)     #  None  !和C#不同是从头开始匹配,如果开头不匹配,则直接返回none,没有迭代过程  <re.Match object; span=(0, 18), match='阿sdf_sflweSDF344#'>
print("起始位置:{:d} 结束位置:{:d} 匹配位置的元组:{:s} 源字符:{:s} 匹配数据:{:s}".format(matchRet1.start(),matchRet1.end(),str(matchRet1.span()),matchRet1.string,matchRet1.group()))
# 起始位置:0 结束位置:18 匹配位置的元组:(0, 18) 源字符:阿sdf_sflweSDF344#SF 匹配数据:阿思sdf_sflweSDF344#
ret=re.search(strPt,strDemo,re.I)  #匹配的第一个
print("起始位置:{:d} 结束位置:{:d} 匹配位置的元组:{:s} 源字符:{:s} 匹配数据:{:s}".format(ret.start(),ret.end(),str(ret.span()),ret.string,ret.group()))
# 起始位置:5 结束位置:18 匹配位置的元组:(5, 18) 源字符:阿sdf_sflweSDF344#SF 匹配数据:_sflweSDF344#
strPt = r"sf"
allRet=re.findall(strPt,strDemo,re.I)  #查找全部匹配的字符串,并以列表返回
print(allRet)   # ['sf', 'SF']
strRp=re.sub(strPt,'1111',strDemo,1,re.I)   #阿sdf_1111lweSDF344#SFasfasf%sf7e  1表示只替换一次
print(strRp)    # 阿sdf_1111lweSDF344#SF
strSplit=re.split(strPt,strDemo,2,re.I)     #['阿sdf_', 'lweSDF344#', 'asfasf%sf7e']  2表示分割俩次
print(strSplit)

函数

​ # def 定义,注意冒号: 多个参数用, 当传递的实参是不可变对象时,进行值传递,为可变对象时,进行引用传递

def functionname([pramlst]) :	  #命名规范:全小写

​ [’’‘comment’’’] # 和C#的///给函数添加注释类似

​ [funcbody] # 函数体,如果有返回值,则用return

​ def functionDemo(name,age)

​ print(“姓名:{😒} 年龄:{:d}”.format(name,age))

函数传参
'''
函数传参
实参传递方式
'''
def function_demo(name, age, des="说明"):     # 有默认值,可以不传
    print("姓名:{:s} 年龄:{:d} des:{:s}".format(name, age + 1, des))    
    


def fun01(a,b,c):#形参 a b c
    print(a)
    print(b)
    print(c)

#位置实参 实参是根据位置与形参对应的
#如果实参位置发生改变 会影响函数结果
fun01(10,20,30)
fun01(30,10,20)

#序列实参  用*将序列中的元素拆开然后与形参依次对应
#序列 字符串 列表 元组
list01 = [10,20,30]
fun01(*list01)
str01 = 'abcd'
fun01(*str01)#报错

#关键字实参
#实参的值与形参的名称对应
fun01(a=10,b=20,c=30)
#使用关键字实参 传参的顺序可以不固定
fun01(c=30,a=10,b=20)
fun01(a=10,b=20,d=40)#错误

#字典实参 使用**将字典拆开,字典中的键值对以关键字的形式进行对应,传递值
dict01 = {'a':10,'b':20,'c':30}
#a = 10 , b = 20 ,c = 30
fun01(**dict01)
#字典中的键的名字要与形参名对应
dict01 = {'a':10,'e':20,'d':30}
fun01(**dict01)#报错

# 混合使用
# 语法规定 先写位置参数 再写关键字参数
fun01(10,20,c=30)
# fun01(c=30,b=20,10)#报错
fun01(10,c=30,b=20)
#星号元组形参
#接受不定数量的实参 让实参的数量可以无限多
def fun02(p1,p2,*args):
    print(p1) #1
    print(p2)   #2
    print(*args)    #3 4 5 6 7 8 9 10

fun02(1,2,3,4,5,6,7,8,9,10)
fun02(1,2)

#在星号元组形参以后的形参叫做命名关键字形参
#传递实参的过程中 必须指定形参的名字
def fun03(*args,p1 = '',p2):
    print(*args) # 1 2 3 4 5 6
    print(p1) #
    print(p2) # 20
fun03(1,2,3,4,5,6,p2=20) 

#双星号字典形参 让关键字实参的数量无限
#将关键字实参的变量名作为字典的键 值做为字典中对应键的值保存
def fun05(**kwargs):
    print(kwargs)

fun05(a=10) #{'a': 10}
fun05(a=10,b=20,c=30)   #{'a': 10, 'b': 20, 'c': 30}

#定义一个函数 函数中包含位置形参、星号元组形参、默认形参、命名关键字形参和双星号字典形参
def fun07(a,*args,b='bbb',c,**kwargs):
    print(a) #1     #5
    print(args) #()  #(6,7)
    print(b) #bbb      #bbb
    print(c) #ccc       #abc
    print(kwargs) #{}   {'d':'798'}

fun07(1,c='ccc')
fun07(5,6,7,c='abc',d='789')

#定义一个函数 接受任意的参数 并输出结果
def fun08(*args,**kwargs):
    for item in args:
        print(item)
    for k,v in kwargs.items():
        print(k,v)

fun08()
fun08(5,6,7,a=123,b='789')  
# 5 
# 6 
# 7 
# a 123  
# b 789
#全局变量,局部变量 定义在函数外,函数内,函数内的局部变量通过 global 修饰后,就成为全局变量

locals() 收集当前的局部变量 保存到字典

def user_info():
    uesr_name = 'shibw'
    user_age = 20
    user_email = 'shibw@tedu.cn'
    gender = '男'
    address = '北京市东城区'
    # return (uesr_name,user_age,uest_email,gender,address)
    # return user_age
    # return {'uesr_name':uesr_name,'user_age':user_age,'user_email':uesr_email,'gender':gender,'address':address}
    #locals() 收集当前的局部变量 保存到字典
    return locals()


#获取到返回的元组
print(user_info())	#{'uesr_name': 'shibw', 'user_age': 20, 'user_email': 'shibw@tedu.cn', 'gender': '男', 'address': '北京市东城区'}
inofs = user_info()
#输出详细信息
print('姓名:%s,年龄:%s,邮箱:%s,性别:%s,地址:%s' % (inofs['uesr_name'],inofs['user_age'],inofs['user_email'],inofs['gender'],inofs['address']) )
#姓名:shibw,年龄:20,邮箱:shibw@tedu.cn,性别:男,地址:北京市东城区
匿名函数

result=lambda[arg1[,arg2…]]:expression

"""
    lambda : 匿名函数
    作用:充当实参

"""
def fun01():
    print("fun01")

fun01()

# 无参数 无返回值
a = lambda :print("fun01")
a()

def fun02(func):
    print("fun02")
    func()

# 将函数作为参数,建议使用lambda.
fun02(lambda :print("fun01"))

def fun03(a,b,c):
    print("fun03")

# 有参数lambda
b = lambda a,b,c:print("fun03")

def fun04():
    print("fun04")
    print("fun04又执行喽")

# lambda 函数体只能有一句话
# fun02(lambda :print("fun04++");print("fun04又执行喽"))
# 不支持赋值语句
# fun02(lambda a:a.name = "zs")

面向对象

类,方法,属性

​ class ClassName: # 命名规范 驼峰命名

​ ‘’‘类注释信息’’’ # 类说明

​ statement #类主体

​ 创建类实例 cn=ClassName(paramlst)

​ paramlst是参数列表 ,可省

__init__(self) 构造函数,不手动创建时除self是无参的,手动创建必须包含一个self参数,指向实例本身的引用,且必须放在第一个
class ClassDemo:
    name = "kcsdemo"  # 类属性 定义在类中,实例方法之外,用法和C#的静态变量类似  各类实例共用
    age = 60
    address = "shenzhen"
    __pinfo="private 信息"
    _ptinfo="protected 信息"

    def __init__(self):
        self.des='实例属性,由实例定义,也只能由实例访问'

    def instaceFunc(self, str):  # 实例方法 定义在类中 第一参数必须是self
        print("name:{:s} age {:d} address:{:s} other:{:s}".format(ClassDemo.name,ClassDemo.age,ClassDemo.address,str+"——"+ClassDemo.company+":"+self.des))      # 通过类名.类属性访问


ClassDemo.company='kingdee'  # 自由的添加类属性
ins1=ClassDemo()
ins2=ClassDemo()
ins2.des="实例属性自由添加修改"
ins1.instaceFunc('test')   # name:kcsdemo age 60 address:shenzhen other:test——kingdee:实例属性,由实例定义,也只能由实例访问
ins2.instaceFunc('test')   # name:kcsdemo age 60 address:shenzhen other:test——kingdee:实例属性自由添加修改

访问权限
方法 属性的访问权限设置  _name 单下划线加名称 protected  __name 双下滑线加名称表示private   __name__前后双下划线一般是系统内置命名
属性
class Wife:
    def __init__(self, name,age):
        self.name = name
        #私有成员:以双下划线开头
        # self.__age = age
        # self.set_age(age)
        self.age = age

    def get_age(self):
        return self.__age

    def set_agetest(self,value):
        if 25<=value<=30:
            self.__age = value
        else:
            #抛出异常
            raise ValueError("我不要!")
    #property 拦截对age的读写操作
    age = property(get_age,set_agetest) #函数名可自定义,不需要带属性名

w01 = Wife('甄宓',26)
#不能访问私有变量
# print(w01.__age)
w01.set_age(25)
print(w01.get_age()) #25
print(w01.age)	#25
# 通过@property 将方法转换为属性,调用时,不在需要()
# @property
# def methodname(self): # 表示类的实例
#     block             # 方法体
class ProClass:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.__area=0.00
    @property
    def area(self):     #只读属性 area 可访问,不可修改,返回私有字段的属性为只读属性
        self.__area=self.width * self.height
        return self.__area


rect = ProClass(29, 31.5)
print("面积为:{:.2f}".format(rect.area))  # 面积为:913.50
#rect.area=100 #can't set attribute  只读不可修改
class Wife:
    def __init__(self, name, age):
        self.__name = name	#不会触发name属性
        self.name='test'	#会触发name属性
        # 私有成员:以双下划线开头
        # self.__age = age
        # self.set_age(age)
        self.age = age

    @property  # 拦截读取 age = property(get_age,None)
    def age(self):
        return self.__age

    # 设置写入方法age.setter(写入方法)
    @age.setter  # 拦截写入
    def age(self, value):
        if 25 <= value <= 30:
            self.__age = value
        else:
            # 抛出异常
            raise ValueError("我不要!")

    # property 拦截对age的读写操作
    # age = property(get_age,set_age)

    @property
    def name(self):#name名称要与self相同
        return self.__name

    @name.setter
    def name(self, value):
        if len(value) > 5:
            self.__name = value


w01 = Wife('甄宓', 25)
# 不能访问私有变量
# print(w01.__age)
# w01.set_age(25)
# print(w01.get_age())
print(w01.age)  # 25
print(w01.name)  # 甄宓
print(w01.__dict__) #{'_Wife__name': '甄宓', '_Wife__age': 25}
print(w01._Wife__age)   #25

#类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的
#对象的__dict__中存储了一些self.xxx的一些东西
#读写age
class Wife:
    def __init__(self, name,age):
        self.name = name
        self.age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self,value):
        if 25<=value<=30:
            self.__age = value
        else:
            raise ValueError("我不要!")

#只读(只能获取)age
class Wife01:
    def __init__(self, name):
        self.name = name
        self.__age = 25

    @property
    def age(self):
        return self.__age

# w01 = Wife01('小乔')
# w01.age = 18 异常

#只写age
class Wife02:
    def __init__(self, name,age):
        self.name = name
        self.age = age

    def set_age(self,value):
        if 25<=value<=30:
            self.__age = value
        else:
            raise ValueError("我不要!")

    age = property(None,set_age)
  

# w03 = Wife02('大桥',28)
# print(w03.age) 异常
继承

class ClassName(baseclasslist): #baseclasslist 要继承的基类,多个用,隔开,和C#类单继承不一样

​ ‘’‘类注释’’’

​ statement #类体

#isinstance()判断对象是否属于一个类
rint(isinstance(t01,Student))

# issubclass()判断一个类是不是另一个类的子类
print(issubclass(Teacher,Person))

方法重写

​ 直接在子类中写一个同名,同参数的方法就重写了

调用基类的构造函数
	super().__init__()

str repr eval、 exec

str()函数:将值转化为适于人阅读的字符串的形式

repr()函数:将值转化为供解释器读取的字符串形式

eval() 将字符串当做一句代码去执行 ,只能执行一行表达式

exec() 将字符串当做一块代码去运行用换行符或分号 分隔每一个语句

class StudentModel:
    def __init__(self, name='', age=0, score=0,id=0):
        self.name = name
        self.age = age
        self.score = score
        self.id = id

    #对象-->字符串(格式随意)
    def __str__(self):
        return '编号:%d,姓名:%s' % (self.id,self.name)
    #对象-->字符串(解释器可识别的,有格式要求,也就是说返回的字符串要能通过eval等函数执行)
    def __repr__(self):
        return "StudentModel('%s',%d,%d,%d)" % (self.name,self.age,self.score,self.id)

s01 = StudentModel('哪吒',3000,59,1)
print(s01)
str01 = str(s01)
print(str01)

#将字符串当做一句代码去执行
#eval()只能执行一行表达式
print(eval("1+2*5"))
#eval('del s01') #报错 不能识别语句

#将字符串当做一块代码去运行
#用换行符或分号 分隔每一个语句
str02 = '''a = 10
b = 20
print(a+b)
'''
exec(str02)
exec("a=11\nb=20;print(a+b)")

#克隆对象

print(repr(s01))
#repr 返回Python格式的字符串
#eval 执行字符串
s02 = eval(repr(s01))   # 将repr形成的字符串当做代码与去执行
#s03 = eval(str(s01))   # 异常
print(s02)  #编号:1,姓名:小李
# print(s02)
s02.name = "小李"
print(s01)  #编号:1,姓名:小李
print(s02)  #编号:1,姓名:小李



st="asdbd"
print(str(st)) #asdbd
print(repr(st)) #'asdbd'
print(eval(repr(st))) #asdbd
print(eval(str(st)))    #异常:name 'asdbd' is not defined  str转换出来的字符串,没带‘’会被解释器认为是变量,所以异常

a=1

# str()函数:将值转化为适于人阅读的字符串的形式
# repr()函数:将值转化为供解释器读取的字符串形式
# 1.除了字符串类型外,使用str还是repr转换没有什么区别,字符串类型的话,外层会多一对引号,这一特性有时候在eval操作时特别有用; 
# 2.命令行下直接输出对象调用的是对象的repr方法,print输出调用的是str方法

eval() 案例

class SkillImpactEffect:
    '''
    技能影响效果
    '''
    def impact(self):
        pass

#伤害效果
class DamageEffect(SkillImpactEffect):
    def __init__(self,value):
        self.value = value

    def impact(self):
        print('扣你%d血' % self.value)

#消耗法力
class CostSPEffect(SkillImpactEffect):
    def __init__(self,value):
        self.value = value

    def impact(self):
        print('消耗%d法力' % self.value)

#降低防御力
class LowerDeffenseEffect(SkillImpactEffect):
    def __init__(self, ratio, time):
        self.ratio = ratio
        self.time = time

    def impact(self):
        print('降低防御%.1f防御力,持续%.1f秒' % (self.ratio,self.time))

#技能释放器
class SkillDeployer:
    '''
    技能释放器
    '''
    def __init__(self,name):
        self.name = name
        #保存配置文件内容
        self.__dict_skill_config = self.__loacd_config_file()
        #保存创建好的效果对象
        self.__list_effect_object = self.__create_effect_object()

    #读配置文件
    def __loacd_config_file(self):
        return {
            '韦陀杵':["LowerDeffenseEffect(0.3,2.5)","CostSPEffect(20)","DamageEffect(200)"],
            '亢龙有悔':["DamageEffect(500)","CostSPEffect(100)"]
        }
    #创建对象
    def __create_effect_object(self):
        list_effect_name = self.__dict_skill_config[self.name]
        return [eval(item) for item in list_effect_name] #通过eval执行生成对象

    #调用方法
    def genernate_skill(self):
        print('看招',self.name)
        for item in self.__list_effect_object:
            item.impact()

skill01 = SkillDeployer("亢龙有悔")
skill01.genernate_skill()
# 看招 亢龙有悔
# 扣你500血
# 消耗100法力
闭包
  1. 三要素:

    – 必须有一个内嵌函数。

    – 内嵌函数必须引用外部函数中变量。

    – 外部函数返回值必须是内嵌函数。

  2. 语法

    – 定义:

    def 外部函数名(参数):

    ​ 外部变量

    ​ def 内部函数名(参数):

    ​ 使用外部变量

    ​ return 内部函数名

    – 调用:

    ​ 变量 = 外部函数名(参数)

    ​ 变量(参数)

  3. 定义:在一个函数内部的函数,同时内部函数又引用了外部函数的变量。

  4. 本质:闭包是将内部函数和外部函数的执行环境绑定在一起的对象。

  5. 优点:内部函数可以使用外部变量。

  6. 缺点:外部变量一直存在于内存中,不会在调用结束后释放,占用内存。

  7. 作用:实现python装饰器。一个函数可以被多个装饰器修饰,执行顺序为从近到远。

"""
    闭包:外部函数执行完毕后,不立即释放内存.
        而是等着内部函数使用外部嵌套变量.
"""

def fun01():
    a = 10
    def fun02():
        print(a)

    return fun02# 返回内部函数(没有执行)


# re 存储的是fun02
re = fun01()

re()# 调用fun02   10
设计模式

1.装饰器模式

def print_func_name(func):
    # *args 原函数参数可以无限制
    def wrapper(*args,**kwargs): 
        print(func.__name__)# 打印函数名称
        # return 原函数返回值
        return func(*args,**kwargs)# 调用函数,
    return wrapper

@print_func_name    #@语法糖
def say_hello():
    a=1
    print('test')
    print("hello")
    return 1

@print_func_name
def say_goodbye(name):
    print(name,"---goodbye")
    return 2

print(say_hello())#1   相当于调用 print_func_name(say_hello),执行返回的wapper()
print(say_goodbye("qtx"))#2

模块

一个 .py文件 就是一个模块

每个python模块(python文件,也就是此处的test.py和import_test.py)都包含内置的变量__name__,当运行模块被执行的时候,__name__等于文件名(包含了后缀.py);如果import到其他模块中,则__name__等于模块名称(不包含后缀.py)。而“main”等于当前执行文件的名称(包含了后缀.py)。进而当模块被直接执行时,name == 'main’结果为真。

导入模块

​ import modulename

​ from modulename import member #member 可以是一个也可以是多个,多个用,隔开,也可用*通配符代表所有member

import  ootest

ootest.ClassDemo().instaceFunc("testModule")
print(ootest.ClassDemo.company)     #模块名.相应对象 会把引入模块执行一次 
if __name__=='__main__':
    print("no module",__name__,'__main__')
else:
    print(__name__,'__main__')

from  funcDemo import *
print(circlearea(20))   # from import 不用再写模块名  全部引入,会把引入模块执行一次 譬如funcDemo中的 func_demo('tet', 23, 'rt') 会执行输出 ('tet', 23, 'rt')

from funcDemo import  circlearea
print(circlearea(30))   # 指引入需要的

import funcDemo
print(funcDemo.circlearea(20))

以下为引入的模块

ootest

class ClassDemo:
    name = "kcsdemo"  # 类属性 定义在类中,实例方法之外,用法和C#的静态变量类似  各类实例共用
    age = 60
    address = "shenzhen"
    __pinfo="private 信息"
    _ptinfo="protected 信息"

    def __init__(self):
        self.des='实例属性,由实例定义,也只能由实例访问'

    def instaceFunc(self, str):  # 实例方法 定义在类中 第一参数必须是self
        print("name:{:s} age {:d} address:{:s} other:{:s}".format(ClassDemo.name,ClassDemo.age,ClassDemo.address,str+"——"+ClassDemo.company+":"+self.des))      # 通过类名.类属性访问


ClassDemo.company='kingdee'  # 自由的添加类属性
ins1=ClassDemo()
ins2=ClassDemo()
ins2.des="实例属性自由添加修改"
ins1.instaceFunc('test')   # name:kcsdemo age 60 address:shenzhen other:test——kingdee:实例属性,由实例定义,也只能由实例访问
ins2.instaceFunc('test')   # name:kcsdemo age 60 address:shenzhen other:test——kingdee:实例属性自由添加修改

# 方法 属性的访问权限设置  _name 单下划线加名称 protected  __name 双下滑线加名称表示private   __name__前后双下划线一般是系统内置命名

funcDemo

def function_demo(name, age, des="说明"):  # 有默认值,可以不传
    print("姓名:{:s} 年龄:{:d} des:{:s}".format(name, age + 1, des))

function_demo("kcs", 29, "kingdee")  # 位置参数 传参时,按位置顺序指定   姓名:kcs 年龄:30 des:kingdee  姓名:kcs 年龄:30 des:说明
function_demo(age=29, name="kcs")  # 关键字参数,传参时,按名称传值,无关顺序


def func_demo(*prams):
    print(prams)  # ('tet', 23, 'rt')  *可变参数,会处理放到一个元组中
    for item in prams:
        print(item)

func_demo('tet', 23, 'rt')

def func_dicDemo(**params):
    print(params)  # {'tes': 1, 'dte': 'te'}
    for key, value in params.items():
        print(key, value, end='_')

#func_dicDemo(tes=1, dte='te')  # ** 表示输入的参数,类似于键值对形式,并会转换成字典

#全局变量,局部变量 定义在函数外,函数内,函数内的局部变量通过global修饰后,就成为全局变量

# 匿名函数
import math
def circlearea(r):
    result=math.pi*r*r
    return  result
r=10
print(circlearea(r))    #314.1592653589793
retlamda=lambda r:math.pi*r*r
print(retlamda(r))  #314.1592653589793
模块检索

​ 模块文件检索优先顺序:

​ 1.在当前目录查找

​ 2.在环境变量 PYTHONPATH下的每个目录进行查找

​ 3.在Python的默认安装目录查找

​ 以上路径都保存在模块sys的属性path中

		import sys
		print(sys.path)
     
   #['E:\\PythonDemo', 'E:\\PythonDemo', 'C:\\Program Files\\JetBrains\\PyCharm 2020.1.2\\plugins\\python\\helpers\\pycharm_display', 'C:\\Program Files\\python38.zip', 'C:\\Program Files\\DLLs', 'C:\\Program Files\\lib', 'C:\\Program Files', 'C:\\Program Files\\lib\\site-packages', 'C:\\Program Files\\JetBrains\\PyCharm 2020.1.2\\plugins\\python\\helpers\\pycharm_matplotlib_backend']

添加检索路径

​ egpath:“E:\program\demo”

​ 1.临时添加(只在执行当前文件的窗口中有效,窗口关闭即失效)

​ sys.path.apend(“E:\program\demo”)

​ 2.在Python的安装目录下的 Lib\site-packages子目录中添加*.ph 文件 将路径添加到其中

​ E:\program\demo

​ 3. 在环境变量 PYTHONPATH添加

模块变量
__all__变量:定义可导出成员,仅对from xx import *语句有效。

__doc__变量:文档字符串。

__file__变量:模块对应的文件路径名。

__name__变量:模块自身名字,可以判断是否为主模块。

当此模块作为主模块(第一个运行的模块)运行时,__name__绑定'__main__',不是主模块,而是被其它模块导入时,存储模块名。

包名 小写

# 创建包就是创建一个文件夹,并在改该文件夹下创建一个__init__.py的文件,该文件可为空,也可添加代码,在导入包的时候会自动执行
print("包名:{:s}".format(__name__))

异常处理

try:

​ block1

except [(ExceptionName1,ExceptionName2)[as alias]] :

​ block2 # 发生异常执行 eg:print(alias)

else:

​ block3 # 不发生异常执行

finally:

​ block4 # 始终执行

抛出异常

​ raise [ExceptionName[(异常描述信息)]]

try

​ pass

except Exception as exp

​ print(str(exp.args))

数据结构

线性结构:1-1

其存储方式分为顺序存储,链式存储

  1. 顺序结构 优点 : 查找遍历方便 缺点 : 数据量大的时候不利于存储 不利于从中间插入数据

    若将线性表L=(a0,a1, ……,an-1)中的各元素依次存储于计算机一片连续的存储空间,这种机制表示为线性表的顺序存储结构。

    特点

    • 逻辑上相邻的元素 ai, ai+1,其存储位置也是相邻的;
    • 存储密度高,方便对数据的遍历查找。
    • 对表的插入和删除等运算的效率较差。
  2. 链式结构 优点: 数据存储分散,便于数据的插入删除操作 缺点: 结构设计相对复杂,遍历速度慢

    将线性表L=(a0,a1,……,an-1)中各元素分布在存储器的不同存储块,称为结点,每个结点(尾节点除外)中都持有一个指向下一个节点的引用,这样所得到的存储结构为链表结构。

    特点

    • 逻辑上相邻的元素 ai, ai+1,其存储位置也不一定相邻;
    • 存储稀疏,不必开辟整块存储空间。
    • 对表的插入和删除等运算的效率较高。
    • 逻辑结构复杂,不利于遍历。

自定义链表

# 创建节点类
class Node:
    """
    包含一个简单的数字作为数据
    next 构建关系
    """
    def __init__(self,val,next=None):
        self.val = val  #  有用数据
        self.next = next # 节点关系

"""
1. 构建节点间关系
2. 在节点中存储数据
3. 对单链表进行节点操作
"""

# 单链表的类
class LinkList:
    """
    思路: 生成对象即表示一个单链表对象
         对象调用方法可以完成对单链表的各种操作
    """
    def __init__(self):
        """
        初始化时 创建一个无用的节点,让对象拥有该节点,以表达链表的开端
        """
        self.head = Node(None)

    # 初始化
    def init_list(self,iter):# 链表初始化,将含迭代器的对象转换为链表
        p = self.head
        for i in iter:
            p.next = Node(i)
            p = p.next

    # 遍历打印
    def show(self):
        p = self.head.next # 第一个有效节点
        while p is not None:
            print(p.val)
            p = p.next   # p向后移动

    # 判断链表是否为空
    def is_empty(self):
        return self.head.next is None

    # 清空链表
    def clear(self):
        self.head.next = None

    # 尾部插入
    def append(self,val):
        p = self.head
        # p 移动到最后一个节点
        while p.next is not None:
            p = p.next
        p.next = Node(val)

    # 头部插入
    def head_insert(self,val):
        node = Node(val)
        node.next = self.head.next
        self.head.next = node

    # 指定位置插入
    def insert(self,index,val):
        p = self.head
        # 将p移动到待插入位置的前一个
        for i in range(index):
            # 超出最大范围
            if p.next is None:
                break
            p = p.next

        node = Node(val)
        node.next = p.next
        p.next = node

    # 删除节点(删除第一个val值)
    def delete(self,val):
        p = self.head
        # 确定p的位置(停留在待删除节点的前一个)
        while p.next and p.next.val != val:
            p = p.next

        # 分情况讨论
        if p.next is None:
            raise ValueError("x not in link")
        else:
            p.next = p.next.next

    # 获取节点值
    def get_value(self,index):
        if index < 0:
            raise IndexError('link index out of range')
        p = self.head.next
        for i in range(index):
            if p.next is None:
                raise IndexError('link index out of range')
            p = p.next
        return p.val
  1. 定义

栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈),允许进行操作的一端称为“栈顶”,另一固定端称为“栈底”,当栈中没有元素时称为“空栈”。

  1. 特点:
  • 栈只能在一端进行数据操作
  • 栈模型具有先进后出或者叫做后进先出的规律

栈的操作有入栈(压栈),出栈(弹栈),判断栈的空满等操作。

"""
sstack.py  栈模型的顺序存储

思路:
1. 利用列表完成顺序存储,但是列表功能多,不符合栈模型特点
2. 使用类将列表封装,提供符合栈特点的接口方法
"""

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

# 顺序栈模型
class SStack:
    def __init__(self):
        # 开辟一个顺序存储的模型空间
        # 列表的尾部表示栈顶
        self._elems = []

    # 判断栈是否为空
    def is_empty(self):
        return self._elems == []

    # 入栈
    def push(self,val):
        self._elems.append(val)

    # 出栈
    def pop(self):
        if self.is_empty():
            raise StackError("Stack is empty")
        # 弹出一个值并返回
        return self._elems.pop()

    # 查看栈顶元素
    def top(self):
        if self.is_empty():
            raise StackError("Stack is empty")
        return self._elems[-1]
"""
lstack.py 栈的链式结构
重点代码

思路:
1. 源于节点存储数据,建立节点关联
2. 封装方法 入栈 出栈 栈空 栈顶元素
3. 链表的开头作为栈顶(不需要每次遍历)
"""

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

# 创建节点类
class Node:
    def __init__(self,val,next=None):
        self.val = val  #  有用数据
        self.next = next # 节点关系

# 链式栈
class LStack:
    def __init__(self):
        # 标记顶位置
        self._top = None

    def is_empty(self):
        return self._top is None

    def push(self,val):
        self._top = Node(val,self._top)

    def pop(self):
        if self._top is None:
            raise StackError("Stack is empty")
        value = self._top.val
        self._top = self._top.next
        return value

    def top(self):
        if self._top is None:
            raise StackError("Stack is empty")
        return self._top.val

队列
  1. 定义

队列是限制在两端进行插入操作和删除操作的线性表,允许进行存入操作的一端称为“队尾”,允许进行删除操作的一端称为“队头”。

  1. 特点:
  • 队列只能在队头和队尾进行数据操作
  • 队列模型具有先进先出或者叫做后进后出的规律
"""
squeue.py  队列的顺序存储

思路分析:
1. 基于列表完成数据的存储
2. 通过封装功能完成队列的基本行为
3. 无论那边做对头/队尾 都会在操作中有内存移动
"""

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

# 队列操作
class SQueue:
    def __init__(self):
        self._elems = []

    # 判断队列是否为空
    def is_empty(self):
        return self._elems == []

    # 入队
    def enqueue(self,val):
        self._elems.append(val)

    # 出队
    def dequeue(self):
        if not self._elems:
            raise QueueError("Queue is empty")
        return self._elems.pop(0) # 弹出第一个数据
"""
lqueue.py 链式队列
重点代码

思路分析:
1. 基于链表构建队列模型
2. 链表的头作为队头,尾作为队尾
3. 定义两个标记标记队头和队尾
4. 头和尾代表同一个无用节点时队列为空
"""

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

# 创建节点类
class Node:
    def __init__(self,val,next=None):
        self.val = val  #  有用数据
        self.next = next # 节点关系

# 队列操作
class LQueue:
    def __init__(self):
        # front 队头  rear 队尾
        self.front = self.rear = Node(None)

    def is_empty(self):
        return self.front == self.rear

    def enqueue(self,val):
        self.rear.next = Node(val)
        self.rear = self.rear.next

    def dequeue(self):
        if self.is_empty():
            raise QueueError("Queue is empty")
        # front 是指向队头节点的前一个
        self.front = self.front.next
        return self.front.val

*树形结构 1-n

树(Tree)是n(n≥0)个节点的有限集合T,它满足两个条件:有且仅有一个特定的称为根(Root)的节点;其余的节点可以分为m(m≥0)个互不相交的有限集合T1、T2、……、Tm,其中每一个集合又是一棵树,并称为其根的子树(Subtree)。

在这里插入图片描述

  • 一个节点的子树的个数称为该节点的度数,一棵树的度数是指该树中节点的最大度数。
  • 度数为零的节点称为树叶或终端节点,度数不为零的节点称为分支节点。
  • 一个节点的子树之根节点称为该节点的子节点,该节点称为它们的父节点,同一节点的各个子节点之间称为兄弟节点。一棵树的根节点没有父节点,叶节点没有子节点。
  • 节点的层数等于父节点的层数加一,根节点的层数定义为一。树中节点层数的最大值称为该树的高度或深度。

在这里插入图片描述

二叉树

定义

二叉树(Binary Tree)是n(n≥0)个节点的有限集合,它或者是空集(n=0),或者是由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成。二叉树与普通有序树不同,二叉树严格区分左孩子和右孩子,即使只有一个子节点也要区分左右。

在这里插入图片描述

"""
bitree.py 二叉树的实现

思路分析:
1. 使用链式存储, Node表达一个节点(值,左链接,右链接)
2. 分析遍历过程
3. 递归实现遍历
"""


# 二叉树节点
class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


# 二叉树遍历
class Bitree:
    # 传入树根
    def __init__(self, root):
        self.root = root

    # 先序遍历
    def preOrder(self, node):
        if node is None:
            return
        print(node.val, end=' ')
        self.preOrder(node.left)
        self.preOrder(node.right)

    # 中序遍历
    def inOrder(self, node):
        if node is None:
            return
        self.inOrder(node.left)
        print(node.val, end=' ')
        self.inOrder(node.right)

    # 后序遍历
    def postOrder(self, node):
        if node is None:
            return
        self.postOrder(node.left)
        self.postOrder(node.right)
        print(node.val, end=' ')

    # 层次遍历
    def levelOrder(self, node):
        lq = LQueue()  # 引用上述链式对列
        # 初始节点先入队,循环判断,队列不为空则出队
        # 出队元素的左右孩子分别入队
        lq.enqueue(node)
        while not lq.is_empty():
            # 出队,打印表示遍历
            node = lq.dequeue()
            print(node.val, end=' ')
            if node.left:
                lq.enqueue(node.left)
            if node.right:
                lq.enqueue(node.right)


if __name__ == '__main__':
    # B F G D H I E C A
    # 构建起一个二叉树
    b = Node('B')
    f = Node('F')
    g = Node("G")
    d = Node('D', f, g)
    h = Node('H')
    i = Node('I')
    e = Node('E', h, i)
    c = Node('C', d, e)
    a = Node('A', b, c)  # 树根

    bt = Bitree(a)

    bt.preOrder(bt.root)
    print()
    bt.inOrder(bt.root)
    print()
    bt.levelOrder(bt.root)
常见排序算法
"""
sort.py 排序训练
"""

# 冒泡
def bubble(l):
    n = len(l)
    # 循环n - 1 次,每次确定一个最大值
    for i in range(n - 1):
        # 两两比较交换
        for j in range(n - 1 - i):
            if l[j] > l[j + 1]:
                l[j],l[j + 1] = l[j + 1],l[j]  # 直接一起交换值,不需要中间项过度


l = [4,5,7,1,2,9,6,8]
bubble(l)
print(l)
"""
*快速排序算法
"""

def sub_sort(l,low,high):
    x = l[low]  # 基准
    while low < high:
        # 如果后边的数比x大high向前走
        while l[high] > x and high > low:
            high -= 1
        l[low] = l[high]  # 比x小的往前甩
        # 如果前面的数比x小则low往后走
        while l[low] <= x and low < high:
            low += 1
        l[high] = l[low]  # 比x大的往后甩
    l[low] = x  # 将x插入最终位置
    return low  #  每一轮最终基准数确定的位置


# low : 第一个元素索引号,high: 最后一个元素索引号
"""
该写法表示希望low传一个整形,high传一个整形,返回值为None类型
但是没有强制要求必须这样做
"""
def quick(l:list,low:int,high:int)->None:#-> 3.x语法,常常出现在python函数定义的函数名后面,为函数添加元数据,描述函数的返回类型
    if low < high:
        key = sub_sort(l,low,high)
        quick(l,low,key-1)
        quick(l,key+1,high)


l = [8,1,12,7,6,10,3,4,8,5,9,2,11,5,13]
quick(l,0,len(l)-1)
print(l)

IO / 文件及目录操作

字节串(bytes)

在python3中引入了字节串的概念,与str不同,字节串以字节序列值表达数据,更方便用来处理二进程数据。因此在python3中字节串是常见的二进制数据展现方式。

  • 普通的ascii编码字符串可以在前面加b转换为字节串,例如:b’hello’
  • 字符串转换为字节串方法 :str.encode()
  • 字节串转换为字符串方法 : bytes.decode()

文件

  1. 打开文件

    Python 内置了File对象 通过open(),close() 要及时关闭文件

    file=open(filename[,mode[,buffering[,encoding]]])

    filename:如果与py文件在同一目录下,写文件名就可以,不在同一目录要全路径或相对路径

file_object = open(file_name, access_mode='r', buffering=-1)
功能:打开一个文件,返回一个文件对象。
参数:file_name  文件名;
     access_mode  打开文件的方式,如果不写默认为‘r’ 
          文件模式                        操作
              r                    以读方式打开 文件必须存在
              w                    以写方式打开
                                   文件不存在则创建,存在清空原有内容 
              a                    以追加模式打开 
              r+                   以读写模式打开 文件必须存在
              w+                   以读写模式打开文件
                                   不存在则创建,存在清空原有内容
              a+                   以读写模式打开 追加模式
              rb                   以二进制读模式打开 同r
              wb                   以二进制写模式打开 同w
              ab                   以二进制追加模式打开 同a
              rb+                  以二进制读写模式打开 同r+
              wb+                  以二进制读写模式打开 同w+
              ab+                  以二进制读写模式打开 同a+
     buffering  1表示有行缓冲,默认则表示使用系统默认提供的缓冲机制。
返回值:成功返回文件操作对象。
  1. 读取文件

read([size])
功能: 来直接读取文件中字符。
参数: 如果没有给定size参数(默认值为-1)或者size值为负,文件将被读取直至末尾,给定size最多读取给定数目个字符(字节)。
返回值: 返回读取到的内容

  • 注意:文件过大时候不建议直接读取到文件结尾,读到文件结尾会返回空字符串。

readline([size])
功能: 用来读取文件中一行
参数: 如果没有给定size参数(默认值为-1)或者size值为负,表示读取一行,给定size表示最多读取制定的字符(字节)。
返回值: 返回读取到的内容

readlines([sizeint])
功能: 读取文件中的每一行作为列表中的一项
参数: 如果没有给定size参数(默认值为-1)或者size值为负,文件将被读取直至末尾,给定size表示读取到size字符所在行为止。
返回值: 返回读取到的内容列表

文件对象本身也是一个可迭代对象,在for循环中可以迭代文件的每一行。

for line in f:
     print(line)
"""
从终端输入一个单词,从单词本中刚找到该单词,打印这一行内容,如果没有找到则打印"找不到"
"""

word = input("单词:")

# 打开文件
f = open('dict.txt')

for line in f:
    w = line.split(' ')[0]
    # 遍历的单词已经大于目标,说明找不到了
    if w > word:
        print("没有找到该单词")
        break
    elif w == word:
        print(line)
        break
else:
    print("没有找到该单词")

f.close()
  1. 写入文件

write(string)
功能: 把文本数据或二进制数据块的字符串写入到文件中去
参数:要写入的内容
返回值:写入的字符个数

  • 如果需要换行要自己在写入内容中添加\n

writelines(str_list)
功能:接受一个字符串列表作为参数,将它们写入文件。
参数: 要写入的内容列表

"""
编写一个文件拷贝程序,将一个文件拷贝一份,重新取另外一个名字(自定).
      文件可能是文本,也可能是二进制
"""
filename = input("文件:")
fr = open(filename,'rb')
fw = open("备份-"+filename,'wb')
while True:
    # 循环读取
    data = fr.read(1024)
    if not data:  # 文件结束
        break
    fw.write(data)
fr.close()
fw.close()
  1. 关闭文件

打开一个文件后我们就可以通过文件对象对文件进行操作了,当操作结束后使用close()关闭这个对象可以防止一些误操作,也可以节省资源。

file_object.close()

  1. with操作

python中的with语句使用于对资源进行访问的场合,保证不管处理过程中是否发生错误或者异常都会执行规定的“清理”操作,释放被访问的资源,比如有文件读写后自动关闭、线程中锁的自动获取和释放等。

with语句的语法格式如下:

with context_expression [as obj]:
    with-body

通过with方法可以不用close(),因为with生成的对象在语句块结束后会自动处理,所以也就不需要close了,但是这个文件对象只能在with语句块内使用。

with open('file','r+') as f:
    f.read()

注意

  1. 加b的打开方式读写要求必须都是字节串
  2. 无论什么文件都可以使用二进制方式打开,但是二进制文件使用文本方式打开读写会出错


filetxt= open(r"C:\Users\Administrator.-20171206IUEUWS\Desktop\pythonNode\Test\tets.txt","r",1,encoding="utf-8")
print(filetxt)
str=filetxt.read()  #测试python file open
print(str)
filetxt.close()

filetxt1= open(r"C:\Users\Administrator.-20171206IUEUWS\Desktop\pythonNode\Test\tetsRW.txt","a+",1,encoding="utf-8")
filetxt1.write("safasf")
filetxt1.close()

filetxt2=open(r"..\testfile\te1.txt")
print(filetxt2)
filetxt2.close()
if os.path.exists(r'..\testfile\te1.txt'):
    os.rename(r'..\testfile\te1.txt', r'..\testfile\test.txt', )  # 删除文件 如果不存在,则异常

print(os.stat(r'..\testfile\test.txt'))	#os.stat_result(st_mode=33060, st_ino=1407374883553465, st_dev=1710438242, st_nlink=1, st_uid=0, st_gid=0, st_size=86, st_atime=1591954640, st_mtime=1592186618, st_ctime=1591954640)
os.startfile(r'..\testfile\test.txt')  # 用默认关联的程序打开文件
print(os.access(r'..\testfile\test.txt', os.W_OK))  # 获取对文件的操作权限  os.R_OK:读取  os.W_OK:写入 os.OK:执行  os.F_OK:存在

import  stat	#引入状态包
os.chmod(r'..\testfile\test.txt',stat.S_IREAD)
print(os.access(r'..\testfile\test.txt', os.W_OK))
# if os.path.exists(r'..\testfile\te1.txt'):
# os.remove(r'..\testfile\test.txt')  #删除文件 如果不存在,则异常
with 和C# using 功能类似,控制自动释放

with expression as target

with body

with open(r"..\testfile\te1.txt","r+",1,encoding="utf-8") as filearw:
    str =filearw.read()
    print('111'+str)    #111testa

刷新缓冲区

缓冲:系统自动的在内存中为每一个正在使用的文件开辟一个缓冲区,从内存向磁盘输出数据必须先送到内存缓冲区,再由缓冲区送到磁盘中去。从磁盘中读数据,则一次从磁盘文件将一批数据读入到内存缓冲区中,然后再从缓冲区将数据送到程序的数据区。

刷新缓冲区条件:

  1. 缓冲区被写满
  2. 程序执行结束或者文件对象被关闭
  3. 行缓冲遇到换行
  4. 程序中调用flush()函数
"""
buffer.py
缓冲区演示
"""

# f = open('test','w',1) # 行缓冲
f = open('test','w')

while True:
    data = input(">>")
    if not data:
        break
    f.write(data + '\n')
    f.flush()  # 主动刷新缓冲,如果不刷新,每次以w模式打开就会清除掉之前写入的内容

f.close()

文件偏移量

  1. 定义

打开一个文件进行操作时系统会自动生成一个记录,记录中描述了我们对文件的一系列操作。其中包括每次操作到的文件位置。文件的读写操作都是从这个位置开始进行的。

  1. 基本操作

tell()
功能:获取文件偏移量大小

seek(offset[,whence])
功能:移动文件偏移量位置
参数:offset 代表相对于某个位置移动的字节数。负数表示向前移动,正数表示向后移动。
whence是基准位置的默认值为 0,代表从文件开头算起,1代表从当前位置算起,2 代表从文件末尾算起。

  • 必须以二进制方式打开文件时基准位置才能是1或者2
"""
seek.py  文件偏移量

注意: 1. open打开文件会重置文件偏移量
     2. 读写操作使用的是一个偏移量值
     3. seek操作文件偏移量一般是以二进制打开
"""

f = open("test",'wb+')

f.write(b"Hello world")
# f.close()
#
# f = open('test','r')

print("偏移量:",f.tell()) # 获取文件偏移量  # 偏移量: 11

f.seek(-5,2)  # 将文件偏移量定位到开头

data = f.read() 
print(data) #b'world'

f.close()

文件描述符

  1. 定义

系统中每一个IO操作都会分配一个整数作为编号,该整数即这个IO操作的文件描述符。

  1. 获取文件描述符

fileno()
通过IO对象获取对应的文件描述符

f = open("test",'wb+')
print(f.fileno()) # 3

文件管理函数

  1. 获取文件大小

os.path.getsize(file)

  1. 查看文件列表

os.listdir(dir)

  1. 查看文件是否存在

os.path.exists(file)

  1. 判断文件类型

os.path.isfile(file)

  1. 删除文件

os.remove(file)

目录操作

​ os 是内置的与操作系统功能和文件系统相关的模块,不同的系统表现可能表现不同

import  os

print(os.name)      # nt 用于获取操作系统类型 nt:windows  posix:Linux,unix,Mac os
print(os.linesep)   #  当前操作系统的换行符
print(os.sep)       # \ 当前操作系统的操作分隔符
print(os.getcwd())  #  E:\PythonDemo\ostest 获取当前路径
print(os.path.abspath(r'..\testfile\demo1.py')) #  E:\PythonDemo\testfile\demo1.py 获取相对路径的绝对路径
print(os.path.join(os.getcwd(),'test')) # E:\PythonDemo\ostest\test 拼接路径,不需要/
print(os.path.exists(r'..\testfile'))   # True
print(os.path.isdir(r'..\testfile'))    # True
# print(os.listdir('E:\PythonDemo'))
if not os.path.exists('DirDemo'):
    print(os.mkdir('DirDemo',)) # None
if not os.path.exists('E:\PythonDemo\DirTest'):
    print(os.mkdir('E:\PythonDemo\DirTest'))    # None
#  print(os.mkdir(r'E:\PythonDemo\Dirtest\1\2'))   #系统找不到指定的路径。: 'E:\\PythonDemo\\Dirtest\\1\\2'
if not os.path.exists(r'E:\PythonDemo\Dirtest\1\2'):
    print(os.makedirs(r'E:\PythonDemo\Dirtest\1\2'))    # None

os.rmdir(r'E:\PythonDemo\Dirtest\1\2')  # 只能删除空目录

import shutil   #标准模块

shutil.rmtree(r'E:\PythonDemo\ostest\DirDemo')  # 可以删除非空目录

tuples=os.walk(r'E:\PythonDemo')    #遍历目录,返回元组生成器对象
for tp in tuples:
    print(tp)
# ('E:\\PythonDemo', ['.idea', 'DirTest', 'FileDemo', 'ostest', 'pkgdemo1', 'testfile', '__pycache__'], ['demo1.py', 'DicTest.py', 'funcDemo.py', 'moduletest.py', 'modulpath.py', 'ootest.py', 'pdemo1.py', 'pkgtest.py', 'propertyDemo.py', 'retestdemo.py', 'strtest.py', 'TestDemo.py', 'tupletest.py', 'ZetTest.py', '人哇若.py'])
# ('E:\\PythonDemo\\.idea', ['dictionaries', 'inspectionProfiles'], ['.gitignore', 'misc.xml', 'modules.xml', 'PythonDemo.iml', 'workspace.xml'])
# ('E:\\PythonDemo\\.idea\\dictionaries', [], ['Administrator.xml'])
# ...

数据库链接

sqlite:

​ 内置

#1.创建链接对象 connect()  链接参数以具体模块定义为准      相当于sqlConnection
#2.游标对象 cursor() 用于指示抓取数据操作的上下文,用于执行sql ,proc等      #相当于sqlCommand+sqlAdapter

import  sqlite3
conn=sqlite3.connect('iteTest.db')
cursor=conn.cursor()
cursor.execute('drop table User')
cursor.execute('create table User(id int(10) primary key,name nvarchar(10),age int(3))')
cursor.close()
conn.commit()
conn.close()

mssql:

​ 需要先安装包,在终端 pip install pymssql;因为网络等原因,通常需要离线下载后,在本地安装,如:

pip install E:\PythonDemo\pymssql-2.1.4-cp38-cp38-win_amd64.whl


import pymssql

try:
    msConn = pymssql.connect('127.0.0.1', 'sa', 'kangzi20119', 'ReportServer')
    if msConn:
        print("链接成功")
        cursor = msConn.cursor()
        cursor.execute("SELECT * FROM Roles")  # 执行查询
        data = cursor.fetchall()
        print(type(data))
        print(data)
        msConn.close()
except Exception as ei:
    print("链接失败:" + str(ei))

常用内置函数

testfield=125

type(testfield) 返回变量的类型

id(testfield) 返回变量所指的内存地址

str(testfield) 将数值转换为字符串

range(start,end,step):返回一系列连续的整数 range(7) 返回 0~6

枚举函数enumerate

  1. 语法:

for 变量 in enumerate(可迭代对象):

​ 语句

for 索引, 元素in enumerate(可迭代对象):

​ 语句

  1. 作用:遍历可迭代对象时,可以将索引与元素组合为一个元组。

zip

  1. 语法:

for item in zip(可迭代对象1, 可迭代对象2….):

​ 语句

作用:将多个可迭代对象中对应的元素组合成一个个元组,生成的元组个数由最小的可迭代对象决定

range

range() 函数可创建一个整数列表

range(10)        # 从 0 开始到 10
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(1, 11)     # 从 1 开始到 11
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range(0, 30, 5)  # 步长为 5
[0, 5, 10, 15, 20, 25]
range(0, 10, 3)  # 步长为 3
[0, 3, 6, 9]
range(0, -10, -1) # 负数
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
range(0)
[]
range(1, 0)
[]


【为什么学PythonPython 是当今非常热门的语言之一,2020年的 TIOBE 编程语言排行榜中 ,Python名列第一,并且其流行度依然处在上升势头。 在2015年的时候,在网上还经常看到学Python还是学R的讨论,那时候老齐就选择了Python,并且开始着手出版《跟老齐学Python》。时至今日,已经无需争论。Python给我们带来的,不仅仅是项目上的收益,我们更可以从它“开放、简洁”哲学观念中得到技术发展路线的启示。 借此机会,老齐联合CSDN推出了本课程,希望能影响更多的人走进Python,踏入编程的大门。 【课程设计】 本课程共包含三大模块: 一、基础知识篇 内置对象和基本的运算、语句,是Python语言的基础。本课程在讲解这部分知识的时候,不是简单地将各种知识做简单的堆砌,而是在兼顾内容的全面性的同时,更重视向学习者讲授掌握有关知识的方法,比如引导学习者如何排查错误、如何查看和理解文档等。   二、面向对象篇 “面向对象(OOP)”是目前企业开发主流的开发方式,本课程从一开始就渗透这种思想,并且在“函数”和“类”的学习中强化面向对象开发方式的学习——这是本课程与一般课程的重要区别,一般的课程只在“类”这里才提到“对象”,会导致学习者茫然失措,并生畏惧,乃至于放弃学习。本课程则是从开始以“润物细无声”的方式,渗透对象概念,等学习到本部分的时候,OOP对学习者而言有一种“水到渠成”的感觉。   三、工具实战篇 在项目实战中,除了前述的知识之外,还会用到很多其他工具,至于那些工具如何安装?怎么自己做工具?有那些典型工具?都是这部分的内容。具体来说,就是要在这部分介绍Python标准库的应用以及第三方包的安装,还有如何开发和发布自己的工具包。此外,很多学习Python的同学,未来要么从事数据科学、要么从事Web开发,不论哪个方向,都离不开对数据库的操作,本部分还会从实战的角度,介绍如何用Python语言操作常用数据库。
©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页