0%

第六周-面向对象、函数高阶用法

多态

python的多态与java的多态类似。比如一种常见的使用形式就是在函数传参的时候传递的可以是父类和继承该父类的多种子类。然而python比java更灵活

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
定义:
多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

例如:
序列有多种形态:字符串,列表,元祖
动物有多种形态:人,猪,狗

多态和多态性的区别:
多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)
多态性:一种调用方式,不同的执行效果(多态性)

"""
面向对象的三大特征:封装,继承,多态

封装:又称为信息的隐藏,类的实现和使用时分开的,类提供了外部访问的方法,调用者不需要关注
类里面的具体实现,会调用即可

生活中封装:买手机会用就可以

继承:一个类继承另外一个类,被继承的类称为父类或者基类,继承的类称为子类或者派生类,
子类可以共享父类里面受保护,公有属性和方法,子类不能共享父类私有属性和方法
继承可以减少代码的书写,提高代码的可维护性

多态:同一种事物有多种形态
多态性:同一种调用方式,返回不同的结果
多态的前提:继承和重写
"""
#多态:一种事物有多种表现形式
#定义一个父类
class Animal(object):
#定义一个普通方法
def sayHello(self):
pass

#定义一个子类Person,继承父类Animal
class Person(Animal):
#重写父类同名的方法
def sayHello(self):
print('hello,i am Person')

#定义一个子类Pig,继承父类Animal
class Pig(Animal):
#重写父类同名的方法
def sayHello(self):
print('aoao,i am Pig')

#定义一个子类Dog,继承父类Animal
class Dog(Animal):
#重写父类同名的方法
def sayHello(self):
print('wangwang,i am Dog')

#实例化不同子类创建对象
Per = Person()
Pi = Pig()
Do = Dog()
# Per.sayHello()
# Pi.sayHello()
# Do.sayHello()

#多态性:同一种调用方式,返回不同的结果
def func(o): #python是动态语言,o是多态性的体现,这里不需要指定类型,参数的类型由调用者传的值决定
o.sayHello()

func(Per)
func(Pi)
func(Do)

#多态的好处
class Cat(Animal): #继承父类Animal重新定义子类Cat
def sayHello(self):
print('mimi,i am Cat')

#创建一个Cat的对象ca
ca = Cat()
func(ca)

"""
多态的好处:
1.提高代码在外部调用灵活性
2.提高代码的扩展性
"""

类属性和实例属性

类属性

定义:在类中定义的属性

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
概述:
在类中定义的属性(公有和私有)

#定义一个人类,设置姓名和年龄属性

class Person(object):
name = 'xiaoming' #公有类属性
__age = 12 #私有类属性

#创建Person类的对象p
p = Person()
print(p.name) #实例对象访问类的公有属性
print(Person.name) #类对象访问类的公有属性

print(p.__age) #实例对象访问类的私有属性 not ok
print(Person.__age) ##类对象访问类的私有属性 not ok

实例属性

定义:定义在init初始化方法中的属性

举个例子,什么是实例属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#定义一个人类,设置姓名,年龄和地址等属性

class Person(object):
address = '上海市' #类属性

#定义初始化方法
def __init__(self,name,age):
self.name = name #实例属性
self.age = age

#创建Person类的对象pe
pe = Person('张三',30)
# print(pe.address) #通过实例对象访问类属性
# print(pe.name) #通过实例对象访问实例属性
# print(pe.age)

print(Person.address) #类在定义的时候已经产生了,类属性直接属于类
print(Person.name) #当实例化类创建对象,对属性赋值 实例属性才会产生内存里面 类访问不到实例属性
print(Person.age)

实例属性和类属性的关系:同名的情况下,实例属性会覆盖类属性

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#定义一个人类
class Person(object):
country = 'china' #类属性

#定义初始化方法
def __init__(self):
self.country = '上海市' #实例属性

#创建Person类的对象p
p = Person()
print(p.country) #通过实例对象访问属性 输出“上海市”
print(Person.country) #类对象访问属性 输出“china”
#通过实例属性修改类属性的值
p.country = 'chinese' #实例属性会屏蔽类属性
print(p.country) # 输出“chinese”
print(Person.country) # 输出“china”

