类和对象
python是一个面向对象的语言,其中,几乎所有的东西都有自己的属性和方法,那就像我们可以自定义函数一样,我们可以自己定义出一种东西,而这个东西的属性和方法都是我们自己定义的。
而类 (Class) 其实相当于是我们创建对象的“蓝图”,也可以这样说,类其实是我们创建一个对象的函数,我们可以利用这个函数来创建一个对象。
创建类
我们创建一个类,也就是创建一个可以构造一类对象的构造函数:
class aml():
x = 5
此时我们就创建一个名为 aml 的类,里面有一个方法 x 。这个 x 的方法的意思是 如果我用了这个方法,那么我的这个对象的值就是 5 。
创建对象
在我们创建了 我们自定义的类 之后,我们就可以用问你自定义的类来去创建对象了:
class aml():
x = 5
p1 = aml() # 此时的p1 就是我们创建的一个对象
print(p1.x) #打印p1 的时候,我们使用 这个对象里面的 x 这个方法
输出: 5
__init__() 函数给属性赋值
上述的创建是最简单的类和对象的创建,我们要更好的使用类和对象,就要借助这种函数,这个函数是在类里面自定义的一个函数,这个函数可以帮我们实现更多的功能。我们之前是在这个类里面实现了这个类所能执行的方法,而这个函数可以帮我们实现这个类的属性。
每一个类都有一个__init__() 函数,这个函数在这个类启动时候执行,将值赋值给对象; 也就是说每一次在创建这个类的对象的时候,都会自动调用这个类里面的这个函数。
class Person():
def __init__(slef,name,age):
slef.name = name
slef.age = age
p1 = Person('bili','16')
print(p1.name) #bili
print(p1.age) #16
我们可以用这__init__函数来把我们这个对象的属性进行赋值。其中的 slef 也就是这个对象的名称。
创建方法
我们还可以在这个类里面,创建属于这个类的方法,这个方法其实就是对应这个类的 函数。
class Person():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
p1 = Person('bili','18')
p1.Func() #执行 p1对象的类中的 Func() 这个方法
输出:
My name is bili ; my age is 18
self 参数是对类的当前实例的引用,用于访问属于该类的变量。
我们也可以不用这个self 来表示这个对象的名称,这对象的名称是在函数参数列表里首元素位置,我们可以用任意的名称来表示,因为这是函数的参数嘛。但是我们在函数中,要用到这个对象的名字的时候,必须是这个函数参数的首个参数。这个首个参数就是对象的名称。
对象的属性的操作
修改对象属性
当我们创建了一个对象之后,可以像下面一个修改这个对象的属性:
class Person():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
p1 = Person('bili','18')
p1.age = 15
p1.Func() #执行 p1对象的类中的 Func() 这个方法
输出:
My name is bili ; my age is 15
删除对象的属性
del p1.age
这个时候 p1 中的age 这个属性就被删除掉了。
删除对象
我们这个 del 操作不仅仅可以删除对象里面属性,还可以删除对象:
del p1
pass语句
我们之前也说过,这个类的定义,就像是在定义一个创建对象的函数一样,那么同样的,这个类的定义中的代码块也是不能为空的,为空会报错:
class Person():
如果这个类定义里面是空的,我们需要在这个类定义的代码块里面输入 pass语句:
class Person():
pass
python的继承
所谓继承就是,我们在一个类中使用继承另一个类之后,另一个类的方法和属性我们就可以使用了。
父类是继承的类,也称为基类。
子类是从另一个类继承的类,也称为派生类。
任何一个类都可以是父类,那么父类的创建就和类创建一样。
创建子类
要实现继承,主要还是子类的创建;当我们在创建一个类之后,像在此基础上,用其他类的属性和方法,那么就只需要在创建子类的时候,用父类作为这个子类的参数:
class Father():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
class son(Father):
pass
p1 = son('bili','18')
p1.Func() #执行 p1对象的类中的 Func() 这个方法
输出:
My name is bili ; my age is 18
我们发现当我们使用 子类-son来创建 p1 这个对象之后,使用了 父类-Father 当中的属性和对象操作,仍然适用。
子类__init__函数注意事项
我们上述对于子类的创建, 子类中的内容是用 pass 跳过的,当我们需要用__init__函数定义子类的属性的时候,需要注意的是:
我们在子类中使用__init__函数定义属性之后,子类的__init__函数创建的子类,会覆盖引用的父类的__init__函数创建的属性;也就是说,我们这个时候,父类的属性将不在适用。
class Father():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
class son(Father):
def __init__(self,name1,age1):
self.name1 = name1
self.age1 = age1
p1 = son('bili','18')
p1.Func() #执行 p1对象的类中的 Func() 这个方法
我们发现此时father里属性不在适用。
如果我们想在 子类 定义 自己的属性之后,同时继承父类的属性,那么就需要在后面添加对父类__init__函数的调用:
class Father():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
class son(Father):
def __init__(self,name1,age1):
self.name1 = name1
self.age1 = age1
Father.__init__(self,name1,age1)
p1 = son('bili','18')
p1.Func() #执行 p1对象的类中的 Func() 这个方法
输出:
My name is bili ; my age is 18
Father.__init__(self,name1,age1) 的里面就是把 子类的 中的 self,name1,age1 这些参数都传给我的Father中的__init__函数里,在进行Father类里面 的属性定义。
使用 super() 函数
我们上述是使用,在子类 中 定义 自己的属性的时候,在后面添加 父类 属性的 引用。除了这个方式之外,在python中还有一个函数--- super()函数,这个函数使用之后,可以是 子类 继承 父类的方法和属性。
class Father():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
class son(Father):
def __init__(self,name1,age1):
self.name1 = name1
self.age1 = age1
super().__init__(name1,age1)
p1 = son('bili','18')
p1.Func() #执行 p1对象的类中的 Func() 这个方法
输出:
My name is bili ; my age is 18
我们看上述的倒数第三行代码,我们这样子使用这个 super() 函数之后就可以达到 这个句代码相同的功能--- Father.__init__(self,name1,age1) ----。我们super后面__init__ 函数里的参数,不用传 对象的名称,只需要把 父类 中的属性传入即可,这就把父类里面的属性拷贝过来。
在使用super()函数的时候不必在 加上父类的名字,它将自动的从其父类 中 继承方法和属性。
添加属性
在里面son 类里面 新加一个Myyear的属性:
class Father():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
class son(Father):
def __init__(self,name1,age1):
self.name1 = name1
self.age1 = age1
Father.__init__(self,name1,age1)
self.Myyear = 2022
p1 = son('bili','18')
print(p1.Myyear) #输出: 2022
如果再次当中我们的 2022 应该是一个变量,而且在创建 p1 对象的时候,应该传入这个参数:
class Father():
def __init__(Myself,name,age):
Myself.name = name
Myself.age = age
def Func(Youself):
print(f'My name is {Youself.name} ; my age is {Youself.age}')
class son(Father):
def __init__(self,name1,age1,year):
self.name1 = name1
self.age1 = age1
Father.__init__(self,name1,age1)
self.Myyear = year
p1 = son('bili','18','2022')
print(p1.Myyear) #输出: 2022
在定义的 类函数之外也可以添加属性:
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
Per.year = 2022 #在Per 类里面创建一个 year 属性
p1 = Per('li si','18')
p1.Func('zhang san','22') # 输出: My name is zhang san ; My age is 22
print(p1.year) # 输出: 2022
这是为类创建 属性,我们也可以 单独为一个对象创建一个新的属性:
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
p1 = Per('li si','18')
p1.year = 2022
print(p1.year) # 输出: 2022
我们这一次操作就是在 p1 这个对象中插入 year 这个属性,注意是单独为 p1 这个对象插入属性,其他同类对象是不可用的:
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
p1 = Per('li si','18')
p1.year = 2022
print(p1.year) # 输出: 2022
p2 = Per('zhang san','20')
print(p2.year)
delattr()方法 和 setattr()方法
除此之外,我们还可以使用 delattr 方法来删除 某个对象中的某个属性,格式:
delattr(对象名,'要删除的属性名')
需要注意的是,属性名是一个字符串,要用字符串的规则 括起来,具体示例:
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
p1 = Per('li si','18')
p1.year = 2022
delattr(p1,'name')
print(p1,name)
这个时候 p1 对象中的name 属性已经不在了,我们在使用这个属性就会报错:
setattr 方法 可以帮我们 在某一个 对象里面创建一个属性,他的语法规则是:
setattr(对象名,'需要创建的属性名','属性需要赋的值')
具体示例:
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
p1 = Per('li si','18')
p1.year = 2022
delattr(p1,'name')
# hasattr 为判断某个对象中 的某个 属性是否存在的函数
# 存在就返回 True 不存在就返回 false
print(hasattr(p1, "name")) #False 说明这个时候 p1 里面没有 name 这个属性
setattr(p1,'name','wang wu')
print(hasattr(p1, "name")) #True 说明此时 p1 里面有了 name 这个属性
MethodType 方法 给对象添加方法
MethodType 方法的使用需要 import 这个MethodType。MethodType 的格式:
MethodType(方法名,对象名)
具体示例;
from types import MethodType
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
p1 = Per('li si','18')
p1.Func = MethodType(Func,p1)
p1.Func('zhangsan','18') #My name is zhangsan ; My age is 18
我们可以看到,此时在 Per 类之外定义的 Func 函数(方法) , 已经可以被我们的 p1 所调用了。
迭代器
迭代器是一种特殊的对象,它可以记住每一次迭代之后,所遍历的位置,下一次迭代的时候就从这个位置开始下个位置进行迭代,直到迭代完这里面的数据为止。也就是说,迭代器只会往前不会后退。
可迭代对象
我们把可以从 for循环这类语句中中 读取一个元素的给我们使用的 对象,称为可迭代对象。
我们可以使用 isinstance 方法来帮助我们判断一个对象是否为 可迭代对象,这个方法使用来判断一个对象是否是某个类型的方法,如果是就返回 True ; 不是就返回 False,语法规则:
isinstance( 对象名 , 类型名 )
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
class son():
def __init__(self,name,age):
self.name = name
self,age = age
p1 = Per('li si','18')
p2 = son('wangwu','20')
print(isinstance(p1,Per)) #True
print(isinstance(p2,Per)) #False
print(isinstance(p1,son)) #False
print(isinstance(p2,son)) #True
我们可以用这样的方式来判断一个对象是不是 可迭代对象:
注:Iterable 对象 需要 引用 :from collections.abc import Iterable 或者 from collections import Iterable
from collections.abc import Iterable
class Per():
def __init__(self,name,age):
self.name = name
self.age = age
def Func(self,name,age):
print(f'My name is {name} ; My age is {age}')
class son():
def __init__(self,name,age):
self.name = name
self,age = age
p1 = Per('li si','18')
p2 = son('wangwu','20')
print(isinstance(p1,Iterable)) #Fasle
print(isinstance(p2,Iterable)) #Fasle
我们发现我们创建的两个类的对象 都不是可迭代对象。
迭代器 VS 可迭代对象(Iterable)
在python中 列表、元组、字典和集合这些都是可迭代的对象。它们是可迭代的容器,我们可以从中获取迭代器(Iterator),
这些可迭代对象里面都有一个 可以获取这可迭代对象的迭代器的方法 iter()函数:
list = ('hello','world','lisi')
myit = iter(list)
此时我们就用 iter 方法把 list 的这可迭代对象的 迭代器 取出来 给到 myit 中了,此时我们myit 就是list的 迭代器,此时我们打印 myit 类型发现 myit 的类型是迭代器 这种特殊类型:
print(type(myit))
输出:
print(type(myit))
此时我们可以利用这个 myit 迭代器 在用 next() 函数 来输出 list 这里面的值:
list = ('hello','world','lisi')
myit = iter(list)
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
输出:
hello
world
lisi
当我们的next() 访问到 myit 的最后一个数据之后一个数据的时候 ,他会提示 抛出异常 ,来提醒我们这个 myit 里的数据访问完了。
list = ('hello','world','lisi')
myit = iter(list)
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
同样的,只要是可迭代对象里面获取出来的 迭代器都是可以使用 next ()函数的:
list = 'abcdefg'
myit = iter(list)
for i in range(0,7):
print(next(myit))
: 输出结果
迭代器也可以作为可迭代对象,所以我们可以用for循环,把他作为一个可迭代对象来回使用:
list = ('hello','world','lisi')
myit = iter(list)
for i in myit:
print(i)
输出:
hello
world
lisi
当我们直接用for遍历打样字符串 的时候 ,for循环其实是 帮我们创建了一个 迭代器 ,然后每一次循环使用 next()函数就行访问操作。
mystr = "banana"
for x in mystr:
print(x)
创建迭代器
我们之前说过迭代器其实就是一种对象,那么我们如何创建一个迭代器?
要把对象/类创建为迭代器,必须为对象实现 __iter__()
和 __next__()
方法,
__iter__() 的实现和 __init__ 函数试下类似 ,我们可以在这个函数里实现一些操作,但是必须一直返回迭代器本身。
__net__() 同样允许我们执行一些操作(初始化等等),但是必须指向这个列表里面下一个项目。
例:我们实现一个 数字的迭代器,从1 开始 ,每个序列都增加1(即:返回 1 2 3 4 5 6 等等)
class Per():
def __iter__(self):
self.num = 1
return self
def __next__(self):
num1 = self.num
self.num += 1
return num1
p1 = Per()
mytier = iter(p1)
print(next(p1))
print(next(p1))
print(next(p1))
print(next(p1))
print(next(p1))
print(next(p1))
如此我们就打印了 1~6:
StopIteration
我们发现,上面我打印 1~6 有点憨憨的,那么像之前我们用过 for 循环来 结合 迭代器来打印过 某个列表里面的内容,那么我们的这个 自定义的迭代器能不能用for循环呢?
答案是 yes ,但是会出现一些问题:
class Per():
def __iter__(self):
self.num = 1
return self
def __next__(self):
num1 = self.num
self.num += 1
return num1
p1 = Per()
mytier = iter(p1)
for i in mytier:
print(i)
我们发现这个程序无休止的循环 ~~~~,这是因为我们没有给他的循环设置条件,而这个条件不光光可以再循环里面设置,还可以在我们 定义的 迭代器 中实现。
class Per():
def __iter__(self):
self.num = 1
return self
def __next__(self):
if self.num <= 5:
num1 = self.num
self.num += 1
return num1
else:
raise StopIteration
p1 = Per()
mytier = iter(p1)
for i in mytier:
print(i)
这个当中 的 __next__() 中,我们加了一个 if 条件判断 就限制这个迭代器只能迭代到 5 ,那么如果超出 5 了就是 else 里面语句:
如果你有足够的 next()
语句,或者在 for 循环中使用,则上面的例子将永远进行下去。
为了防止迭代永远进行,我们可以使用 StopIteration
语句。
在 __next__()
方法中,如果迭代完成指定的次数,我们可以添加一个终止条件来引发错误