第五讲 Python中的函数

5.1  声明和调用函数

5.1.1  函数定义

函数:指组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。【一个工具,随调随用。函数一词来源于数学,但编程中函数和数学中的函数有很大不同,编程中的函数在英文中也有很多的不同。函数是指将一组语句的集合通过一个名字(函数名)封装起来,要执行这个函数,只需调用这个函数名即可.】

5.1.2  函数的作用

函数能提高应用的模块性和代码的重复利用率。【降级代码冗余,增加代码的复用性,提高开发效率,提高程序扩展性】

5.1.3  函数的声明和调用

◆函数的两个阶段:定义阶段,调用阶段。

定义阶段:只检查函数体内代码语法,不执行函数体内代码。

调用阶段:执行代码。

◆自定义函数:

Ø可以使用def关键字来创建Python自定义函数,其基本语法结构如下:

def 函数名(参数列表)

                                                        函数体

                                                    函数名() #调用函数

Ø参数列表可以为空,即没有参数,也可以包含单个参数、多个参数、默认参数、可变长参数、参数之间使用逗号分隔。

Ø函数中无参数:

def func()

函数体

func() #调用函数

def lily():

     num=600

     score=num/6

     return score

print(lily())#输出100.0

◆函数的三种调用方式

Ø在本模块中调用

Øif __name__ == '__main__': 主函数调用

主函数的解释:

→if __name__ == '__main__': 是函数的入口,也称为主函数 ,__name__ 是当前模块名,当模块被直接运行时模块名为 __main__ ,这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。

→在平时读代码的时候,经常出现if __name__==‘__main__’,这是一个函数的主入口,__name__代表当前模块的名称,__main__代表被运行模块的名称,如果两个模块相等就运行,不相等就不运行。

——————————————————————————————————————————————————————————————

注意:以上两种都是在本模块的调用;如果调不了,就是命名的问题,不要和python中的命名一样

……………………………………………………………………………………………………………………………………………………………………

Ø在其他模块中调用

★注意:必须按照缩写去写函数(因为缩进不容易报错,这是由于python用缩进代替其它编程语言的begin和and,python中的缩进决定了代码的作用域)

【例】

Ø>def out():

      print('这是我输出的第二个语句')

out()#输出这是我输出的第二个语句

>from diaoyong import out

out()#输出这是我输出的第二个语句 这是我输出的第二个语句

Ø>def out():

      print('这是我输出的第二个语句')

 if __name__ == '__main__':

      out()#输出这是我输出的第二个语句

>from diaoyong import out

out()#输出这是我输出的第二个语句

5.2  参数和返回值

5.2.1  函数中参数定义 

如果你希望函数是可以计算的,但计算的数据需要从外面传进来,那么传输数据的介质就叫做参数。参数分为形参和实参:

形参:函数定义时括号内的参数    实参:函数调用时括号内的参数

◆形参相当于变量,实参相当于变量的值。

◆形参:只在被调用时,才分配内存单元。调用结束,立刻释放所分配的内存。只在函数内部有效

◆实参:进行函数调用时,实参必须是确定的值。可以是常量、变量、表达式、函数。

5.2.2  函数中有单个参数

def test(name):

    """

 

    :param name:#参数name

    :return:

    """

    print('我是上海'+name)

test('彭于晏') #调用函数,输出我是上海彭于晏

5.2.3  函数中有多个参数

def test(name,age):

    """

 

    :param name: 传入的参数为姓名

    :param age: 传入的参数为年龄

    :return:

    """

    print('我是上海'+name+'今年'+age)

test('吴彦祖','18')#输出我是上海吴彦祖今年18

5.2.4  函数定义时带上默认参数(缺省参数)

def test(name='周杰伦'):

    print('我是上海'+name)

test()#输出我是上海周杰伦【#调用函数未给默认参数传新值,则函数使用默认值 】

def test(name='周杰伦'):

    print('我是上海'+name)

test('成龙')#输出我是上海成龙【调试函数给默认参数传新值,则函数使用新值】

★注意:当多种参数同时出现在函数中,默认参数要放在最后的位置

5.2.5  可变长参数

可变长定义:

定义一个可变长元组后,函数调用处可以给当前可变长形参赋予N个实参,如没有定义是可变长元组:在函数调用处只能给对应形参对应个数的具体实参。

可变长参数中的可变长元组 "*"表示的是可变长元组

def test(*name):#*号表示多个参数

    print(name)

test('北京','故宫','长城')#输出('北京', '故宫', '长城')

可变长参数中的可变长字典 "**"表示的是可变长字典

def test(*value,**value1):

    print(value)

    print(value1)

dict={'name':'周杰伦','age':18}

test('周杰伦','吴彦祖',**dict)

#输出('周杰伦', '吴彦祖'){'name': '周杰伦', 'age': 18}

★注意:当可变长元组和可变长字典同时出现时,默认将可变长字典放后面

★【拓展】可更改(mutable)与不可更改(immutable)对象

在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

 ◆不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。

 ◆可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

 ◆python 函数的参数传递:

Ø不可变类型:类似 c++ 的值传递,如整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改a的值,只是修改另一个复制的对象,不会影响 a 本身。

Ø可变类型:类似 c++ 的引用传递,如列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

注意:python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

5.2.6  函数的变量和作用域

变量作用域:一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:

ØL (Local) 局部作用域   ØE (Enclosing) 闭包函数外的函数中

ØG (Global) 全局作用域

ØB (Built-in) 内置作用域(内置函数所在模块的范围)

以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。

◆在函数中也可以定义变量,在函数中定义的变量被称之为局部变量,局部变量只在定义它的函数内部有效。【定义在函数内部的变量拥有一个局部作用域】 

◆在函数体之外定义的变量,我们称之为全局变量。【定义在函数外的拥有全局作用域】

◆局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

【例】 num=400

def lily():

    global num#把函数内局部变量变为全局变量,函数外的原变量失效,global只能在函数体内使用

    num=200

    sum=num+100

    print(sum)

lily()

test=num

print(test)#输出300  200

【例】num=400

def lily():

    num=200

    sum=num+100

    print(sum)

lily()

test=num

print(test)#输出300 40

【例】num=100#在函数体外的变量是全局变量

def lily():

    num=200#定义在函数体内的变量为局部变量

    print(num)

lily()#输出200

5.2.7  函数的返回值

◆Python中,用def语句创建函数时,可以用 return 语句指定应该返回的值,该返回值可以是任意类型。需要注意的是,return 语句在同一函数中可以出现多次,但只要有一个得到执行,就会直接结束函数的执行。

◆函数中,使用return语句的语法格式如下:

return [返回值]

其中,返回值参数可以指定,也可以省略不写(将返回空值 None)。

Ødef lily():

      num=600

      score=num/6

      return score#return能把结果返回,但其后面的代码不会被执行                 print(lily())#输出100.0

◆返回值的作用

Ø在程序开发中,有时候会希望一个函数执行程序结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理。

Ø返回值是函数完成工作后,最后给到调用者的一个结果。

Ø在函数中使用return关键字可以返回结果。

Ø调用函数的一方可以使用变量来接收函数的返回结果。

【例】需求:登录银行系统并显示余额,有两个功能第一个是登录,第二个是登录后显示余额,先登录然后根据登录是否成功然后是否显示余额。

[思路分析]:如果想查询到余额,前提必须登录,所以现在我们用两个函数来处理,第一个函数实现登录,第二个函数实现余额查询,调用第一个函数得到的结果给第二个函数,然后第二个函数根据结果进行代码处理。

def login():

    name=input('账号:')

    if name=='admin':

        pw=input('密码:')

        if pw=='123456':

            print('登录成功')

            return ('登录成功')

        else:

             print('密码输入错误')

    else:

         print('账号输入错误')