del p.country #删除实例对象
print()
print(p.country) # 输出“china”,是类对象,不是实例对象
print(Person.country) # 输出“china”

#类里面定义同名的实例属性和类属性,实例对象修改类属性,实例属性会屏蔽同名类属性
#实例属性优先级高于类属性

静态方法和类方法

类方法

定义

概述: 类对象所拥有的方法,需要使用到修饰器 @classmethod---->类方法 对于类方法,第一个参数必须是类对象,一般以cls表示作为第一个参数(当然可以用其他的名字,但是不建议修改)

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 定义一个人类

class Person(object):
country = 'china' # 类属性

@classmethod
def getCountry(cls):
return cls.country

@classmethod
def setCountry(cls, country):
cls.country = country


# 创建Person对象
p = Person()
print(p.getCountry()) # 通过实例对象访问类方法 输出“china”
print(Person.getCountry()) # 通过类对象访问类方法 输出“china”

p.setCountry('chinese')
print(p.getCountry()) # 输出"chinese"
print(Person.getCountry()) # 输出“chinese”

# 总结:类方法可以修改类属性

静态方法

定义:通过修饰器@staticmethod来进行修饰,不需要传参数

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
概述:
需要通过修饰器@staticmethod来进行修饰,不需要传参数

#定义一个人类
class Person(object):
country = 'china' #类属性

@staticmethod
def getCountry():
return Person.country

#创建Person类的对象
p = Person()
print(p.getCountry()) #通过实例对象访问静态方法

总结

类方法:声明方法之前,需要使用到修饰器 @classmethod,里面第一个参数类对象cls,类对象访问的是类属性或者类方法 实例方法:隐含传递的参数是self,对象本身,self访问的可能是实例属性,也有可能是类属性,类方法,静态方法 静态方法:声明方法之前,需要使用到修饰器@staticmethod,不需要加任何参数,访问的是类属性的引用,只能通过类对象调用

__slots__

定义:限制实例属性

语法格式:slots = ('属性1','属性2')

__slots__属性限制添加属性只对当前类的实例对象起作用,对类属性,继承的子类实例对象不起作用的

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
动态语言:可以在运行的过程中,修改代码
静态语言:编译时已经确定的代码,运行的时候不能修改

如果我们想要限制实例属性?
允许对Person实例中添加name和age属性,
python允许定义class的时候,定义一个特殊的变量---->__slots__,限制class能够添加的属性

语法格式:__slots__ = ('属性1','属性2')

#定义一个人类,只允许添加姓名和年龄属性

class Student(object):
__slots__ = ('name','sex') #限制当前类添加的属性

#通过Student类创建对象stu
stu = Student()
#往对象里面添加属性
stu.name = '张三'
stu.sex = '男'
print(stu.name)
print(stu.sex)
#增加一个新的属性
# stu.weight = '80kg' #报错,类中限制添加属性没有weight
# print(stu.weight)
Student.weight = '50kg' # 添加类属性
print(stu.weight)

#定义一个子类demo,继承Student
class Demo(Student):
pass
d = Demo()
d.height = '180'
print(d.height)

"""
注意:__slots__属性限制添加属性只对当前类的实例对象起作用,对类属性,继承的子类实例对象不起作用的
"""

@property

私有属性添加getter和setter方法

python中和java类似的是私有属性不能直接修改,需要调用专门的方法才能修改;但python相对于java做出了优化,通过property函数创建一个特性(property),将 getMoney 方法作为获取属性值的方法,setMoney 方法作为设置属性值的方法。这样就可以像访问普通属性一样来访问 Money 类中的 money 属性

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#定义一个money类,设置一个私有的__money属性

class Money(object):
#定义一个初始化方法
def __init__(self):
self.__money = 0

#定义对属性设置的方法
def setMoney(self,value):
if isinstance(value,int) or isinstance(value,float):
self.__money = value
else:
print('Error:金额只能是整形或者浮点型')

#定义方法获取属性值
def getMoney(self):
return self.__money

#添加实例属性
money = property(getMoney,setMoney)

#通过Money类创建对象mo
mo = Money()
# print(mo.__money) #实例对象不能访问类的私有属性
mo.setMoney(100)
print(mo.getMoney()) # 输出100

