一. 构造函数
构造函数也被称为构造器,当创建对象的时候第一个被自动调用的函数,系统默认提供了一个无参的构造函数 per = Person()
语法:
def __ init__(self,arg1,arg2,…):
函数体
说明:
之前的写法中并没有显示的定义一个个构造函数,所以系统默认提供了一个无参的构造函数
arg1,arg2,…可以自己定义,但是,一般情况下,构造函数的形参列表和成员变量有关
构造函数的特点:创建对象;给对象的成员变量赋值
构造函数和成员函数之间的区别:
1.成员函数的函数名可以自定义,但是,构造函数的函数名是固定的__init__
2.成员函数需要被手动调用,但是,构造函数在创建对象的过程中是自动被调用的
3.对于同一个对象而言,成员函数可以被调用多次,但是,构造函数只能被调用一次
二. 迭代器
迭代是python中访问集合元素的一种非常强大的一种方式。迭代器是一个可以记住遍历位置的对象,因此不会像列表那样一次性全部生成,而是可以等到用的时候才生成,因此节省了大量的内存资源。迭代器对象从集合中的第一个元素开始访问,直到所有的元素被访问完。迭代器有两个方法:iter()和next()方法。
类似于list、tuple、str 等类型的数据可以使用for …… in…… 的循环遍历语法从其中依次拿到数据并进行使用,我们把这个过程称为遍历,也称迭代。python中可迭代的对象有list(列表)、tuple(元组)、dirt(字典)、str(字符串)set等。
可迭代对象,可以被for循环的数据-----迭代器iter(),iter(),-------生成器 yield [] ()
生成器就是一种迭代器
可以被next调用并不断返回下一个值的对象称为迭代器:iterator
it = iter([1,2,3,4])
while True:
try:
res = next(it)
print(res)
except StopIteration as e:
break
>1
>2
>3
>4
三. 生成器
生成器是python中的一个对象(按照某种规律,来生成元素的对象),生成器不是列表,保存了产生元素的算法,同时会记录游标的位置(现在拿到第几个元素了),为了下次继续拿数据,而不是从头开始拿数据。可以通过一直调用next()方法获取值,这个对象不保存数据,每次调用会返回一个值,即做到了列表的好处,又不占用空间。
将列表[]改为()即可称为生成器
只要把一个列表生成式的[]改成(),就创建了一个generator
generator保存的是算法
每次调用next(g),就计算出g的下一个元素的值,
直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误
一直用next调用,一定不是一个好办法,我们需要用for来调用
for可以将StopIteration处理
因为生成器也是一个可迭代对象
我们可以用列表推导(生成式)来初始化一个列表:
list5 = [x for x in range(5)]
print(list5) #output:[0, 1, 2, 3, 4]
用类似的方式来生成一个生成器,只不过我们这次将上面的[ ]换成( ):
gen = (x for x in range(5))
print(gen)
#output: <generator object <genexpr> at 0x0000000000AA20F8>
看到上面print(gen) 并不是直接输出结果,而是告诉我们这是一个生成器。
调用这个gen有两个方式:
#1
for item in gen:
print(item)
#output:
0
1
2
3
4
#2
print(next(gen))#output:0
print(next(gen))#output:1
print(next(gen))#output:2
print(next(gen))#output:3
print(next(gen))#output:4
print(next(gen))#output:Traceback (most recent call last):StopIteration
四. 编码与解码
比特 / bit:计算机中最小的数据单位,是单个的二进制数值 0 或 1
字节 / byte:计算机存储数据的单元,1 个字节由 8 个比特组成
字符:人类能够识别的符号
编码:将人类可识别的字符转换为机器可识别的字节码 / 字节序列
解码:将机器可识别的字节码 / 字节序列转换为人类可识别的字符
编码格式;
Python2 的默认编码是ASCII,不能识别中文字符,需要显示指定字符编码。
Python3 的默认编码是Unicode,可以识别中文。
计算机内存的数据,统一使用Unicode编码;数据传输或保存在硬盘上,是哟还能UTF-8编码。
编码和解码
编码(encode):将Unicode字符串转换为特定编码格式对应的字节码的过程。
s = "学习python"
print(s.encode()) # encode()函数里参数默认为utf-8
print(s.encode('gbk'))
# 结果
'''
b'\xe5\xad\xa6\xe4\xb9\xa0python'
b'\xd1\xa7\xcf\xb0python'
'''
解码(decode):将特定编码格式的字节码转换为对应的Unicode字符串的过程。
# encode和decode的编码格式必须一致,如gbk编码,必须用gbk解码
s1 = b'\xe5\xad\xa6\xe4\xb9\xa0python'
s2 = b'\xd1\xa7\xcf\xb0python'
print(s1.decode()) # 用默认的utf-8解码
print(s2.decode('gbk')) # 用gbk解码
# 结果
'''
学习python
学习python
'''
五. 继承
继承就是让类和类之间产生父子关系,子类可以拥有父类的静态属性和方法。继承就是可以获取另外一个类的静态属性或者普通方法,(并非所有成员)。
在Python中,新建的类可以继承一个或者多个父类,父类又可以称为基类或者超类,新建的类称为派生类或子类。
'''单继承和多继承简单定义'''
class Parent1:
pass
class Parent2:
pass
class Sub1(Parent1): #单继承
pass
print(Sub1.__bases__) # 查看自己的父类---->(<class '__main__.Parent1'>,)
class Sub2(Parent1,Parent2): # 多继承
pass
print(Sub2.__bases__) # 查看自己的父类---->(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
类继承功能
类解决对象与对象之间代码冗余的问题,子类可以遗传父类的属性
继承解决的是类与类之间代码冗余的问题
object类丰富了代码的功能
多继承的优缺点
优点:子类可以同时遗传多个父类的属性,最大限度的重用代码
缺点:违反人的思维习惯,一个人有两个爹,代码的可读性会变差,不建议使用多继承,如果不可避免多个父类的继承,应该使用 Mixins机制 参考
继承表达的是一种“是”什么关系
继承中子类和父类的概念
父类:用于被继承的类,称之为父类,又叫做基类或者超类。
子类:继承其他类的类,称为子类,又叫派生类
六. 列表生成式
列表生成式是Python内置的非常简单却强大的可以用来创建list的生成式。
列表生成式的结构是在一个中括号里包含一个表达式,然后是一个for语句,然后是0个或多个for或者if语句。列表表达式可以是任意的,意思是你可以在列表中放入任意类型的对象。返回结果将是一个新的列表,在这个以if和for语句为上下文的表达式运行完成之后产生。
语法: [元素 for循环 if语句]
说明: 元素和for循环不能省略,但是,if语句可以省略
fff = [x if x % 2 == 0 else -x for x in range(1,10)]
print(fff)
>>>[-1, 2, -3, 4, -5, 6, -7, 8, -9]
七. exec对字符串执行和eval对字符串求值
exec
exec函数主要用于动态地执行代码字符串,exec 返回值永远为 None。exec()不仅可以执行python代码,还可以共享上下文,但需要注意尽量不要在全局作用域下用exec()函数执行python代码,以免发生命名空间冲突。
为了解决这个问题,可以在执行之前创建一个空字典scope = {},作为exec()函数的第二个参数,这样通过exec执行python代码时创建的变量就会存储在字典scope中。
如果exec()函数执行的python代码中含有参数,且要传参,则可以在exec()中 以字典形式进行传参,这时exec就有了第三个参数args。当说要执行的代码是多行时,可以用"“” “”"引起来.
args = {'x': 1, 'y': 2}
scope = {}
print(exec('print(x + y)', scope, args))
print(scope.keys())
# 结果
'''
3
dict_keys(['__builtins__'])
'''
eval
eval()函数来执行一个字符串表达式,实现一个可以计算表达式的计算器,并返回表达式的值。eval()函数的语法:eval(expression[, globals[, locals]]),expression是表达式;globals是变量作用域,全局命名空间,如果被提供,这必须是一个字典对象;locals是变量作用域,局部变量命名空间,如果被提供,可以是任何映射对象。
python中查找变量的顺序是:局部 --> 全局 --> 内置
a = 1 # 当前变量
b = 2 # 当前变量
c = 3 # 当前变量
globals = {'a': 10, 'b': 20} # 全局变量
locals = {'b': 200, 'c': 300} # 局部变量
print(eval('a + b + c')) # 后两个参数省略,默认在当前作用域下,即a+b+c = 1+2+3 = 6
print(eval('a + b + c', globals, locals)) # 指定globals、locals参数,优先局部,再全局,最后当前作用域,即a+b+c = 10+200+300 = 510
# 结果
'''
6
510
'''