def rmb():

    cx=login()

    if cx=='登录成功':

        print('您的账户余额为99999999999')

    else:

        print('查询余额失败')

rmb() #输出  账号:admin  密码:123456   登录成功   您的账户余额为99999999999

5.3  python内置函数

5.3.1  format()函数

format()函数是一种格式化字符串的函数,该函数增强了字符串格式化的功能。

基本语法:是通过 {} 来代替以前的 %

不设置指定位置,按默认顺序

str="{}{}".format("hello","kitty",'boy')   print(str)

#输出hellokitty

str="{}{}{}".format("hello","kitty",'boy')   print(str)

#输出hellokittyboy

设置指定索引位置格式化输出

str='{0}{2}'.format('hello','kitty','boy')   print(str)

#输出helloboy

设置参数名称格式化输出

str='姓名:{name} 年龄:{age}'.format(name='kitty',age='18')

print(str)#输出  姓名:kitty 年龄:18

对列表进行格式化

Ølist=['kitty',18]

str = '姓名:{0[0]} 年龄:{0[1]}'.format(list)

print(str)#输出姓名:kitty 年龄:18

Ølist=['kitty',18]

list1=['tom',24]

str = '姓名:{1[0]} 年龄:{0[1]}'.format(list,list1)

print(str)#输出  姓名:tom 年龄:18

★注意:大括号里面的0和1代表的是列表、中括号里面的0和1是列表元素对应的索引位

对字典进行格式化输出, "**"表示可变长字典

Ødict={'name':'kitty','age':'18'}

str = '姓名:{name} 年龄:{age}'.format(**dict)

print(str)#输出 姓名:kitty 年龄:18

Ødict={'name2':'kitty','age2':'18'}

dict1={'name1':'tom','age1':'24'}

str = '姓名:{name1} 年龄:{age2}'.format(**dict,**dict1)

print(str)#输出  姓名:tom 年龄:18

5.3.2  zip()函数

zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表,如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。

Ø list1=['kitty','tom','lily']

list2=['18','22','24']

list3=list(zip(list1,list2))

print(list3)#输出[('kitty', '18'), ('tom', '22'), ('lily', '24')]

Ølist1=['kitty','tom','lily']

list2=['18','24']

list3=list(zip(list1,list2))

print(list3)#输出[('kitty', '18'), ('tom', '24')]

Ølist1=['kitty','tom','lily']

list2=['18','24']

list3=dict(zip(list1,list2))

print(list3)#{'kitty': '18', 'tom': '24'}

5.3.3  open()函数

open() 函数用于打开一个文件,创建一个 file 对象,接收两个参数:文件名(file)和模式(mode)

语法:open(file, mode),模式有r(只读),w(写入覆盖),a(写入追加)

文件打开模式:文件句柄 = open('文件路径', '模式')

读的模式: r(只读) [默认]

Økitty=open('wps.txt','r',encoding='utf-8')

all=kitty.read()

print(all)#输出Nice to meet you!!!

Økitty=open('wps.txt','r',encoding='utf-8')

all=kitty.read()#读取文件中所有内容返回字符串#输出

Nice to meet you!!!

125466

kbkvh

all=kitty.readline() #读取文件中第一行内容

#输出Nice to meet you!!! 

all=kitty.readlines() #读取文件中所有内容返回列表

#输出['Nice to meet you!!!\n', '125466\n', 'kbkvh']

读相关函数文件中包含中文字符的解决方法

o = open(r'C:\aa.txt','r')

all = o.read()

print all.decode('gbk') #进行解码为gbk编码

路径中包含中文字符的解决方法

path = unicode(r'C:\多测师\aa.txt',encoding='utf-8')

o = open(path,'r')

a = o.read()

print a

写的模式:w(写入覆盖)  

 注:python具有垃圾回收机制,当执行write写入操作时,无法确定是否会立即写入文件,为了提高写入效率,首先会将数据放到缓冲区,只有当文件已满、调用flush或文件关闭(内部执行flush)时,缓冲区才会写入文件,因此,原因是不能使用两个不同的变量名称,因为写入操作从未真正发生在kitty.close()行之前使用相同的变量名‘工作’的原因是,当你重新绑定kitty=open(filename)时,以前绑定到wps.txt的文件现在不在任何地方被引用,因此收集器将其删除,当文件句柄被删除时,数据写入文件,因此你可以在以后读取到它。

Økitty=open('wps.txt','w',encoding='utf-8')

kitty.write('你好,kitty')

kitty.writelines('\n很高兴遇见你')

kitty.close()#关闭文件 #输出你好,kitty

                            很高兴遇见你

Økitty=open('wps.txt','w',encoding='utf-8')

kitty.write('你好,kitty')

kitty.writelines('很高兴遇见你\nNice to meet you')

kitty.close()#输出你好,kitty很高兴遇见你Nice to meet you

追加的模式:a(写入追加)

kitty=open('wps.txt','a',encoding='utf-8')

kitty.write('\npython学习要灵活一点')

kitty.close()#输出  你好,kitty很高兴遇见你

                    Nice to meet you

                    python学习要灵活一点

open()函数扩展用法

with open("C:\\aa.txt", 'r')as f:

a = f.read()

b = f.readline()

c = f.readlines()

d = f.write()

e = f.writelines()

用with语句的好处,就是到达语句末尾时,会自动关闭文件,即便出现异常。

【拓展】as的三种用法:

◆  with...as...

第一种是某些对象总是有固定的规律做事,使用with as语句,省去必须要做的事情

◆  基本原理:with语句后面的对象,它的特殊方法__enter__会被自动调用,而__enter__方法返回的对象会赋值给as后面定义的变量temp,当with as代码体中的全部语句执行完毕,with后面的对象,它的特殊方法__exit__又会被自动调用

Ø和with结合使用,主要用于文件的读写操作,省去了关闭文件的麻烦。

Ø

1、内置函数open会返回一个File对象

2、File对象的__enter__方法会被自动调用,且__enter__方法返回是self,即File对象本身

3、__enter__方法返回的对象,会被赋值给as后面定义的变量my_file中

4、接着with as方法体中的print()语句执行

5、执行结束后,File对象的__exit__方法会被自动调用

◆  导入模块起别名

第二种是导入模块是对模块进行重命名,也就是给模块起一个别名。

Øimport numpy as np#导入numpy整个模块,并指定别名为np

◆  except结合使用

第三种是写入异常,和except组合使用,将捕获到的异常对象赋值给e,可查看异常。

 

Python内置函数

内置函数

abs()

divmod()

input()

open()

staticmethod()

all()

enumerate()

int()

ord()

str()

any()

eval()

isinstance()

pow()

sum()

basestring()

execfile()

issubclass()

print()

super()

bin()

file()

iter()

property()

tuple()

bool()

filter()

len()

range()

type()

bytearray()

float()

list()

raw_input()

unichr()

callable()

format()

locals()

reduce()

unicode()

chr()

frozenset()

long()

reload()

vars()

classmethod()

getattr()

map()

repr()

xrange()

cmp()

globals()

max()

reverse()

zip()

compile()

hasattr()

memoryview()

round()

__import__()

complex()

hash()

min()

set()

 

delattr()

help()

next()

setattr()

 

dict()

hex()

object()

slice()

 

dir()

id()

oct()

sorted()

exec内置表达式


5.4  python中的模块

5.4.1  模块的定义

◆Python模块(Module):是一个Python文件,以.py 结尾,包含了

Python 对象定义和Python语句。

Ø模块让你能够有逻辑地组织你的Python代码段。把相关的代码分配到一个模块里能让你的代码更好用,更易懂。

Ø模块能定义函数,类和变量,模块里也能包含可执行的代码。