# 下面这两行代码看似是直接修改了对象的私有属性,实际上是先调用了getMoney和setMoney方法
mo.money = 500
print(mo.money) # 输出500

使用property取代getter和setter方法

取代set/get------》修饰器-----》@property @property--->属性函数,可以对属性赋值时候做必要的检查,并保证代码的清晰简短 作用: 1.将方法转化为只读 2.重新实现一个属性的设置和读取方法,可做边界判定

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Money(object):
#定义初始化方法
def __init__(self):
self.__money = 0

@property
def money(self): #相当于获取元素值方法
return self.__money

@money.setter #money是上面取值的方法名 赋值的方法
# @money.setter是一个装饰器,用于指定一个方法作为属性的设置方法
def money(self,value):
if isinstance(value,int) or isinstance(value,float):
self.__money = value
else:
print('Error:不是整形也不是浮点型')
# 上面两个方法同名,第一个用来获取元素,第二个用来设置元素的值,然后在外界看起来虽然是私有属性的money和实例属性并无区别
#通过Money创建对象m
m = Money()
print(m.money)
m.money = 16888
print(m.money)

发送邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#导入邮件库
import smtplib
#导入邮箱文本
from email.mime.text import MIMEText

#设置邮箱服务器 qq/126/163/gmail/yahoo/阿里云
SMTPServer = 'smtp.163.com'
#设置发送邮箱的地址
sender = 'ztb0016@163.com'
#设置发送邮箱的通行码,不是密码
password = 'GTTULMLHIKOZSXIZ'


#设置发送的内容
message = '你是一个好人123333...'
#转换成人能够看懂的格式
msg = MIMEText(message)
#设置发送邮件的主题
msg['subject'] = '来自一位帅哥的表白33333'
#发送者
msg['from'] = sender

#设置邮箱服务器, 25表示的是端口
emailServer = smtplib.SMTP(SMTPServer,25)
#登录邮箱
emailServer.login(sender,password)
#发送邮件的内容
emailServer.sendmail(sender,['piolet0016@gmail.com'],msg.as_string())
#关闭邮箱
emailServer.quit()

用列表模拟栈

append模拟入栈

pop模拟出栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
"""
栈--->有名堆栈
原理:先进后出

装子弹
"""
#使用列表模拟堆栈
#入栈
# stack = []
# stack.append('A')
# stack.append('B')
# stack.append('C')
# print(stack)
#
# #出栈
# stack.pop()
# print(stack)
import os
def getAllFileDir(path):
stack = []
#入栈
stack.append(path)
#处理栈,当栈为空的时候结束操作
while len(stack) != 0:
#出栈
outDir = stack.pop()
#获取当前目录所有文件
filelist = os.listdir(outDir)
#判断哪些是目录,继续入栈,如果是文件直接打印
for fileName in filelist:
#判断文件是否是路径(用绝对路径)
fileAbsPath = os.path.join(outDir,fileName)
if os.path.isdir(fileAbsPath):
print('目录:',fileName)
#入栈
stack.append(fileAbsPath)
else:
print('文本文件:',fileName)
#调用函数
getAllFileDir('C:\python课程大纲\python课程大纲')

专门模拟队列的

定义一个队列

1
2
import collections
queue = collections.deque()

入队

1
queue.append(path)

出队

1
outDir = queus.popLeft()

具体事例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
"""
队列原理:先进先出
#银行办理业务排队

collections
deque() 创建一个队列
append() 队列添加元素
popLeft() 从队列里面删除元素
len() 获取长度

listdir()获取当前目录下所有的文件
isdir()判断是否是目录
"""
import collections
import os
def getAllFileDir(path):
#创建一个队列
queue = collections.deque()
#入队
queue.append(path)
#处理队列,如果队列为空结束操作
while len(queue) != 0:
#出队
outDir = queue.popleft()
#获取当前目录下所有的文件
filelist = os.listdir(outDir)
#判断哪些是目录,入队,如果是文件直接打印
for fileName in filelist:
#判断是否是路径(用绝对路径)
fileAbsPath = os.path.join(outDir,fileName)
if os.path.isdir(fileAbsPath):
print('目录:',fileName)
#入队
queue.append(fileAbsPath)
else:
print('文本文件:',fileName)
#调用函数
getAllFileDir('C:\python课程大纲\python课程大纲')

