4.1 轻松看对象
1.面向对象
关于面向对象的解释:
https://www.jianshu.com/p/7a5b0043b035
如果你看完了上面的链接,也就会明白,我刚刚直接给你一个链接去理解面向对象,本身就是一个面向对象的思想。
我一步一步给你解释,这就是面向过程,而直接给你一个包含解释面向对象的链接(封装),这就是面向对象。
2.类(Class)
类就是将物品的特征抽象到一个类别里面。如,人类、鸟类都是一个种类,类里面包含了物品的特征,如人类的的特征有年龄、姓名、眼耳鼻口等等。
Python中定义类:如,创建人类,特征是有(True)名字、姓名和性别
class People(object):
Name = True
Age = True
Sex = True
人类的特征还有他们的行为,那么可以定义行为,如吃水果
class People(object):
Name = True
Age = True
Sex = True
def eatFruits(self,Fruit): """self表示的是某一个人类,是确定的物,相当Java的this"""
print("吃" + Fruit)
类就是像一张设计图,把一类东西的共同特征和行为设计保存起来。
3.对象
类是一张设计图,而设计图产出的物品就是对象。比如说,上帝创造了人类,以及人类的对象,亚当和夏娃。
class People(object):
Name = True
Age = True
Sex = True
def eatFruits(self,Fruit):
print("吃" + Fruit)
First_People = People() """上帝创造了第一个人类——第一个对象"""
First_People.Name = "Adam" """他的名字叫亚当"""
First_People.Age = 930 """他的年龄930岁"""
First_People.Sex = "Man" """他的性别为男"""
print(First_People) """第一个人类的编号"""
print(First_People.Name) """第一个人类的名字"""
print(First_People.Age) """第一个人类的年龄"""
print(First_People.Sex) """第一个人类的性别"""
结果:
<__main__.People object at 0x0000021A60B0E860>
Adam
930
Man
Second_People = People() """上帝创造了第二个人类——第二个对象"""
Second_People.Name = "Eve" """她的名字叫夏娃"""
Second_People.Age = 930 """她的年龄930岁"""
Second_People.Sex = "Woman" """她的性别为女"""
print(Second_People) """第二个人类的编号"""
print(Second_People.Name) """第二个人类的名字"""
print(Second_People.Age) """第二个人类的名字"""
print(Second_People.Sex) """第二个人类的名字"""
结果:
<__main__.People object at 0x0000021A60B28710>
Eve
930
Woman
"""亚当和夏娃偷吃苹果"""
First_People.eatFruits("apple")
Second_People.eatFruits("apple")
结果:
吃apple
吃apple
这就是对象的特征和行为。
4.魔法函数( __ FunctionName __ )
上面的代码中,我们是用对象名调用对象的特征,并且赋值,这样有时创建的对象多了,就比较麻烦,我们可以通过魔法函数,当每次创建对象时就可以帮他们起名字,这样就可以让代码更简洁。
魔法函数的格式
class People(object):
Name = True
Age = True
Sex = True
def __init__(self,Name,Age,Sex): """魔法函数的格式:两条下划线+函数名+两条下划线(参数)"""
self.Name = Name
self.Age = Age
self.Sex = Sex
print(Name,Age,Sex)
People1 = People("Adam",930,"Man")
People2 = People("Eve",930,"Woman")
People3 = People("小明",10,"Man")
结果:
Adam 930 Man
Eve 930 Woman
小明 10 Man
4.2 继承者们
1.子类
类还可以细分为子类。比如,人类包括了亚洲人、欧洲人、美洲人。
我们把人类叫作父类,把亚洲人、欧洲人、美洲人叫做子类。
子类拥有父类的东西(特性、行为),它们通过继承(Inheritance)来连接。
继承的格式
"""定义人类(父类)"""
class People(object):
Name = True
Age = True
Sex = True
"""定义亚洲人类(子类)"""
class Asian(People):
Etiquette = "鞠躬" """礼仪是鞠躬"""
"""定义欧洲人类(子类)"""
class European(People):
Etiquette = "握手"
"""定义美洲人类(子类)"""
class America(People):
Etiquette = "亲脸颊"
People1 = Asian() """创建亚洲人"""
People2 = European() """创建欧洲人"""
People3 = America() """创建美洲人"""
print(People1.Etiquette , "------" , People1.Name) """亚洲人拥有人类的特点"""
print(People2.Etiquette , "------" , People2.Name) """欧洲人拥有人类的特点"""
print(People3.Etiquette , "------" , People3.Name) """美洲人拥有人类的特点"""
结果:
鞠躬 ------ True
握手 ------ True
亲脸颊 ------ True
2.属性覆盖
在继承的过程中,子类可以增加父类没有的东西,还可以替换父类中已经存在的属性。比如说,人类可以吃东西,而亚洲人可以改写成吃粥。
"""定义人类(父类)"""
class People(object):
Name = True
Age = True
Sex = True
def eatFunction(self):
print("吃东西")
"""定义亚洲人类(子类)"""
class Asian(People):
Name = "亚洲人"
Etiquette = "鞠躬"
def eatFunction(self):
print("吃粥")
"""定义欧洲人类(子类)"""
class European(People):
Name = "欧洲人"
Etiquette = "握手"
def eatFunction(self):
print("吃面包")
"""定义美洲人类(子类)"""
class America(People):
Name = "美洲人"
Etiquette = "亲脸颊"
def eatFunction(self):
print("吃薯条")
People0 = People()
People1 = Asian()
People2 = European()
People3 = America()
print(People0.Name)
People0.eatFunction()
print()
print(People1.Name)
People1.eatFunction()
print()
print(People2.Name)
People2.eatFunction()
print()
print(People3.Name)
People3.eatFunction()
结果:
True
吃东西
亚洲人
吃粥
欧洲人
吃面包
美洲人
吃薯条
从上面例子可以看出,亚洲人类会调用自身定义的eatFunction()方法,而不是人类的eatFunction()。这就是父类中的同名属性(方法)被子类的同名属性(方法)覆盖(override)
但有时我们不能将父类中的行为去除,需要父类中的行为,这是我们可以在覆盖时利用super
关键字。super关键字可按照需要放在子类方法中的任意位置
class People(object):
Name = True
Age = True
Sex = True
def eatFunction(self):
print("吃东西")
class Asian(People):
Name = "亚洲人"
Etiquette = "鞠躬"
def eatFunction(self):
super().eatFunction() """"super关键字:super().属性或方法"""
print("吃什么")
print("吃粥")
People0 = People()
People1 = Asian()
print(People0.Name)
People0.eatFunction()
print()
print(People1.Name)
People1.eatFunction()
结果:
True
吃东西
亚洲人
吃东西
吃什么
吃粥
4.3 那些年,错过的对象
其实在之前学过的知识当中,已经触及过对象了,只不过这些对象已经是定义好在Python中的。如 列表list,元组tuple,字符串str,词典dict。
我们可以通过dir()、help()来查看它们的类。
如下
dir(list)
help(list)
当然我们也可以自己定义一个类,然后加入文档注释,查看类。如下
class People(object):
"""
这是一个人类
"""
Name = True
Age = True
Sex = True
def eatFunction(self):
print("吃东西")
1.列表对象
list中的方法
-
插入功能
1)在最后插入(append)
li = [1,2.2,3,3,"这是4",5]
print("插入前",li)
li.append("这是添加功能,只在最后添加")
print("插入后",li)
结果:
插入前 [1, 2.2, 3, 3, '这是4', 5]
插入后 [1, 2.2, 3, 3, '这是4', 5, '这是添加功能,只在最后添加']
2)在指定位置插入(insert)
li = [1,2,3,6,"这是4",5]
print("插入前",li)
li.insert(2,"这是插入功能,在指定位置后面插入")
print("插入后",li)
结果:
插入前 [1, 2, 3, 6, '这是4', 5]
插入后 [1, 2, '这是插入功能,在指定位置后面插入', 3, 6, '这是4', 5]
-
查找索引和计数功能
1)查找索引功能(index)
通过内容查找索引
li = [1,2,3,6,3,"这是4",5]
print(li)
print("查找第一个元素为3的索引",li.index(3))
结果:
[1, 2, 3, 6, 3 , '这是4', 5]
查找第一个元素为3的索引 2
2)计数功能(count)
li = [1,2,3,6,3,"这是4",5]
print(li)
print("查找一共有多少个3:",li.count(3))
结果:
[1, 2, 3, 6, 3, '这是4', 5]
查找一共有多少个3: 2
-
删除功能
1)去除列表最后一个元素,并返回该元素(pop)
li = [1,2,3,6,3,"这是4",5]
print("删除pop前",li)
li.pop()
print("删除pop后,删除掉最后一个元素",li)
结果:
删除pop前 [1, 2, 3, 6, 3, '这是4', 5]
删除pop后,删除掉最后一个元素 [1, 2, 3, 6, 3, '这是4']
2)去除列表第一个出现的元素(remove)
li = [1,2,3,6,3,"这是4",5]
print("删除remove前",li)
li.remove(3)
print("删除remove后,删除掉第一个元素3后",li)
li.remove(3)
print("删除remove后,删除掉第二个元素3后",li)
结果:
删除remove前 [1, 2, 3, 6, 3, '这是4', 5]
删除remove后,删除掉第一个元素3后 [1, 2, 6, 3, '这是4', 5]
删除remove后,删除掉第二个元素3后 [1, 2, 6, '这是4', 5]
3)清空列表(clear)
li = [1,2,3,6,3,"这是4",5]
print("清空列表前",li)
li.clear()
print("清空列表后",li)
结果:
清空列表前 [1, 2, 3, 6, 3, '这是4', 5]
清空列表后 []
-
其他操作
1)排序功能(sort)
注意:如果列表里面有字符串和数字,无法进行排序
li = [1,2,3,6,3,4,5]
print("排序之前",li)
li.sort()
print("排序之后",li)
结果:
排序之前 [1, 2, 3, 6, 3, 4, 5]
排序之后 [1, 2, 3, 3, 4, 5, 6]
"""按照某一排序标准排序,使用sort里面的key,
lambda是匿名函数,这里是按照字符串的索引为1的元素进行排序"""
li = ['xaz','bxz','cd']
print("排序之前",li)
li.sort(key = lambda x:x[1])
print("排序之后",li)
结果:
排序之前 ['xaz', 'bxz', 'cd']
排序之后 ['xaz', 'cd', 'bxz']
2)颠倒次序(reverse)
li = [1,3,2,'xaz','bd',9,10]
print("颠倒之前",li)
li.reverse()
print("颠倒之后",li)
结果:
颠倒之前 [1, 3, 2, 'xaz', 'bd', 9, 10]
颠倒之后 [10, 9, 'bd', 'xaz', 2, 3, 1]
"""更简便的颠倒"""
li = [1,3,2,6,4,10,9]
print("颠倒前",li)
print("颠倒后",li[::-1])
结果:
颠倒前 [1, 3, 2, 6, 4, 10, 9]
颠倒后 [9, 10, 4, 6, 2, 3, 1]
3)利用1)和2)可以进行逆序排序
li = [1,3,2,6,4,10,9]
print("未逆序前",li)
li.sort()
print("先排好序",li)
li.reverse()
print("再将排序好的颠倒,逆序完毕",li)
结果:
未逆序前 [1, 3, 2, 6, 4, 10, 9]
先排好序 [1, 2, 3, 4, 6, 9, 10]
再将排序好的颠倒,逆序完毕 [10, 9, 6, 4, 3, 2, 1]
"""更简易的逆序方式"""
li = [1,3,2,6,4,10,9]
print("逆序前",li)
li.sort()
print("进行排序后,进行颠倒",li[::-1])
结果:
逆序前 [1, 3, 2, 6, 4, 10, 9]
进行排序后,进行颠倒 [10, 9, 6, 4, 3, 2, 1]
2.元组与字符串对象
- 元组的操作
由于元组的数据固定,因此它的操作比较少,只有两个
tup = (1,3,4,4,3,2)
print(tup)
print('这是计数功能',tup.count(3))
print('这是按内容查找索引功能',tup.index(2))
结果:
(1, 3, 4, 4, 3, 2)
这是计数功能 2
这是按内容查找索引功能 5
-
字符串操作
字符串是特殊的元组,因此可以进行元组的操作,除此之外还有其他操作。
1)计数和查找功能
str1 = 'HelloWorld HelloWorld'
str2 = "World"
print("str1:",str1)
print("str2:",str2)
print("str2在str1中出现的次数",str1.count(str2))
print("str1.find: 从左开始,查找str2在str1中第一次出现的次数",str1.find(str2))
print("str1.rfind: 从右开始,查找str2在str1中第一次出现的次数",str1.rfind(str2))
print("str1.index: 从左开始,查找str2在str1中第一次出现的索引",str1.index(str2))
print("str1.rindex: 从右开始,查找str2在str1中第一次出现的索引",str1.rindex(str2))
结果:
str1: HelloWorld HelloWorld
str2: World
str2在str1中出现的次数 2
str1.find从左开始,查找str2在str1中第一次出现的次数 5
str1.rfind从右开始,查找str2在str1中第一次出现的次数 16
str1.index从左开始,查找str2在str1中第一次出现的索引 5
str1.rindex从右开始,查找str2在str1中第一次出现的索引 16
2)判断功能
str1 = 'HelloWorld HelloWorld'
print("str1:",str1)
print(".isalnum()如果所有字符都是数字或字母则放回True:",str1.isalnum())
print(".isalpha()如果所有字符都是字母则放回True:",str1.isalpha())
print(".isdigit()如果所有字符都是数字则放回True:",str1.isdigit())
print(".istitle()如果所有词都是首字母大写则放回True:",str1.istitle())
print(".isspace()如果所有字符都是空格则放回True:",str1.isspace())
print(".islower()如果所有字符都是小写字母则放回True:",str1.islower())
print(".isupper()如果所有字符都是大写字母则放回True:",str1.isupper())
结果:
str1: HelloWorld HelloWorld
.isalnum()如果所有字符都是数字或字母则放回True: False
.isalpha()如果所有字符都是字母则放回True: False
.isdigit()如果所有字符都是数字则放回True: False
.istitle()如果所有词都是首字母大写则放回True: False
.isspace()如果所有字符都是空格则放回True: False
.islower()如果所有字符都是小写字母则放回True: False
.isupper()如果所有字符都是大写字母则放回True: False
3)其他功能
"""分割功能"""
str1 = 'HelloWorld HelloWorld'
print("str1分割前:",str1)
print("默认以空格为分隔符,str1分割后:",str1.split())
str2 = 'HelloWorld,HelloWorld'
print("str2分割前:",str2)
print("以,为分隔符,str2分割后:",str2.split(','))
结果:
str1分割前: HelloWorld HelloWorld
默认以空格为分隔符,str1分割后: ['HelloWorld', 'HelloWorld']
str2分割前: HelloWorld,HelloWorld
以,为分隔符,str2分割后: ['HelloWorld', 'HelloWorld']
"""替换功能"""
"""将旧字符串替换为新字符串"""
str1 = 'HelloWorld1 HelloWorld2'
print('替换前',str1)
print('替换后',str1.replace('World1','Python1'))
结果:
替换前 HelloWorld1 HelloWorld2
替换后 HelloPython1 HelloWorld2
"""将字符串第一个字母替换为大写"""
str1 = 'helloWorld1 helloWorld2'
print('替换前',str1)
print('替换后',str1.capitalize())
结果:
替换前 helloWorld1 helloWorld2
替换后 Helloworld1 helloworld2
"""将字符串的每个单词的首字母大写,以空格分开"""
str1 = 'helloWorld1 helloWorld2'
print('替换前',str1)
print('替换后',str1.title())
结果:
替换前 helloWorld1 helloWorld2
替换后 Helloworld1 Helloworld2
"""将字符串字母全部改为小写"""
str1 = 'HelloWorld1 HELLOWORLD2'
print('替换前',str1)
print('替换后',str1.lower())
结果:
替换前 HelloWorld1 HELLOWORLD2
替换后 helloworld1 helloworld2
"""将字符串字母全部改为大写"""
str1 = 'HelloWorld1 HelloWorld2'
print('替换前',str1)
print('替换后',str1.upper())
结果:
替换前 HelloWorld1 HelloWorld2
替换后 HELLOWORLD1 HELLOWORLD2
"""将字母大小写互换"""
str1 = 'HelloWorld1 HelloWorld2'
print('替换前',str1)
print('替换后',str1.swapcase())
结果:
替换前 HelloWorld1 HelloWorld2
替换后 hELLOwORLD1 hELLOwORLD2
"""去除字符串两边空格"""
str1 = ' HelloWorld1 HelloWorld2 '
print("去除两边空格前:",str1)
print("去除两边空格后:",str1.strip())
结果:
去除两边空格前: HelloWorld1 HelloWorld2
去除两边空格后: HelloWorld1 HelloWorld2
"""以str为分隔符,将s中的元素合并成字符串"""
li = ['P','y','t','h','o','n']
str1 = ' '.join(li) """以空格为分隔符"""
print(str1)
str1 = '-'.join(li) """以-为分隔符"""
print(str1)
str1 = ','.join(li) """以,为分隔符"""
print(str1)
str1 = '*'.join(li) """以*为分隔符"""
print(str1)
结果:
P y t h o n
P-y-t-h-o-n
P,y,t,h,o,n
P*y*t*h*o*n
3.词典对象
- 遍历功能
1)遍历每一个键keys()方法
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('字典:',di)
print("遍历字典的每一个键keys()方法")
for k in di.keys():
print(k,end = ' ')
结果:
字典: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
遍历字典的每一个键keys()方法
剑魂 狂战 阿修罗 鬼泣
2)遍历每一个值values()方法
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('字典:',di)
print("遍历字典的每一个值values()方法")
for v in di.values():
print(v,end = ' ')
结果:
字典: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
遍历字典的每一个值values()方法
93 97 95 94
3)遍历每一个键和每一个值items()方法
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('字典:',di)
print("遍历字典的每一个键和值items()方法")
for k,v in di.items():
print(k,v,end = ' ')
结果:
字典: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
遍历字典的每一个键和值items()方法
剑魂 93 狂战 97 阿修罗 95 鬼泣 94
4)遍历每一个键值对items()方法
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('字典:',di)
print("遍历字典的每一个键值对items()方法")
for kv in di.items():
print(kv,end = ' ')
结果:
字典: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
遍历字典的每一个键值对items()方法
('剑魂', 93) ('狂战', 97) ('阿修罗', 95) ('鬼泣', 94)
- 删除功能
1)清空功能
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('清空字典前:',di)
di.clear()
print('清空字典后:',di)
结果:
清空字典前: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
清空字典后: {}
2)删除功能
"""删除最后一个键值对,并且放回该键值对popitem()"""
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('删除前:',di)
print("删除最后一个键值对,并返回该键值对",di.popitem())
print('删除后',di)
结果:
删除前: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
删除最后一个键值对,并返回该键值对 ('鬼泣', 94)
删除后 {'剑魂': 93, '狂战': 97, '阿修罗': 95}
"""按照键删除键值对,并返回该键对应的值pop()"""
di = {"剑魂":93,"狂战":97,"阿修罗":95,"鬼泣":94}
print('删除前:',di)
print('删除并返回对应的值',di.pop("剑魂"))
print('删除后',di)
结果:
删除前: {'剑魂': 93, '狂战': 97, '阿修罗': 95, '鬼泣': 94}
删除并返回对应的值 93
删除后 {'狂战': 97, '阿修罗': 95, '鬼泣': 94}
4.4 意想不到的对象
1.循环对象
循环对象:该对象包含了一个__ next __()方法,该方法用来生成下一次循环的结果。相当于一个指针,指向下一个元素。每次循环时,都会调用该方法,直到抛出StopIteration异常。
如果学过Java的同学,可能知道,这就是Java中的迭代器Iterator,是专门用于遍历元素的一个工具。
Python中内置函数iter()能把一个容器型对象(元组、字典、字符串、字典)转变为循环对象(迭代器)
Iterator = iter([3,4,1,2,7,"Python"])
print(Iterator.__next__())
print(Iterator.__next__())
print(Iterator.__next__())
print(Iterator.__next__())
print(Iterator.__next__())
print(Iterator.__next__())
结果:
3
4
1
2
7
Python
我们可以利用循环对象来改写上面的代码
for it in iter([3,4,1,2,7,"Python"]):
print(it)
结果:
3
4
1
2
7
Python
我们也可能尝试着自定义循环对象,这时我们需要生成器(generator)。
生成器的格式与定义函数相似,只是在return的地方改为yield。
生成器中可以有多个yield。当生成器遇见一个yield时,就暂停运行生成器,返回yield后面的值。当再次调用生成器时,会从暂停的地方继续运行,知道遇见下一个yield。
定义生成器
def gen():
a = 100
yield a
a = a*8
yield a
yield 1000
for i in gen():
print(i)
结果:
100
800
1000
生成器的好处
def gen():
i = 0
while i < 10000000:
i = i + 1
yield i
"""
这个生成器能产生多个元素,如果实现创建序列保存10000000个元素,
那么会占用很大的空间,再进行循环,造成极大浪费。
而生成器会产生10000000个元素,但是在循环结束后就会释放,提高了利用空间。
"""
Python中的range()函数返回的就是一个循环对象。
2.函数对象
函数(方法)也是一种对象。任何一个有__ call__()特殊方法的对象都被当作是方法,即对象就是一个函数,对象就是一个方法。
如,
class ClassDemo(object):
def __call__(self,x):
print("我是__call__()方法,调用ClassDemo类的对象就能调用我")
return x * 2
Class1 = ClassDemo()
print(Class1(3))
结果:
我是__call__()方法,调用ClassDemo类的对象就能调用我
6
Class1作为ClassDemo类的一个对象,当被调用时,Class1执行call()方法。
3.模块对象
模块也是对象。比如引入模块time。
import time
dir(time)
可以看见time对象里面有很多个属性和方法可以调用,比如sleep()。
之前,我们引入函数的第二种方式,如
引入time对象的sleep()属性
from time import sleep
引入time对象的所有属性
from time import *
这种引入方式实际上就是,引入模块对象的属性。
在引入模块时,我们还可以给模块换个名字,对模块名进行缩写。
import time as t
t.sleep(10) """程序停止10s"""
要注意,如果直接从模块导入所有函数,当导入多个模块时,很可能发生属性名冲突,而导致错误。比如mytime模块里面也有一个sleep()函数时
import time
import mytime
sleep() """我们不清楚这个sleep()是来自time模块还是mytime模块"""
--------------------------------------------------------------------------------
对此我们可以这样解决
import time as t
import mytime as mt
t.sleep()
mt.sleep()
上面就是通过对象名区分出了不同的属性。
如果有多个模块对象,它们的功能相似,我们可以将它们放在一个文件夹之中,构成一个模块包。比如放在this_dir种,需要时调用即可,比如文件夹中有time模块
import this_dir.time