1
变量名,等号,变量值
id,type,value
等号比较的是value
is比较的是id,是否是同一内存地址
2
x=y=z=10
3
x,y,*_=[3.1,2.1,4.3,2.2,1.3,9.3]
4 int float str list tuple dict set
list dict set
int float str tuple
5 int float str list tuple dict set
list tuple dict set
str list tuple
6
python2 ascii
python3 utf-8
7
怎么存 怎么取
8
unicode 2 2
utf-8 1 3
gbk 1 2
ascii 1 无
coding:utf-8,来决定以什么编码格式来读入内存
9
unicode encode
10
decode
11
文本模式读 bytes模式读
文件 读 以utf-8解码到内存
12
存放变量名与值内存地址关系的地方
内置---全局---局部
局部---全局---内置
13
1
14
可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,
可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
15
对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,
若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
16
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环
17
面向过程的程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。
优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
18
res = x if x > y else y
19
1
names=[name.upper() for name in names]
2
names=[len(name) for name in names if not name.endswith('sb')]
3
with open('settings.py',encoding='utf-8') as f:
print(max(len(line) for line in f))
4,5
with open('settings.py',encoding='utf-8') as f:
print(sum(len(line) for line in f))
生成器就是迭代器 惰性计算,节省内存 一次性的,只能往后走,不能往前退
#优点:
- 提供一种统一的、不依赖于索引的迭代方式
- 惰性计算,节省内存
#缺点:
- 无法获取长度(只有在next完毕才知道到底有几个值)
- 一次性的,只能往后走,不能往前退
6
with open('aa',encoding='utf-8') as f:
info_list = [line.strip().split(',') for line in f] #列表生成式
res=sum(float(price)*int(count) for _,price,count in info_list) #解压缩+sum迭代函数
print(res)
with open('aa',encoding='utf-8') as f:
info = [{
'name':line.strip().split(',')[0],
'price':float(line.strip().split(',')[1]),
'count':int(line.strip().split(',')[2])
} for line in f] #列表生成式
print(info)
with open('aa',encoding='utf-8') as f:
info = [{
'name':line.strip().split(',')[0],
'price':float(line.strip().split(',')[1]),
'count':int(line.strip().split(',')[2])
} for line in f if float(line.strip().split(',')[1]) > 10000] #列表生成式加了一层判断
print(info)
20
1 #max+匿名函数
print(max(salaries,key=lambda k:salaries[k]))
2 #map+匿名函数
print(list(map(lambda k:(k,salaries[k]*12),salaries)))
3 #filter+匿名函数
print(tuple(filter(lambda k:salaries[k] > 10000,salaries)))
21 生成器
yield VS return
相同点:都是用在函数内,都可以返回值,没有类型限制,没有个数限制
不同点:return只能返回一次值,yield可以返回多次值
22
面向过程的程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。
优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计:核心是对象二字,对象是特征与技能的结合体,基于面向对象设计程序就好比在创造一个世界,你就是这个世界的上帝,存在的皆为对象,不存在的也可以创造出来,与面向过程机械式的思维方式形成鲜明对比,面向对象更加注重对现实世界的模拟,是一种“上帝式”的思维方式。
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:
1. 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
2. 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方
23 #继承 派生 组合
组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
class Course:
def __init__(self,name,period,price):
self.name=name
self.period=period
self.price=price
def tell_info(self):
print('<%s %s %s>' %(self.name,self.period,self.price))
class Teacher(People):
def __init__(self,name,age,sex,job_title):
People.__init__(self,name,age,sex)
self.job_title=job_title
self.course=[]
self.students=[]
class Student(People):
def __init__(self,name,age,sex):
People.__init__(self,name,age,sex)
self.course=[]
egon=Teacher('egon',18,'male','沙河霸道金牌讲师')
s1=Student('牛榴弹',18,'female')
python=Course('python','3mons',3000.0)
linux=Course('python','3mons',3000.0)
#为老师egon和学生s1添加课程
egon.course.append(python)
egon.course.append(linux)
s1.course.append(python)
#为老师egon添加学生s1
egon.students.append(s1)
#使用
for obj in egon.course:
obj.tell_info()
24
经典类与新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
Python中子类可以同时继承多个父类,如A(B,C,D)
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
当类是经典类时,多继承情况下,在要查找属性不存在时,会按照深度优先的方式查找下去
当类是新式类时,多继承情况下,在要查找属性不存在时,会按照广度优先的方式查找下去
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表
F.mro() #等同于F.__mro__
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
25 #@property 特性(伪装)
class People:
def __init__(self,name,weight,height):
self.name =name
self.weight =weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height**2)
p1 = People('xjj',70,1.78)
print(p1.bmi)
26 #__str__方法 在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回
class People:
def __init__(self,name,sex):
self.name=name
self.sex=sex
def __str__(self):
return '[name:%s sex:%s]' %(self.name,self.sex)
p1=People('egon','male')
print(p1)
27
#多态性(继承) 不同的对象,执行相同的方法名,执行的效果不同(代码不同)
多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪
文件有多种形态:文本文件,可执行文件
一 什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)
多态性是指在不考虑实例类型的情况下使用实例
在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),
不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
多态性分为静态多态性和动态多态性
静态多态性:如任何类型都可以用运算符+进行运算
动态多态性:如下
peo=People()
dog=Dog()
pig=Pig()
#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()
#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
二 为什么要用多态性(多态性的好处)
python本身就是支持多态性的
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
三 鸭子类型 多个完全不相关的类 但是定义时 大家约定俗成用相同的方法名 就是鸭子类型
Python崇尚鸭子类型 用于程序组件的松耦合度
28 #反射 通过字符串来操作类或者对象的属性
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。
这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
hasattr(object,name) #检测是否含有某属性
getattr(object, name, default=None) #获取属性
setattr(x, y, v) #设置属性
delattr(x, y) #删除属性
3 为什么用反射之反射的好处
好处一:实现可插拔机制
可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
好处二:动态导入模块(基于反射当前模块成员)
29 30 call init
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名首字母大写')
if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
raise TypeError('必须有注释且不能为空')
super().__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs):
# print(self,args,kwargs)
obj = self.__new__(self) #从类对象复制一个模板,里面已经放入了公共的属性
# print(obj.a) #比如这里输出就是a
self.__init__(obj,*args,**kwargs) #调用People类的init方法初始化
# print(obj.__dict__)
obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in obj.__dict__.items()}
#初始化完成,在未返回前,修改对象属性
return obj
class People(object,metaclass=Mymeta):
'''test'''
a='a'
def __init__(self,name,age):
self.name=name
self.age=age
p1 = People('xjj',18)
p1.name = 'egon' #修改不了,只是新加了一个属性
print(p1.__dict__)