包和目录的区别:包和模块都可以被导入,但是不能只导入目录

Ø新建一个软件包里面有一个默认的__init__.py.这个模块来初始化这个包当前所有的内容,有__init__.py模块的包才叫做包

ØPython中分为内置模块和自建模块(我们自己创建的模块)

5.4.2  模块的调用和导入

◆模块的导入

import语句

Ø模块定义好后,可以使用import语句来引入模块,语法如下:

import module1,module2.....moduleN

比如要引用模块 time,就可以在文件最开始的地方用import time 来引入。在调用time模块中的函数时,必须这样引用:

模块名.函数名(如:time.sleep(2))

注意:一个模块只会被导入一次,不管你执行了多少次import,这样可以防止导入模块被一遍又一遍地执行

Øfrom....import *  导入一个模块中的所有项目,如导入time模块中的所有类、函数、变量等等。语法如下:  

from time import *

Øfrom....import...从模块中导入一个指定的部分到当前命名空间中。语法如下:

from modname import name1,name2...nameN

→要导入time模块的sleep函数,使用如下语句:

from time import sleep

→要导入time模块中的sleep函数并取别名,使用如下语句:

from time import sleep as s

5.4.3  常见的模块

python中常见的模块:time模块、random模块、hashlib模块、os模块、re模块、string模块、xlrd模块、json模块、sys模块

5.4.3.1  Time模块

◆时间戳

Ø时间戳是指格林威治时间 1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒) 起至现在的总秒数

Ø最早出现的 UNIX 操作系统考虑到计算机产生的年代和应用的时限综合取了1970年1月1日作为 UNIX TIME 的纪元时间(开始时间)

◆Time模块中常见的方法:

Øtime.time()#1970到现在经过的秒数

import time#导入time模块

print(time.time())#通过模块把里面的函数进行调用

#输出1660135212.766191

Øtime.ctime()#固定格式的当前时间

import time

print(time.ctime())

#输出Wed Aug 10 21:15:44 2022

Øtime.sleep()#延时或休眠,单位是秒


import time

time.sleep(3)

print(1)

from time import sleep

sleep(3)

print (1)


from time import *

sleep(3)

print (1)

#线程等待三秒,输出1

Øtime.localtime()

→当参数为默认值时,返回本地当前时间的时间元组

import time

print(time.localtime())

#输出time.struct_time(tm_year=2022, tm_mon=8, tm_mday=10, tm_hour=20, tm_min=45, tm_sec=7, tm_wday=2, tm_yday=222, tm_isdst=0)

→当输入参数秒后,返回的是1970年1月1日早上8点后+参数秒数后的时间

import time

print(time.localtime(60))#输出time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=8, tm_min=1, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)

Øtime.asctime()#转换为asc码显示当前时间

import time

print(time.asctime())#输出Wed Aug 10 20:51:09 2022

Øtime.strftime(str,str_fmt)#根据 str 的格式把时间字符串解析为时间元组

import time

print(time.strftime('%Y-%m-%d-%H-%M-%S'))

#输出2022-08-10-21-02-23

【拓展】python 中时间日期格式化符号:

%y 两位数的年份表示(00-99)    %Y 四位数的年份表示(000-9999)

%m 月份(01-12)               %d 月内中的一天(0-31)

%H 24小时制小时数(0-23)      %I 12小时制小时数(01-12)

%M 分钟数(00=59)              %S 秒(00-59)

%a 本地简化星期名称             %A 本地完整星期名称

%b 本地简化的月份名称           %B 本地完整的月份名称

%c 本地相应的日期表示和时间表示 %j 年内的一天(001-366)

%p 本地A.M.或P.M.的等价符

%U 一年中的星期数(00-53)星期天为星期的开始

%w 星期(0-6),星期天为星期的开始

%W 一年中的星期数(00-53)星期一为星期的开始

%x 本地相应的日期表示              %X 本地相应的时间表示

%Z 当前时区的名称                  %% %号本身

 

from time import time,sleep,ctime#导入多个函数可以用逗号隔开

挎包导入模块  from modetest import hanshu#通过包名把里面的模块导入

5.4.3.2  random模块

python中的random模块:生成随机浮点数、整数、字符串,还可以随机选择列表序列中的一个元素random() 方法返回随机生成的一个实数,它在[0,1)范围内。

◆random模块中常见的方法:

Ørandom.random()   返回随机生成的一个 [0,1) 范围内的实数

import random

print(random.random())#该方法随机生成0到1之间的随机浮点数,能取到0但取不到1

Ørandom.randint(x,y)

import random

print(random.randint(1,5))#随机生成指定范围内的一个整数型随机数,包括开始值与结束值

Ørandom.randrange(a,b,step)

随机生成一个 [a,b) 之间的一个整数,可以定义 step 步长,与range()用法类似

import random

print(random.randrange(1,3,2))#生成指定范围内的奇数,不包括结束值

print(random.randrange(0,3,2))#生成指定范围内的偶数,不包括结束值

Ørandom.choice(a)

从 a 中随机选择一个元素,a 不能为空且 a 不能为字典

import random

print(random.choice('hrofl69'))#生成随机字符

Ørandom.sample(a,n)

import random

list=['1','3','5','7','9']

print(random.sample(list,3))#从list列表中随机取3个随机且独立的元素

Ørandom.shuffle( )

import random

list=['1','3','5','7','9']

random.shuffle(list)#洗牌,随机生成列表

print(list)

注意:shuffle()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法

练习:使用random模块随机生成手机号码,开头三位数字自定义

import random

def phonenum(startnum):

    phone=str(startnum)

    for i in range(8):

        phone+=str(random.randint(0,9))

    return phone

print('随机电话号码:'+phonenum(137))

#输出随机电话号码:13776277368

import hashlib

def md5fun(string):

    list1=[]

    md5=hashlib.md5()#MD5加密

    md5.update(string.encode('utf-8'))

    list1.append(string)

    list1.append(md5.hexdigest())

    return list1

print('生成16进制字符串为:{0[1]}'.format(md5fun(phonenum(137))))#生成16进制字符串为:c53cb7f966bed2dd59e78dd3702e86b8

 

 

Hashlib.md5()#MD5加密

import hashlib

kitty=hashlib.md5()#通过hashlib模块中MD5函数创建一个对象

kitty.update('123456'.encode('utf-8'))#通过MD5对象调用update函数对字符串进行加密

print(kitty.hexdigest())#通过对象调用hexdigest函数生成一个16进制并且为32位的字符串

#输出e10adc3949ba59abbe56e057f20f883e

 

练习:用random模块随机生成6位数验证码

import string

import random

def yanzhengma(num):

    strs = ''

    for i in range(num):

        strs += str(random.choice(string.digits + string.ascii_letters))

    return strs

print('随机验证码为:' + yanzhengma(6))

#输出   随机验证码为:Oeffv6

练习:通过md5加密算法把随机生成的6位数验证码进行加密返回16进制的字符串

import hashlib

def md5fun(string):

    list1=[]

    md5=hashlib.md5()

    md5.update(string.encode('utf-8'))

    list1.append(string)

    list1.append(md5.hexdigest())

    return list1

print('\n随机字符串:{0[0]}\n生成16进制字符串为:{0[1]}'.format(md5fun(yanzhengma(6))))

输出:生成16进制字符串为:eeeb71171fe971d5321e27af133f5def

5.4.3.3  python中os模块

os模块提供了多数操作系统的功能接口函数。当os模块被导入后,它会自适应于不同的操作系统平台,根据不同的平台进行相应的操作,在python编程时,经常和文件、目录打交道,所以离不了os模块。【os模块可以帮助我们直接对操作系统进行操作,通过直接调用操作系统对可执行操作文件、命令,直接操作文件,目录等】