高阶函数

map

定义:根据提供的函数对指定的序列做映射

格式

map(function,iterable) function---》函数,两个参数---》返回值是一个新的列表 iterable---》一个或者多个序列

python2:返回列表 python3:返回的是迭代器

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
li = [1,2,3,4]
#案例1:计算列表各个元素的平方
#定义一个求平方的函数
def square(n):
return n ** 2

res = map(square,li) #将li列表里面每个元素先作为square函数参数,获取每个元素平方,再执行map函数
print(res) #输出<map object at 0x000002C8C4875CC0>
print(tuple(res)) #输出(1, 4, 9, 16)
print(list(res)) #输出[]
#案例2:将单个字符转换为对应的字面量整数
li2 = ['1','2','3','4']
#定义一个函数
def chrToInt(str):
return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5}[str]
res2 = map(chrToInt,li2)
# print(list(res2))

#案例3:将整数元素的序列,转换为字符串类型
#[1,2,3,4]--->['1','2','3','4']
res3 = map(str,[1,2,3,4])
print(tuple(res3))

reduce

定义:reduce()函数会对参数中的元素进行累积

函数将一个数据集合(列表,元组)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。

格式:

reduce(function,iterable,[initializer]) function:函数,有两个参数 iterable:可迭代的对象 initializer:可选,初始化参数

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from functools import reduce
#案例1:两个数的求和
def add(a,b):
return a + b
res = reduce(add,range(1,101))
print(res)

#案例2:获取每一个词出现的次数(空格)
str = 'hello python hello php python aa ss aa'
list = str.split(' ')
print(list)

#定义一个函数
def func(x,y):
if y in x:
x[y] += 1
else:
x[y] = 1
return x
res3 = reduce(func,list,{})
# reduce 函数的工作流程是:
# 将初始值 {} 和列表中的第一个元素传递给函数 func 进行处理,得到一个新的结果。
# 将上一步的结果和列表中的下一个元素传递给函数 func 进行处理,得到另一个新的结果。
# 不断重复上述过程,直到列表中的所有元素都被处理完毕。
# 返回最终的结果,即字典,其中存储了每个单词的出现次数。
print(res3)

filter

定义

filter()函数:用于过滤序列,过滤掉不符合条件的元素,返回由符合条件的元素组成的新列表

格式

filter(function,iterable) function:函数 判断函数 iterable:序列,序列的每一个元素作为参数传递到函数进行判断,返回True,False,最后将返回True的元素存放到一个新的列表中

返回值

Pyhton2返回列表 Python3返回迭代器对象

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#案例1:筛选指定的元素
list01 = [1,2,3,4,5,6,7,8,9,10]
#案例1:将偶数筛选出来,奇数删除
#定义一个函数
def even(num):
if num % 2 == 0:
return True
return False
res = filter(even,list01)
print(list(res))

#案例2:将没有爱好的信息过滤掉
list02 = [['姓名','年龄','爱好'],['xiaoming',25,'无'],['laowang',30,'写代码'],['xiaogang',29,'无']]
#定义一个函数
def test(v):
if v == '无':
return False
return True
for line in list02:
res2 = filter(test,line)
print(list(res2))
#使用匿名函数
res4 = filter(lambda x:x.isdigit(),L)
print(list(res4))

sorted

定义

sorted()函数对所有的可迭代的对象进行排序的操作 sort: 方法返回的是对已经存在的列表进行操作 sorted:返回值为一个新的list,而不是在原来的基础上进行的操作。

格式

sorted(iterable[, cmp[, key[, reverse]]]) iterable:可迭代的对象 cmp ---》比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。 key ---》主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。 reverse ---》 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
lst = [2,0,99,20,100,111]
lst.sort()
print(lst)
res = sorted(lst)
print(res)

#key接受一个内置函数进行排序
lst2 = [-3,10,8,2,111,-200]
lst2.sort()
print(lst2)
res2 = sorted(lst2,key=abs)
print(res2)