import os

os.system('chcp 65001')#命令提示符中的一个可执行命令,可以返回活动代码页对编码,还可以设置当前对活动代码页

os.system('ping www.baidu.com')#执行cmd命令

os.system('xxx.html')#默认浏览器打开xxx.html文件

os.system('xxx.exe')#运行exe程序

os.system('xxx.py -u http:1.1.1.1')#运行python脚本

 

os模块中常见的方法:

os.getcwd()获取当前执行命令所在目录

os.path.isfile()判断是否为文件

print(os.path.isfile(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))#输出False

os.path.isdir() #判断是否为目录

print(os.path.isdir(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))

#输出True

os.path.exists() #判断文件或目录是否存在

★(重要)os.listdir(dirname) #列出指定目录下的目录或文件

print(os.listdir(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))

#输出['hanshu.py', 'wps.txt', '__init__.py', '__pycache__']

 

os.path.split(name) #分割文件名与目录

print(os.path.split(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest'))#输出('C:\\Users\\Administrator\\PycharmProjects\\pythonProject', 'modetest')

os.path.join(path,name) #连接目录与文件名或目录

print(os.path.join('C:\\Users\\Administrator\\PycharmProjects\\pythonProject', 'modetest'))#输出C:\Users\Administrator\PycharmProjects\pythonProject\modetest

os.mkdir(dir) #创建一个目录

os.mkdir(r'C:\Users\Administrator\PycharmProjects\pythonProject\mulu')

os.rename(old,new) #更改目录名称

os.rename(r'C:\Users\Administrator\PycharmProjects\pythonProject\Azhengze',r'C:\Users\Administrator\PycharmProjects\pythonProject\mulu')

 

5.4.3.4  python中re正则模块

实现一个编译查找,一般在日志处理或者文件处理时用的比较多

正则表达式主要用于模式匹配和替换工作。

预定义字符集匹配:

\d:数字0-9

import re

str=re.match('\d','123434hhjash')

print(str)输出<re.Match object; span=(0, 1), match='1'>

str=re.match('\d','a123434hhjash')

print(str)#输出None(匹配失败)

 

\D:非数字

\s:空白字符

\n:换行符

\r:回车符

re模块数量词匹配:

符号^:表示的匹配字符以什么开头

符号$:表示的匹配字符以什么结尾

符号*:匹配*前面的字符0次或n次

str=re.match('\d*','123434hhjash')

print(str)#输出<re.Match object; span=(0, 6), match='123434'>

str=re.match('\d*','m123434hhjash')

print(str)#输出<re.Match object; span=(0, 0), match=''>

eg:ab* 能匹配a 匹配ab 匹配abb

符号+:匹配+前面的字符1次或n次

str=re.match('\d+','123434hhjash')

print(str)#输出<re.Match object; span=(0, 6), match='123434'>

符号?:匹配?前面的字符0次或1次

str=re.match('\d?','123434hhjash')

print(str)#输出<re.Match object; span=(0, 1), match='1'>

str=re.match('\d?','a123434hhjash')

print(str)#输出<re.Match object; span=(0, 0), match=''>

符号{m}:匹配前一个字符m次

str=re.match('\d{2}','123434hhjash')

print(str)#输出<re.Match object; span=(0, 2), match='12'>

符号{m,n}:匹配前一个字符m到n次(包括n次),m或n可以省略,m、n都是正整数

str=re.match('\d{2,6}','123434hhjash')

print(str)#输出<re.Match object; span=(0, 6), match='123434'>

5.4.4  re模块相关函数

5.4.4.1  match

从第一个字符开始匹配,如果第一个字符不是要匹配的类型、则匹配失败并报错

Østr=re.match('^2\d{2}','23434hhjash')

print(str)#输出<re.Match object; span=(0, 3), match='234'>

Østr=re.match('^2\d{2}','123434hhjash')

print(str)#输出None

Østr=re.match('^2\D{1,3}','2hhjash')

print(str)#输出<re.Match object; span=(0, 4), match='2hhj'>

Østr=re.match('^2\D{1,3}$','2hhj')#要求字符串位数要与1,3对应,位数若多或少会报错为none

print(str)#输出<re.Match object; span=(0, 4), match='2hhj'>

Østr=re.match('^1[38675][13586]\d{8}$','15366668888')

print(str)#输出<re.Match object; span=(0, 11), match='15366668888'>

Østr=re.match('^1[a-z][A-Z]\d{8}$','1aA88886666')

print(str)#输出<re.Match object; span=(0, 11), match='1aA88886666'>

注意:如果规则带了'+',则匹配1次或者多次,无'+'只匹配一次

5.4.4.2  search

从第一个字符开始查找、一找到就返回第一个字符串,找到就不往下找,找不到则报错

Østr=re.search('\d','2664ewhsjuf15sd')

print(str.group())#输出2

Østr=re.search('\d+','w2664ewhsjuf15sd')

print(str.group())#输出2664

Østr=re.search('\d+','wewhsjuf15sd')

print(str.group())#报错AttributeError: 'NoneType' object has no attribute 'group'

Østr=re.search('\d*','2664ewhsjuf15sd')

print(str.group())#输出2664

Østr=re.search('\d*','w2664ewhsjuf15sd')

print(str.group())#无返回值,第一个必须是整型数字

5.4.4.3  findall   

从第一个字符开始查找,找到全部相关匹配为止,找不到返回一个列表[]

Østr=re.findall('\d+','o2664ewhsjuf15sd')

print(str)#输出['2664', '15']

Østr=re.findall('\D+','o2664ewhsjuf15sd')

print(str)#输出['o', 'ewhsjuf', 'sd']

 

Østr=re.findall('error','o2664ewherror15sd$')

  print(str)#输出['error']【可用于查找关键字】

Østr=re.findall('error(.+)error','erroro2664ewherror15sderror$')#查找以error开头,以error结尾的中间部分

print(str)#输出['o2664ewherror15sd']【.表示任意字符但使用换行符,换行符后面将不会被匹配    +表示匹配1次或多次】

Østr=re.findall('error(.+)error','erroro2664ewherror15s\nderror$')

print(str)#输出['o2664ewh']

Østr = re.findall('python','kitty')

print(str)#无匹配项时,输出空列表[]

5.4.4.4  compile

编译模式生成对象,找到全部相关匹配为止,找不到返回一个列表[]

Østr=re.compile('error')#需要查找出的对象

str2=str.findall('4146aajerror$%54errorfgg')#定义在哪找

print(str2)#输出['error', 'error']

5.4.5  【模块练习】

Ø使用os模块写一个递归打印出一级目录下面所有的绝对路径

import os

def get_path(path):

    kitty=os.listdir(path)

#     print(kitty)

    for i in kitty:

        newpath=os.path.join(path, i)#对文件和目录进行拼接后读取文件绝对路径

        if os.path.exists(newpath): #通过读取绝对路径判断newpath是否为一个文件

            print(newpath)

        else:

            get_path(newpath)#此处是递归函数,在函数中调用自己

get_path(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest')#获取目录

#输出C:\Users\Administrator\PycharmProjects\pythonProject\modetest\hanshu.py

C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt

C:\Users\Administrator\PycharmProjects\pythonProject\modetest\__init__.py

C:\Users\Administrator\PycharmProjects\pythonProject\modetest\__pycache__

Ø用正则方法实现统计文件指定字符所在行的数量,如“实现”所在行出现多少次(文件中的“实现”)

import re

def count(path):

    kitty=open(path,'r')

    hello=kitty.readlines()

    num=0

    for i in hello:

        tom=re.findall('kitty',i)

#第一种方法

        for j in set(tom):

            num+=1

    print(num)

第二中方法

if 'kitty' in tom:

            num+=1

     print(num)

count(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt')#输出2

Ø用正则实现写一段代码统计文件中的例如error和waring单词它们分别出现的次数

方法一★import re

def count(path):

    kitty=open(path,'r',encoding='utf-8')#定义对象并打开文件,只读

    hello=kitty.readlines()#读取所有行

    dict1={}

    for i in hello:#遍历出一个i

        tom=re.findall('error',i)#从i中找error

        lily=re.findall('waring',i)#从i中找waring

        for j in tom:

            dict1[j]=dict1[j]+1 if j in dict1 else dict1.setdefault(j,1)

        for k in lily:

            dict1[k]=dict1[k]+1 if k in dict1 else dict1.setdefault(k,1)

    print(dict1)

count(r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt')

#输出{'error': 3, 'waring': 2}

方法二★import re

fileurl=r'C:\Users\Administrator\PycharmProjects\pythonProject\modetest\wps.txt'

liststr=['error','warning']

def filelistcount(url,strlist):

    with open(url,'r',encoding='utf-8') as file:

        count=0

        dicstr={}

        allline=file.read()

        print(file.read())

        for i in set(strlist):

            str1=re.findall(i,allline)

            dicstr.setdefault(i,len(str1))

        print(dicstr)

filelistcount(fileurl,liststr)

#输出{'warning': 0, 'error': 3}

Ø用正则完成市面上手机号码编写规则,随机生成11位数,然后通过正则匹配出符合规则的11位手机号码

import random,string,re

def get_phone():

    num=string.digits

    list=[]

    for i in range(11):

        list.append(random.choice(num))#随机选取数字

    hello=''.join(list)

    kitty=re.findall('^1[34578][12689]\d{8}$',hello)

    if kitty:

        print(''.join(kitty))

    else:

        get_phone()

get_phone()#输出18203964603

 

Python 3 转义字符表(带示例)

5.5  python中的对象

5.5.1  面向对象的基本概念

◆面向对象思想

Ø面向对象编程是在面向过程编程的基础上发展来的,它比面向过程编程具有更强的灵活性和扩展性。

Ø面向对象编程(Object-oriented Programming,简称 OOP),是一种封装代码的方法。其实,在前面章节的学习中,我们已经接触了封装

Ø代码封装,其实就是隐藏实现功能的具体代码,仅留给用户使用的接口,就好像使用计算机,用户只需要使用键盘、鼠标就可以实现一些功能,而根本不需要知道其内部是如何工作的。

Ø面向对象编程,也是一种封装的思想,它可以更好地模拟真实世界里的事物(将其视为对象),并把描述特征的数据和代码块(函数)封装到一起。

面向对象(Object Oriented)是软件开发方法,一种编程范式。【是一种编程思想,任何事物都可作为一个对象,都一个对应的属性和行为】最重要的概念是类和实例

范式从本质上讲是一种理论体系、理论框架。

类(class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

实例(instance):类是一个具体的对象,创建出来的对象称为实例(即实际的对象)。

实例化:创建一个类的实例,类的具体对象。【根据一个类创建不同对象的动作,称为实例化】 

实例属性:对象的属性

实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。【对象或实例独有的属性】 

实例方法:对象调用的方法

类(Class)和实例(Instance)的区别:类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

对象(object):通过类定义的数据结构实例。对象是类的实例,对象就是看得见、摸得着的东西,有自己的特征,也可能有自己的行为,万物皆可对象,对象包括两个数据成员(类变量和实例变量)和方法。

对象和类的关系:类和对象的关系就像模具和铸件的关系,类的实例化的结果就是对象,而对象的抽象体就是类。

属性:类中的所有变量称为属性。属性称为变量:如lily=‘123’

方法:类中的所有定义的函数称为方法。与函数所有不同的是,类方法至少要包含一个 self 参数。类方法无法单独使用,只能和类的对象一起使用。

类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。【即类共有的属性】

继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。

例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

5.5.2  定义和使用类

5.5.2.1  类的定义

类的设计:在使用面向对象开发前,应该首先分析需求,确定程序中包含哪些内容。

在程序开发中,设计一个类,通常要满足以下三个条件:一是类名,即这类事物的名字,需满足大驼峰命名法;二是属性,即这类事物具有什么样的特征;三是方法,即这类事物具有什么样的行为。

大驼峰命名法:每个单词的首字母大写,且单词与单词之间没有下划线

类名的确定:一般采用名词提炼法分析整个业务流程,出现的名词通常就是要找的类

★类名称定义规范:

Ø不要以纯数字命名

Ø不要以python中保留字符(关键字)来命名

Ø不要以文件名命名              Ø不能出现特殊字符

Ø要简短且见名知义

Ø当类名称中有多个单词时,应采用大驼峰命名法

属性和方法的确定:对对象的特征描述,通常可以定义为属性;对于对象具有的行为(动词),通常可以定义为方法。

★注意:若需求中没有涉及到的属性或方法,在设计类时,一般不需要考虑属性和方法

定义简单的类(只包含方法)

面向对象实质是更大的封装,在一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法了

定义只包含方法的类:在python中定义一个只包含方法的类,基本语法如下:

class 类名:

             def 方法1(self,参数列表):

                  pass

             def 方法2(self, 参数列表):

                  pass

方法的定义格式和之前学过的函数拒户一样,区别在于第一个参数必须是self

创建对象:对象是类的实例,只有在类中定义了对象才能使用类。当定义完成后,要使用这个类来创建对象,创建对象基本格式如下:

对象变量=类名()

【例】面向对象程序:小猫爱吃鱼,小猫要喝水

class Cat:#定义一个类

      def eat(self):#定义方法1

          print('小猫爱吃鱼')

      def drink(self):#定义方法2

          print('小猫要喝水')

     tom=Cat()#把Cat()类创建为一个tom对象

     tom.eat()#小猫爱吃鱼#调用tom对象里的eat方法

     tom.drink()#小猫要喝水#调用tom对象里的drink方法

◆python中给对象设置属性:

▼tom.name=’Tom’#但不推荐使用此种方法,因为对象的属性应该封装在类的内部只要在类的外部的代码中直接通过,设置一个属性即可。

class Cat:

                      def eat(self):

                          print('%s爱吃鱼' %self.name)

                  tom=Cat()

                  tom.name='Tom'  #实例变量

                  tom.eat()   #Tom爱吃鱼

                  lily=Cat()

                  lily.name='大熊猫'

                  lily.eat()#大熊猫爱吃鱼

▼标准定义方法:

【例】#object称为父类或基类,也是一切类的父类。类中定义一个方法时按tab键自动定位合适编写位置

#表示该类从哪个类继承下来的,object是所有类都会继承的类

class People(object):#经典类

    # (定义变量)类变量

    head=1

    #构造函数,又称构造方法,此处称为构造方法,作用是为了创建形式对象,双下划线表示私有方法,name、age是形式参数

    def __init__(self,name,age):

        # self.name、self.age称为实例变量,self是当前类的对象本身,私有变量,只能在内部使用

        self.name = name#实例变量

        self.age = age

        #调用实例变量

        # print('name')#输出name

#这是实例方法

    def play(self):

        print(self.name+'去打篮球')

#如何调用,需要先实例化创建一个对象lily,对象的名字叫kitty

lily=People('kitty',22)#创建一个对象lily

tom=People('hello',24)

#调用类方法

lily.play()#输出kitty去打篮球

tom.play()#输出hello去打篮球

#调用类变量

print(People.head)#输出1

▼初始化方法

当使用类名()创建对象时,会自动执行操作,例如为对象在内存中分配空间---创建对象。为对象的属性设置初始值——初始化方法是__init__,是对象的内置方法,主要用来定义一个类具有哪种属性的方法。

由于类可以起到模板的作用,因此在创建实例的时候,可把我们认为必须要绑定的属性强制填进去,此时可用python的内置方法__init__

注意:

Ø定义类的时候__init__是一个构造函数,该函数是两个下划线开头和两个下划线结束,其作用就是当创建类的对象和实例时系统会自动调用构造函数,通过构造函数对类进行初始化操作。

Ø在创建实例的时候,就不能传入空的参数,必须传入与__init__方法匹配的参数

Ø定义类的时候__init__方法中有一个参数self,这也是类中的方法与普通函数的区别,类的中的方法必须有一个参数self,而且位于参数列表的开头。在类中self就是代表类的当前类的实例(对象)自身,在python调用时不用传递该参数,即无需传值,python会将对象自动传给self接受

在初始化方法内部定义属性,即在__int__方法内部使用self.属性名=属性的初始值来定义属性,定义属性之后,再使用Cat创建的对象,都会拥有该属性。

例:在Cat类,把name\colour等属性绑上去

 class Cat(object):

#在定义属性时,不设置初始值时,可设关键字为None,表示无,即一个空对象,没有方法和属性,是一个特殊的常量,并可将None复制给任何一个变量

         def __init__(self,name,colour):

              self.name = name

              self.colour = colour

        lily=Cat('tom',None)

        print(lily.name)#输出tom

        print(lily.colour)#输出None

一个对象的属性可以是另一个类创建时的对象。例如

class Tom():

    def __init__(self,model):

        self.model = model

        self.bull_count = 0

    def add_bullet(self,count):

        self.bull_count+=count

    def shoot(self):

        if self.bull_count<=0:

            print('[%s]祝你生日快乐!!!'%self.model)

            return

        self.bull_count -= 1

        print('[%s]哼哈哼哼哈哈。。[%d]'%(self.model,self.bull_count))

class Masike():

    def __init__(self, name):

        self.name=name

        self.Tom=None

    def fire(self):

        if self.Tom == None:

            print('[%s]去三亚旅游'%self.name)

            return

        print('冲啊。。。[%s]'%self.name)

        self.Tom.add_bullet(50)

        self.Tom.shoot()

hello=Tom('AK47')

kitty=Masike('Ak47')

kitty.Tom=hello

kitty.fire()

print(kitty.Tom)

#输出冲啊。。。[Ak47]

[AK47]哼哈哼哼哈哈。。[49]

<__main__.Tom object at 0x0000025275BA3EE0>

5.5.2.2  类的使用

类的封装/调用

封装是面向对象编程的一大特性, 我们在使用面向对象开发程序的时候, 第一步就应该现在需求分析, 然后根据明确的职责把不同的属性和方法封装到一个又一个抽象的类中, 之所以说是抽象, 因为在程序开发中, 类是不能直接使用的。当我们定义好了一个类之后, 就可以在类的代码外部, 使用定义到的类创建出一个又一个对象, 让这些对象来调用我们封装在类的内部的方法, 这个是面向对象编程的一个非常明显的特点。(在外部,类创建对象, 对象调用方法)

对象的方法的实现细节都是封装在类的内部的。

看到需求, 应该使用名词提炼法, 把需求中的名词提炼出来, 有小明, 就可以定义一个 Person() 类, 在Person() 类增加一个name的属性, 让这个name属性来记录一下小明的名字。体重是小明的一个特征, 因此我们再需要定义一个体重weight 的属性, 让weight 来记录小明的体重

Ø调用类下的方法,必需通过类的的实例/类名()进行调用

Ø 当类中初始化方法__init__中存在参数时,则在实例化时,需要往实例括号中传入参数

 Ø当类中无初始化方法或者__init__中不存在参数时,则在实例化时,不需要往实例括号中传入参数,而在调用方法时再进行传参

◆类的作用

Ø定义变量;

Ø创建对象;

Ø派生子类;

面向对象和面向过程

面向对象开发步骤如下:

1、使用面向对象开发,第1步是设计类,并使用类名()创建对象,创建对象的动作有两步:①在内存中为对象分配空间;②调用初始化方法__init__为对象初始化;

2、创建对象后,内存中就有了一个对象且实实在在的存在,即实例(创建出来的对象叫做类的实例;创建对象的动作叫做实例化;对象的属性叫做实例属性;对象调用的方法叫做实例方法)

Ø面向过程优缺点:

优点:流程化,分步骤实现,效率高,代码短小精悍

缺点:思考难道大,代码复用率低,扩展差,难维护

Ø面向对象优缺点:

优点:结构化,模块化,易扩展,可继承,可覆盖,易维护

缺点:程序臃肿,性能低

◆类对象和实例对象

类是一个特殊的对象,python中一切皆对象,如

class AA: 定义的类属于类对象,

class AA():定义的类属于实例对象。

在python中,类是一个特殊的对象,即类对象,在程序运行时,类同样会被加载到内存,类对象在内存中只有一份,使用一个类可以创建出多个对象实例,除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法(类属性:类方法),通过 类名.  的方式访问类的属性或者调用类的方法。

在程序执行时,对象各自拥有自己的实例属性,调用对象方法,可以通过self.  访问自己的属性并调用自己的方法

Ø结论:每一个对象都有自己独立的内存空间,保存各自不同的属性,多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用传递到方法内部

◆类中的类变量、实例变量

在整个类里面有的属于类的,有的属于对象的,那么属于类的属性叫类变量,属于对象的属性叫做实例变量。

class People(object):

head = 1 #类变量

def __init__(self,name):

self.name = name #实例变量

p = People('xiaowang')#创建对象

◆类属性和实例属性

类属性:指针对类对象定义的属性(类属性作用:通常用来记录与这个类相关的特征,但不会用于记录具体对象的特征,一般在class关键字下方定义类属性)

例:需求是定义一个工具类,每件工具都有自己的name,统计类创建工具(实例对象)的数量?

class Tool(object):

    #定义变量count接收创建工具(对象)的总数

    count = 0

    def __init__(self,name):

        self.name = name

        #针对类属性做一个计数+1

        Tool.count+=1

#创建工具(即实例对象)

tool1=Tool('刀')

tool2=Tool('斧子')

tool3 = Tool('镰刀')

tool4 = Tool('<empty>')

#打印计数

print('现在创建了%d把工具'%Tool.count)

◆类中的实例方法、动态方法、静态方法

★类方法:指针对类对象定义的方法(类方法作用:在类方法内部可以直接访问类属性或者调用其它的类方法)

语法如下:        @classmethod

def 类方法名(cls):

    pass

类方法需要用到修饰器@classmethod来标识,告诉解释器这是一个类方法。类方法的第一个参数是cls指由哪一个类调用的方法,方法内的cls指哪一个类的引用,这个参数与实例方法的第一个参数self类似。

类方法通过类名调用,调用类方法时不需要传递cls参数,在方法内部可以通过cls. 访问当前类的属性,也可以通过cls. 调用当前类的其它的类方法

修饰器:不会改变原有代码结构并增加额外的功能

调用:类名+方法名

【例】定义一个工具类,每件工具都有自己的name,在类中封装一个nasa.tool的类方法,输出使用当前的这个类以及创建对象的个数

class Tool(object):

    #定义变量count接收创建工具(对象)的总数

    count = 0

    def __init__(self,name):

        self.name = name

        #针对类属性做一个计数+1

        Tool.count+=1

    @classmethod

    def tool_count(cls):

            print('现在创建了%d个工具' % cls.count)

#创建工具(即实例对象)

tool1=Tool('刀')

tool2=Tool('斧子')

tool3 = Tool('镰刀')

tool4 = Tool('<empty>')

#打印计数

Tool.tool_count()

 

class Dragon(object):

    dog_count=0

    @staticmethod

    def run():

        #当print打印时不需要访问实例属性也不需要访问类属性的方法

        print('龙在飞!!!')

    def __init__(self,name):

        self.name=name

Dragon.run()

 

@叫做修饰器,装饰器的作用是为了不影响原有的功能基础上给原有的方法增添新的方法的功能

 

静态方法:方法前加了@staticmethod标识符,则称为静态方法,反之为实例方法。静态方法为类所用,可以通过对象来使用,也可通过类来使用,但一般常通过类名使用。这是因为静态方法只需要定义类,不必建立实例就可以直接使用,静态方法只能调用静态变量。

……………………………………………………………………………………………………………………………………………………………………

【例】需求:设计一个类,定义一个类属性记录游戏的历史最高分,定义一个实例属性记录当前游戏的玩家姓名;再定义一个静态方法显示游戏帮助信息,定义一个类方法显示历史记录,定义一个实例方法开始当前玩家的游戏。主程序步骤:1、查看游戏帮助2、查看历史最高分3、创建游戏对象,开始游戏4、游戏结束,查看游戏最高分

class Game(object):

    #类属性,游戏最高分

    top_score=0

    #实例属性,玩家姓名

    def __init__(self,player_name):

        self.player_name=player_name

    #静态方法,显示帮助信息

    @staticmethod#静态方法

    def show_help():

        print('帮助信息:选择一名人物作为你的第一个英雄,开始游戏')

    #类方法,显示历史记录,最高分

    @classmethod#类方法

    def show_top_score(cls):

        print('游戏最高分是%d'%cls.top_score)

#创建实例方法,开始游戏

    def start_game(self):

        print('提示:玩家[%s]开始游戏!!!'%self.player_name)

    #使用类名修改历史最高分

        Game.top_score=999

#1.查看游戏帮助

Game.show_help()#输出  帮助信息:选择一名人物作为你的第一个英雄,开始游戏

#2、查看历史最高分

Game.show_top_score()#输出  游戏最高分是0

#3、创建游戏对象,开始游戏

game=Game('kangkang')

game.start_game()#输出 提示:玩家[kangkang]开始游戏!!!

#4、游戏结束,查看游戏最高分

Game.show_top_score()#输出 游戏最高分是999

……………………………………………………………………………………………………………………………………………………………………

【例】

class People(object):

def __init__(self,name):

self.name = name #实例变量

def play(self): #实例方法

print(self.name + '打篮球')

            p = People('xiaowang')#创建对象

People.play() #类调用实例方法

p.play() #对象调用实例方法#类方法

@classmethod

def func1(cls):

cls.name1 = '我是一个类方法' #定义一个类变量

print (cls.name1)

#静态方法

@staticmethod

def func2():

print ('我是一个静态方法')

Python 中的实例方法、类方法、静态方法的区别

1、关于参数的区别

        实例方法:定义实例方法是最少有一个形参 ---> 实例对象,通常用self

        类方法:定义类方法的时候最少有一个形参 ---> 类对象,通常用cls

        静态方法:定义静态方法的时候可以不定义形参

2、关于方法定义时候添加装饰器的区别

        实例方法:不需要添加装饰器

        类方法:需要添加装饰器 ----> @classmethod

        静态方法:需要添加装饰器 ---> @staticmethod

3、调用:

        1.实例方法可以通过对象直接调用

        2.但是用类名调用的时候,需要创建一个对象,并且在传递参数的时候要将对象传递进去

        3.类方法可以通过类名直接调用,也可以通过对象来调用

        4.静态方法可以通过类名直接调用,也可以通过对象来调用

4、访问对象的区别

实例方法在方法内部需要访问实例属性(实例方法的内部可以使用 类名. 格式访问类属性)

类方法在方法内部只需要访问类属性

静态方法在方法内部不需要访问实例属性和类属性

【问】若方法内部既要访问实例属性又要访问类属性,应该定义什么方法?

实例方法,因为类只有一个,在实例方法的内部可以使用类名访问属性

5、补充

  1.静态方法不可以继承  

  2.类方法不能访问实例变量,只能访问类变量

5.5.3  补充

5.5.3.1   __del__方法

◆在python中当使用类名()创建对象时,为对象分配完空间后,自动调用__init__方法.当一个对象被从内存中销毁前,会自动调用__del__方法

◆应用场景:__init__改造初始化方法,可以让创建对象更加灵活

__del__如果希望在对象被销毁前,再做一些事情,可以使用__del__方法

◆生命周期:一个对象从调用类名()创建,生命周期开始;一个对象的__del__方法一旦被调用,生命周期结束。在对象的生命周期内,可以访问对象属性或者让对象调用方法。

class Cat:

    def __init__(self,new_name):

        self.name=new_name

        print('%s来了'%self.name)

    def __del__(self):

        print('%s去了'%self.name)

#tom是一个全局变量

tom=Cat('Tom')

print(tom.name)

#del关键字可以删除一个对象

del tom

print('-'*50)#打印符号“-”50个

print(tom.name)

5.5.3.2   __str__方法(重要)

◆在python中,使用print输出对象变量,默认情况下,会传出这个变量引用的对象是由哪一类创建的对象,以及在内存中的地址(十六进制表示)。如果希望使用print输出对象变量时,能够自定义打印自定义的内容,就可以使用__str__内置方法

注意:__str__方法必须返回一个字符串

class Cat:

    def __init__(self,new_name):

        self.name=new_name

        print('%s来了'%self.name)

    def __del__(self):

        print('%s去了'%self.name)

    def __str__(self):

        return '我是小猫[%s]'%self.name

tom=Cat('Tom')

print(tom)

#输出 Tom来了

我是小猫[Tom]

Tom去了

5.5.3.3   身份运算符

◆身份运算符:用于比较两个对象的内存地址是否一致,是否是对同一个对象的引用.在Python中针对None进行比较时,建议使用is判断。

is:用来判断两个标识符是不是引用同一个对象(x is y 类似 id(x)==id(y))

is not:判断两个标识符是不是引用不同对象(x is  not y 类似 id(a)!=id(b))

is与==的区别

is用于判断两个变量的引用对象是否为同一个

==用于判断引用变量的值是否相等

5.5.3.4   私有属性和私有方法

◆私有属性和私有方法应用场景:在实际开发中,对象的某些属性或方法可能只希望在对象内部被使用,而不希望在外部被访问到。

◆私有属性:对象不希望公开的属性

◆私有方法:对象不希望公开的方法

◆在属性名或者方法名前增加两个下划线,这种形式的定义就是私有属性或私有方法。

◆在对象的内部,是可以访问对象的私有属性和方法的,在对象的外部,不能访问对象的私有属性和方法

【在对象的外部】

class Women:

    def __init__(self,name):

        self.name = name

        #不能访问年龄

        self.__age=18

    def secret(self):

        print('我的年龄是%d'%self.__age)

lily=Women('xiaoqiao')

lily.secret()#输出 我的年龄是18

 

class Women:

    def __init__(self,name):

        self.name = name

        #不能访问年龄

        self.__age=18

    def secret(self):

#在对象方法内部可以访问对象私有属性

        print('%s年龄是%d'%(self.name,self.__age))

lily=Women('xiaoqiao')

print(lily.age)#调用属性,输出18

lily.__secret()#外部不能直接访问或调用私有属性

lily.secret()#调用方法输出xiaoqiao年龄是18

◆伪私有属性和方法(科普)

注意:在日常开发中,不要使用该方式访问对象的私有属性或私有方法。

结论:python中并没有真正意义上的私有,在给属性、方法命名时,实际上是对名称做的一些特殊处理,使得外界无法访问。处理方式是在名称前加_类名即_类名__名称

【例】

class Women:

    def __init__(self,name):

        self.name = name

        #不能访问年龄

        self.__age=18

    def secret(self):

        print('%s年龄是%d'%(self.name,self.__age))

lily=Women('xiaoqiao')

#私有属性,外部不能直接访问,但可以通过‘_类名__名称’访问

print(lily._Women__age)#输出18

#私有方法,外部不能直接访问,但可以通过‘_类名__名称’访问

lily._Women__secret()#输出xiaoqiao年龄是18

5.5.3.5(拓展)   枚举值

起初python中并未内置枚举(Enumerate)(enum)类型,枚举是在python3.4中添加的新功能(3.4版本前可以使用枚举,但需要下载插件pip install enum安装使用,3.4后不需要下载插件可直接使用)

◆枚举定义:指一系列符号名称的集合,集合中每个元素要保证唯一性和不可变性。

因此我们可以对枚举中的元素进行恒等比较。通俗来讲枚举是一系列常量对集合,是可迭代的。

【例】        from enum import Enum

class DragonColor(Enum):

    Mon='red'

    Tue='yellow'

    Wed='black'

    Thu='black'

    Fri='white'

#访问枚举成员

print(DragonColor.Mon)#输出 DragonColor.Mon

#枚举成员名称

print(DragonColor.Mon.name)#输出 Mon

#枚举成员值

print(DragonColor.Mon.value)#输出 red

……………………………………………………………………………………………………………………………………………………………………

枚举迭代:    from enum import Enum

class DragonColor(Enum):

    Mon='red'

    Tue='yellow'

    Wed='black'

    Thu='pink'

      Fri='white'

for dragon in DragonColor:

                     #枚举成员

                     print(dragon)#输出 DragonColor.Mon

DragonColor.Tue

DragonColor.Wed

DragonColor.Thu

DragonColor.Fri

                      #枚举成员名称

                      print(dragon.name)#输出 Mon

Tue

Wed

Thu

Fri

                       # #枚举成员值

                       print(dragon.value)#输出red

yellow

black

pink

white

唯一unique:

from enum import Enum,unique

                          @unique

                          class DragonColor(Enum):

                                 Mon='red'

                                 Tue='yellow'

                                 Wed='black'

                                 Thu='pink'

                                  Fri='white'

5.5.4  类的三大特性(面向对象的三大特征)

5.5.4.1  封装特性

类里面不光有属性还有方法。这种将属性通过方法直接在类内部操作的形式叫做封装。这里的封装是把属性封装在类内部。【根据职责将属性和方法封装到一个抽象的类中】

具体代码如下:

class People(object):

def __init__(self,name):

self.__name = name

 def setName(self,newname)

self.__name = newname

def getName(self):

return self.__name

p = People("xiaowang")

print(p.__name) #报错

 p.setName("xiaoxiaoming")

 print(p.getName())继承特性

5.5.4.2  继承特性

继承定义

类的继承是面向对象程序设计的一个重要思想,继承时子类可以继承父类的内容,包括成员变量和成员函数。在继承中一个类被另外一个类继承这个类称之为父类或基类,则另外一个类则为子类或派生类。类从父类中继承或派生。

【继承实现代码的重用(重复使用),相同的代码不需要重复的编写。子类拥有父类的所有方法和属性,子类继承父类,可直接享受父类中已经封装好的方法,不需要再次开发。子类中应该根据职责,封装子类特有的属性和方法】

◆继承的传递性

C类从B类继承,B类从A类继承,则C类具有B类和A类所有属性和方法。即子类拥有父类以及父类的父类中封装的所有方法和属性。

◆继承的语法:

class 类名(父类名):

      pass

具体代码示例:

class Father(object): #Father继承object类

def rich_man(self):

print '有钱'

class Son(Father):

def __init__(self):

Father.__init__(self) #继承父类的构造函数

def car(self):

print '喜欢跑车'

s = Son() #根据子类创建对象多态特性  

单继承

一个对象使用另一个对象的属性和方法,被继承的类也称父类

(1)父类与子类的方法不一样

(2)子类拥有与父类相同的方法。当子类拥有与父类相同的方法,通过子类实例调用该方法后,执行的是子类下的方法

(3)子类拥有与父类相同的方法和属性

Ø基本语法:

class 类名(父类名):

                     pass

◆多继承

多继承就是一个子类继承多个父类【子类拥有多个父类并且具有所有父类的属性和方法】

Ø 如果不同的两个父类出现了相同名称的属性或者方法,子类会继承谁的属性或者方法?

基本语法:

class 子类名(父类名1,父类名2)

                       pass

由上面实例可知如下

(1)python3中都是新式类:广度优先,从父类中查询对应的方法,查询到第一个满足的方法之后就直接返回

                object

                |

                A(object)

                |

    A_1(A) --> A_2(A)

    |

    Test(A_1, A_2)

(2)python2中的经典类:深度优先

            A

            |

    A  --> A_2(A)

    |

    A_1(A)

    |

    Test(A_1, A_2)

5.5.4.3  多态特性

多态是以继承和重写父类方法为前提,对所有子类实例化产生的对象调用相同的方法,执行产生不同的执行结果。【不同的子类对象调用相同的方法,产生不同的执行结果,增加代码的灵活度】 

例如同样是人,但是当问起一个人的职业时会有不同的结果,可能是软件测试工程师,可能是HR

在Dog类中封装方法game,普通的狗只是简单的玩耍,定义xiaotianquan继承Dog并重写game方法;定义Person类,并封装一个和狗子玩的方法(在方法内部,直接让狗子对象调用game方法。)

【例】

#创建普通狗对象

class Dog(object):

    def __init__(self,name):

        self.name = name

    def game(self):

        print('%s蹦蹦跳跳的玩耍!!!'%self.name)

#创建XiaoTianQuan狗对象

class XiaoTianQuan(Dog):

    def game(self):

        print('%s在空中腾云驾雾!!!'%self.name)

class Person(object):

    def __init__(self,name):

        self.name=name

    def game_with_dog(self,dog):

        print('%s和%s快乐的玩耍'%(self.name,dog.name))

#Person类只需要让狗对象调用game方法,game方法是在Dog父类中定义

        dog.game()

#创建两个狗对象

tom=XiaoTianQuan('飞天阿福')

laifu=Dog('来福')

#创建一个康康人对象

lily=Person('康康')

#在程序执行时,传入不同的狗对象实参,就会产生不同的执行效果

lily.game_with_dog(tom)#输出  康康和飞天阿福快乐的玩耍 飞天阿福在空中腾云驾雾!!!

# 康康调用和狗子玩的方法

lily.game_with_dog(laifu)#输出 康康和来福快乐的玩耍 来福蹦蹦跳跳的玩耍!!!

◆一个对象的属性和行为不是由他所继承的父类决定的,而是由其本身包含的属性和方法决定的。

class Animal(object):

def talk(self):

print('我是动物')

class Cat(Animal):

def talk(self):

print('喵喵')

class Dog(Animal):

def talk(self):

print('汪汪')

c = Cat()

c.talk()

Python中多态的特点

  1、只关心对象的实例方法是否同名,不关心对象所属的类型;

  2、对象所属的类之间,继承关系可有可无;

  3、多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强;

  4、多态是调用方法的技巧,不会影响到类的内部设计。

◆【拓展】

  Java中多态性的表现: 多态性,可以理解为一个事物的多种形态。同样python中也支持多态,但是是有限的的支持多态性,主要是因为python中变量的使用不用声明,所以不存在父类引用指向子类对象的多态体现,同时python不支持重载。在python中 多态的使用不如Java中那么明显,所以python中刻意谈到多态的意义不是特别大。

posted @ 2022-08-23 10:31  AllWillGoOn  阅读(291)  评论(0编辑  收藏  举报