当前位置:   article > 正文

Python简介_python使用变量前要先定义数据类型。

python使用变量前要先定义数据类型。

1.认识Python

Python的特点

Python是完全面向对象的语言 

函数、模块、数字、字符串都是对象,在Python中一切皆对象
完全支持继承、重载、多重继承
支持重载运算符,也支持泛型设计

拥有一个强大的标准库

Python 语言的核心只包含数字、字符串、列表、字典、文件等常见类型和函数,而由Python标准库提供了系统管理、网络通信、文本处理、数据库接口、图形系统、XML 处理等额外的功能.

Python社区提供了大量的第三方模块,使用方式与标准库类似

它们的功能覆盖科学计算、人工智能、机器学习、Web 开发、数据库接口、图形系统 多个领域.

编译与解释

编译(静态语言):程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如 C、C++、java

解释(脚本语言):以文本方式存储程序代码,会将代码一句一句直接运行。在发布程序时,看起来省了道编译工序,但是在运行程序的时候,必须先解释再运行(将源代码逐条翻译成目标代码同时逐条运行),如Python 、Java Script、PHP

  • 速度 —— 编译型语言比解释型语言执行速度快
  • 跨平台性 —— 解释型语言比编译型语言跨平台性好

执行python程序的方式

(1)解释器python/python3

           Python 2.x 使用的解释器是 ipython
           Python 3.x 使用的解释器是 ipython3

(2)交互式运行Python程序:对每个输入语句即时运行结果

    默认:python shell 

    优点:适合于学习/验证 Python 语法或者局部代码

    缺点:•代码不能保存
               •不适合运行太大的程序

    IPython:◦支持自动补全
                    ◦自动缩进
                    ◦支持 bash shell 命令
                    ◦内置了许多很有用的功能和函数

    退出解释器:①直接输入 exit②按热键 ctrl + d,IPython 会询问是否退出解释器

(3)Python的IDE - PyCharm:文件式编程,批量处理一组语句并运行结果,这是编程的主要方式

集成开发环境:图形用户界面、代码编辑器(支持代码补全/自动缩进)、编译器/解释器、调试器(断点/单步执行)

  • 一个项目通常会包含 很多源文件
  • 每个 源文件 的代码行数是有限的,通常在几百行之内
  • 每个源文件各司其职,共同完成复杂的业务功能

(4)cmd运行python脚本

前置条件:先在windows设置python环境变量

进入cmd:

  1. cd  D:\python+selenium\TestCase    (py文件存放的路径)
  2. 输入python   **.py  直接执行某某py文件,比如:python “E:\private\...\TextProBarV2.py

Python和pip 

首先下载安装好python,命令行判断:

python是否安装成功和安装版本:输入python

检查是否安装了pip:输入pip

注意配置好环境变量(Python安装地址)。

环境变量分为系统环境变量和用户环境变量。

正常所说的环境变量是指系统环境变量,对所有用户起作用,而用户环境变量只对当前用户起作用,如果此电脑登入了另外个用户账号,那配置之前账号的用户环境变量就对另外个用户账号不起作用。

优先级高低是:系统变量 > 用户变量。也就是说,环境变量设置相同,先在系统变量里面找,找不到再到用户变量里面去找。

而在一个环境变量里面,如果有多个值,优先级是最前面的或者最上面的项优先级高。比如在Path环境变量里面,同时设置了python2.7和python3.6的路径,结果是先设置的起作用,这对于切换使用不同版本的软件比较方便,只需要上移/下移就行。

举例:

Python和pip环境变量,添加到path:

C:\Program Files\Python380

C:\Program Files\Python380\Scripts

pip

pip <command> [options]

进入cmd,输入pip,可以查看所有指令。

常用指令:

pip install package-name,用pip来安装第三方的包

  • pip install -r requirements.txt 的作用是从一个文本文件 requirements.txt 中安装所需的 Python 包。一般情况下,项目提供者会在 requirements.txt 文件中列出所有项目所依赖的 Python 包及其版本号,使用这个命令可以方便地安装这些依赖并满足项目运行的需要。

pip install matplotlib==3.4.1,安装指定版本的第三方的包

pip uninstall package_name,卸载某个包

pip install --upgrade package_name# 或者是pip install -U package_name,更新某个包

pip show -f requests,查看指定包的信息

pip list -o 查看需要被升级的包

pip list 查看当前项目安装的包

2. 基础语法

变量

概念:变量是用来保存和表示数据的占位符号

每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建

创建一个变量,包括

  1. 变量的名称
  2. 变量保存的数据
  3. 变量存储数据的类型
  4. 变量的地址(标示)

使用(type)函数可以查看一个变量的类型

(1)数字型

整数(int)

%:取余

//:求整除

pow(x,y)  :计算x^y

pow(x,y[,z]) : 幂余,x和y是必选参数,z是可选参数;如果使用了参数z,中括号必须去掉,即power(x,y,z),其结果是x的y次方再对z求余数,但是这种方式比power(x,y) % z的执行效率要高

abs(x) : 求绝对值

divmod(x,y), 商余,(x//y,x%y)结果为(商,余)

浮点数(float)

注意:浮点数计算存在不确定性位数,但这不是bug;round(x,d)  :对x四舍五入,d是小数截取位数

科学计数法表示: <a>e<b>   表示a*(10^b)

布尔(bool)

“布尔”数据类型只有两种值:True 和False。

        ◾真 True ,非 0 数

        ◾假 False ,0

比较操作符

== 等于,!= 不等于,< 小于,> 大于,<= 小于等于,>= 大于等于,比较两个值,求值为一个布尔值。

>>> 42 == 42
True

布尔操作符

①二元布尔操作符

and 和or 操作符总是接受两个布尔值(或表达式),所以它们被认为是“二元”操作符。如果两个布尔值都为True,and 操作符就将表达式求值为True,否则求值为False。另一方面,只要有一个布尔值为真,or 操作符就将表达式求值为True。如果都是False,所求值为False。

>>> True and True
True
>>> True and False
False

>>> print(0 or 1 and True)
True

②not 操作符

not 操作符只作用于一个布尔值(或表达式),not 操作符求值为相反的布尔值。

>>> not True
False

③混合布尔和比较操作符

>>> (4 < 5) and (5 < 6)
True
>>> (4 < 5) and (9 < 6)
False

复数型 (complex)

a+bj  ; a-bj 

注意:不同数字类型混合运算,结果为“最宽”类型

(2)非数字型

字符串、列表、元组、字典、set集合,详见以下链接:

Python变量——字符串、列表、元组、字典、set_python 字符串 *-CSDN博客

(3)变量进阶

变量的引用

概念:
•变量 和 数据 是分开存储的
•数据 保存在内存中的一个位置
•变量 中保存着数据在内存中的地址
•变量 中 记录数据的地址,就叫做 引用
•使用 id() 函数可以查看变量中保存数据所在的 内存地址(每次运行脚本时,id会变化)

注意:如果变量已经被定义,当给一个变量赋值的时候,本质上是 修改了数据的引用
•变量 不再 对之前的数据引用
•变量 改为 对新赋值的数据引用

在 Python 中,函数的 实参/返回值 都是是靠 引用 来传递来的

可变和不可变类型

不可见类型,内存中的数据不允许被修改。value(值)一旦改变,id(内存地址)也改变,则称为不可变类型(id变,意味着创建了新的内存空间)。
◦数字类型 int, bool, float, complex, long(2.x)

  1. #id
  2. a = 1
  3. print(id(a),type(a)) #1452422928 <class 'int'>
  4. a = 2
  5. print(id(a),type(a)) #1452422944 <class 'int'>
  6. #float
  7. b = 1.23
  8. print(id(b),type(b)) #13260288 <class 'float'>
  9. b = 2.59
  10. print(id(b),type(b)) #13260048 <class 'float'>
  11. #复数型
  12. c = 1+2j
  13. print(id(c),type(c)) #17454936 <class 'complex'>
  14. c = 1-2j
  15. print(id(c),type(c)) #17455608 <class 'complex'>
  16. #bool
  17. d = True
  18. print(id(d),type(d)) #1452241744 <class 'bool'>
  19. d = False
  20. print(id(d),type(d)) #1452241760 <class 'bool'>

◦字符串 str,改变string值后,id也变了

  1. str = "test string"
  2. print(id(str)) #17515288
  3. str = "change"
  4. print(id(str)) #16472544

◦元组 tuple,改变值后,id也变了

  1. info_tuple = ("zhangsan", 18, 1.75)
  2. print(id(info_tuple)) # 15016344
  3. info_tuple = info_tuple + (1,2,3)
  4. print(info_tuple)#('zhangsan', 18, 1.75, 1, 2, 3)
  5. print(id(info_tuple)) #14083496

◦日期

  1. #日期
  2. import datetime
  3. oneday = datetime.date.today()
  4. print(oneday) #2022-03-23
  5. print(id(oneday),type(oneday))# 10508792 <class 'datetime.date'>
  6. oneday = datetime.date.today() - oneday
  7. print(oneday) #0:00:00
  8. print(id(oneday),type(oneday)) #10509176 <class 'datetime.timedelta'>

可变类型:在id(内存地址)不变的情况下,value(值)可以变,则称为可变类型

  • 列表 list,改变列表值后,id不变
  1. l = [1,2,3,4,5]
  2. print(id(l)) # 13642288
  3. print(l[4]) #5
  4. l[4] = 9
  5. print(id(l)) # 13642288
  • 字典 dict,改变value后,id不变(注意:字典的 key 只能使用不可变类型的数据)
  1. info = {"name":"Mary","age":"26"}
  2. print(id(info)) #18251528
  3. info["name"] = "Cindy"
  4. print(id(info)) #18251528
  •  set
  1. set1={1,2,1,3,4,5,6,7}
  2. print(id(set1),type(set1))#21787872 <class 'set'>
  3. set1={1,2,3,8,9,7,10}
  4. print(id(set1),type(set1))#21787872 <class 'set'>

可变类型的数据变化,是通过 方法 来实现的。如果给一个可变类型的变量,赋值了一个新的数据,引用会修改
•变量 不再 对之前的数据引用
•变量 改为 对新赋值的数据引用

身份运算符

身份运算符用于 比较 两个对象的 内存地址 是否一致 —— 是否是对同一个对象的引用

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

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

is 与 == 区别:
is 用于判断 两个变量 引用对象是否为同一个 
== 用于判断 引用变量的值 是否相等

哈希 (hash)

Python 中内置有一个名字叫做 hash() 的函数,获取一个对象的哈希值。
◦接收一个 不可变类型 的数据作为 参数(list,dictionary,set都是unhashable type)
◦返回 结果是一个 整数

哈希 是一种 算法,其作用就是提取数据的 特征码(指纹) 
◦相同的内容 得到 相同的结果
◦不同的内容 得到 不同的结果

在 Python 中,设置字典的 键值对 时,会首先对 key(字典中的key也是不可变数据类型) 进行 hash 以决定如何在内存中保存字典的数据,以方便后续对字典的操作:增、删、改、查。

  1. str = "apple"
  2. print(hash(str)) #-1877658494
  3. print(hash(1.23)) #579820504

局部变量和全局变量

局部变量:

•局部变量 是在 函数内部 定义的变量,只能在函数内部使用
•函数执行结束后,函数内部的局部变量,会被系统回收
•不同的函数,可以定义相同的名字的局部变量,但是 彼此之间 不会产生影响

作用:在函数内部使用,临时 保存 函数内部需要使用的数据

局部变量的生命周期
•所谓 生命周期 就是变量从 被创建 到 被系统回收 的过程
•局部变量 在 函数执行时 才会被创建
•函数执行结束后 局部变量 被系统回收
•局部变量在生命周期 内,可以用来存储 函数内部临时使用到的数据

全局变量:

全局变量 是在 函数外部定义 的变量,所有函数内部都可以使用这个变量

注意:函数执行时,需要处理变量时 会:
1.首先 查找 函数内部 是否存在 指定名称 的局部变量,如果有,直接使用
2.如果没有,查找 函数外部 是否存在 指定名称 的全局变量,如果有,直接使用
3.如果还没有,程序报错!

注意:
1.函数不能直接修改 全局变量的引用;
•如果在函数中需要修改全局变量,需要使用 global 进行声明  
  global num
  # 只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
  num = 100
•为了保证所有的函数都能够正确使用到全局变量,应该 将全局变量定义在其他函数的上方

命名

命名规则:

  1. 大小写字母、数字、下划线
  2. 首字母不能是数字
  3. 大小写敏感
  4. 不与保留字相同
  5. 不能包含空格

在定义变量时,为了保证代码格式,= 的左右应该各保留一个空格

在 Python 中,如果变量名需要由两个或多个单词组成时,

  • 每个单词都使用小写字母,单词与单词之间使用 _下划线 连接(例如:first_name、last_name、qq_number、qq_password)
  • 小驼峰式命名法:第一个单词以小写字母开始,后续单词的首字母大写(例如:firstName、lastName);
  • 大驼峰式命名法:每一个单词的首字母都采用大写字母(例如:FirstName、LastName、CamelCase )

保留字/关键字(33个)

被编程语言内部定义并保留使用的标识符:and,as,assert,break,class,continue,def,del,elif,else,expect,finally,for,from,False,global,if,is,import,in,lambda,not,nonlocal,None,or,pass,return,raise,try,True,while,with,yeild

标识符/关键字后面不需要使用括号

语法:每个保留字所在行最后存在一个冒号(:),比如def,class后面

运算符

算术运算符:+ - * / %(取余)  //(整除) ** (求次方)

逻辑运算符:与(and),或(or),非(not)

成员运算符:

  • in:判断一个元素是否在序列中;
  • not in : 如果在指定的序列中没有找到值返回True,否则返回False

转义符

\b : 回退

\n  :  换行

\r : 回车

\t:横向制表符,在控制台输出一个 制表符,协助在输出文本时 垂直方向 保持对齐

\\:反斜杠符号

\' :单引号 

\": 双引号 

缩进

Python以缩进表达程序的格式框架,所以要严格控制缩进,一般是4个空格,或者一个 tab 键。

注意:在 Python 开发中,Tab 和空格不要混用!

注释

单行注释:  # 追加说明文字  注意:尽量在文字前面打个空格  在# 号前面需要追加两个空格。例如 print()  # 注释

多行注释语法:

                       """
               注释内容
                       """

3.面向对象编程

面向对象编程 —— Object Oriented Programming 简写 OOP。

面向对象与面向过程:

面向过程 面向对象
怎么做1.把完成某一个需求的所有步骤从头到尾逐步实现
2.根据开发需求,将某些功能独立 的代码封装成一个又一个 函数
3.最后完成的代码,就是顺序地调用不同的函数
相比较函数,面向对象是更大的封装,根据职责在一个对象中 封装多个方法
1.在完成某一个需求前,首先确定职责 —— 要做的事情(方法)
2.根据职责确定不同的对象,在对象内部封装不同的方法(多个)
3.最后完成的代码,就是顺序地让不同的对象调用不同的方法
特点1.注重步骤与过程,不注重职责分工
2.如果需求复杂,代码会变得很复杂
3.开发复杂项目,没有固定的套路,开发难度很大
1.注重对象和职责,不同的对象承担不同的职责
2.更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路
3.需要在面向过程基础上,再学习一些面向对象的语法
面向对象是更大的封装,在一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法了

3.1类

(1)概念

类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用。
 ◦特征 被称为属性
 ◦行为 被称为方法

(2)类的设计

类名:命名方法:首字母大写

           名词提炼法 :分析整个业务流程,出现的名词,通常就是找到的类

属性:对对象的特征描述,通常可以定义成属性

方法:对象具有的行为(动词),通常可以定义成方法。类中的函数称为方法,函数的一切都适用于方法,二者之间有一个重要的差别就是调用方式不同。

定义只包含方法的类:

  1. class 类名:
  2.     def 方法1(self, 参数列表):
  3.         pass 
  4.     def 方法2(self):
  5.         pass

3.2对象

对象是由类创建出来的一个具体存在,可以直接使用。

由哪一个类创建出来的对象,就拥有在哪一个类中定义的属性和方法 

创建对象:对象变量 = 类名(),例如:my_dog = Dog()

类和对象的关系

类是模板,对象是根据类这个模板创建出来的,应该先有类,再有对象
•类 只有一个,而对象可以有很多个 
     ◦不同的对象之间属性可能会各不相同
•类 中定义了什么属性和方法,对象中就有什么属性和方法,不可能多,也不可能少

3.3方法

初始化方法__init__ ()

当使用类名() 创建对象时,会自动执行以下操作: 

  • 为对象在内存中分配空间 — 创建对象
  • 为对象的属性设置初始值 — 初始化方法

这个初始化方法就是 __init__ 方法,__init__ 是对象的内置方法(类是一个特殊的对象 —— 类对象,如果不在类中定义def __init__(self),会使用默认的内置方法,如果在类中定义def __init__(self),相当于重构)。__init__ 方法是专门用来定义一个类具有哪些属性的方法。每当根据类创建新实例时,Python都会自动运行这个方法(其他自定义方法需要调用才能使用,要调用方法,可指定实例的名称和要调用的方法:对象.方法名())。

初始化方法__init__ ()开头和末尾有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。

在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对 __init__ 方法进行 改造 

  1. 把希望设置的属性值,定义成 __init__ 方法的参数
  2. 在方法内部使用 self.属性 = 形参 接收外部传递的参数,属性可以任意命名
  3. 在创建对象时,使用 类名(属性1, 属性2...) 调用

举例1:

  1. class Cat:
  2.     def __init__(self, name):
  3.         print("初始化方法 %s" % name)
  4.         self.name = name  
  5. tom = Cat("Tom")
  6. lazy_cat = Cat("大懒猫")

 举例2:给属性设置默认值

类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。在方法__init__()中制定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。    

  1. def __init__(self):
  2. """初始化游戏的静态设置"""
  3. #屏幕设置
  4. self.screen_width = 1200
  5. self.screen_height = 800
  6. self.bg_color = (230,230,230)
  7. #飞船设置
  8. self.ship_limit = 3
  9. #子弹设置
  10. self.bullet_width = 3
  11. self.bullet_height = 15
  12. self.bullet_color = 60,60,60
  13. #将未消失的子弹设置为最大为3颗
  14. self.bullets_allowed = 3
  15. #外星人设置
  16. self.fleet_drop_speed = 10
  17. #以什么样的速度加快游戏节奏
  18. self.speed_up_scale = 1.1
  19. #外星人点数的提高速度
  20. self.score_scale = 1.5

方法中的形参self

python调用__init__()来创建实例时,将自动传入实参self。每个与类相关联的方法调用都自动传实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。例如,我们将通过实参向Cat()传递名字和年龄,self会自动传递,因此我们不需要传递它。当我们根据Cat类创建实例时,都只需要给后面的形参(比如:name,age)提供值。
以self为前缀的变量都可以供类中所有的方法使用,我们也可以通过类的任何实例来访问这些变量。
self.name(实参) = name(形参)获取存储在形参name中的值,并将其存储到变量name中,然后该变量被关联到当前创建的实例。像这样可以通过实例访问的变量称为属性。( self.属性 = 形参)

  1. class Complex:
  2. def __init__(self, realpart, imagpart):
  3. self.r = realpart
  4. self.i = imagpart
  5. x = Complex(3.0, -4.5)
  6. print(x.r, x.i)
  7. #结果:3.0 -4.5

   •在类的外部,通过变量名(即对象名). 访问对象的属性和方法
   •在类封装的方法中通过self.访问对象的属性和方法

总结:
由哪一个对象调用的方法,方法内的self就是哪一个对象的引用.

  1. 在类封装的方法内部,self 就表示当前调用方法的对象自己
  • 调用方法时,不需要传递 self 参数
  • 在方法内部 ◦可以通过 self. 访问对象的属性 ◦也可以通过 self. 调用其他的对象方法

   self. 调用其他的对象方法举例:

私有属性和私有方法

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

定义方式:在定义属性或方法时,在 属性名或者方法名前增加两下划线,定义的就是私有属性或方法,如:self.__age = 18

类属性和类方法

①术语:实例

  1.创建出来的对象叫做类的实例
  2.创建对象的动作叫做实例化
  3.对象的属性叫做实例属性
  4.对象调用的方法叫做实例方法

②类是一个特殊的对象

Python中一切皆对象

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

③类属性和实例属性

•类属性就是给类对象定义的属性,通常用来记录与这个类相关的特征
•类属性不会用于记录具体对象的特征

④类方法和静态方法

类方法

  类方法就是针对类对象定义的方法,在类方法内部可以直接访问类属性或者调用其他的类方法。

  类方法和普通方法的区别是,类方法只能访问类变量,不能访问实例变量。

  语法:

  1. @classmethod
  2. def 类方法名(cls):
  3.     pass

•类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法

•类方法的第一个参数应该是 cls 
        ◦由哪一个类调用的方法,方法内的cls就是哪一个类的引用
        ◦这个参数和实例方法的第一个参数self 类似
        ◦提示使用其他名称也可以,不过习惯使用 cls

•通过类名. 调用类方法,调用方法时,不需要传递 cls 参数

在方法内部 
◦可以通过 cls. 访问类的属性
◦也可以通过 cls. 调用其他的类方法

静态方法

•在开发时,如果需要在类中封装一个方法,这个方法:
         ◦既不需要访问实例属性或者调用实例方法
         ◦也不需要访问类属性或者调用类方法
•这个时候,可以把这个方法封装成一个静态方法

语法如下

  1. @staticmethod
  2. def 静态方法名():
  3.     pass

•静态方法需要用修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法
•通过类名. 调用静态方法

举例:

  1. class Dog(object):    
  2.     # 狗对象计数
  3.     dog_count = 0    
  4.     @staticmethod
  5.     def run():        
  6.         # 不需要访问实例属性也不需要访问类属性的方法
  7.         print("狗在跑...")
  8.     def __init__(self, name):
  9.         self.name = name

普通方法、类方法和静态方法对比:

根据人们的惯用用法,self一般是在实例方法中使用,而cls则一般在类方法中使用,在静态方法中则不需要使用一个默认参数;

静态方法和类方法都需要使用修饰器,分别使用的是staticmethod和classmethod;

普通方法不能通过类名调用,但是静态方法和类方法是可以的。普通方法通过对象调用。

3.4继承

面向对象三大特性:继承、封装、多态。

(1)概念

继承,实现代码的重用,相同的代码不需要重复的编写

概念:子类拥有父类的所有方法和属性

语法:•子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
           •子类中应该根据职责,封装子类特有的属性和方法

           继承的语法:  class 类名(父类名):

           术语:Dog 类是 Animal 类的子类,Animal 类是 Dog 类的父类,Dog 类从 Animal 类继承

                      Dog 类是 Animal 类的派生类,Animal 类是 Dog 类的基类,Dog 类从 Animal 类派生

 继承的传递性:子类拥有父类以及父类的父类中封装的所有属性和方法

(2)重写

当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)两种情况:

①覆盖父类的方法

    •如果在开发中,父类的方法实现和子类的方法实现完全不同
    •就可以使用覆盖的方式,在子类中重新编写父类的方法实现

具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现
重写之后,在运行时,只会调用子类中重写的方法,而不再会调用父类封装的方法

②对父类方法进行扩展

  1.在子类中重写父类的方法
  2.在需要的位置使用super().父类方法来调用父类方法的执行
  3.代码其他的位置针对子类的需求,给子类定义属性和方法,编写子类特有的代码实现

  super:•在Python中super是一个特殊的类
               •super() 就是使用super类创建出来的对象
               •最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现

   super()._init_() 调用父类的方法_init_()

  1. class Bullet(Sprite):
  2.     """一个对飞船发射的子弹进行管理的类"""
  3.     def __init__(self,ai_settings,screen,ship):
  4.         """在飞船所处的位置创建一个子弹对象"""
  5.         super().__init__()
  6.         self.screen = screen
  7.  
  8.         # 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
  9.         self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
  10.         self.rect.centerx = ship.rect.centerx
  11.         self.rect.top = ship.rect.top
  12.  
  13.         # 存储用小数表示的子弹位置
  14.         self.y = float(self.rect.y)
  15.  
  16.         self.color = ai_settings.bullet_color
  17.         self.speed_factor = ai_settings.bullet_speed_factor
  18.     def update(self):
  19.         """向上移动子弹"""
  20.         #更新表示子弹位置的小数值
  21.         self.y -= self.speed_factor
  22.         #更新表示子弹的rect位置
  23.         self.rect.y =self.y
  24.     def draw_bullet(self):
  25.         """在屏幕上绘制子弹"""
  26.         pygame.draw.rect(self.screen,self.color,self.rect)

(3)将实例用作属性

    有时候,根据需要,我们可以把很多属性和方法提取出来,放到一个类中。

    举例说明:把很多属性和方法另一个类Battery中,并将一个Battery实例用作ElectricCar类的一个属性。

  1. class Car():
  2.     --snip--
  3. class Battery():
  4.     def _init_(self,battery_size=70):
  5.         self.battery_size = battery_size
  6. class ElectricCar(Car):
  7.     def _init_():
  8.     super()._init_(make,model,year)
  9.     #将实例用作属性
  10.     self.battery = Battery()
  11. my_tesla = ElectricCar('tesla','model s','2018')

(4)父类的私有属性和私有方法

  1.子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
  2.子类对象可以通过父类的公有方法间接访问到私有属性或私有方法

•私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
•私有属性、方法通常用于做一些内部的事情

(5)多继承

概念:子类可以拥有多个父类,并且具有所有父类的属性和方法
        例如:孩子会继承自己父亲和母亲的特性

语法:class 子类名(父类名1, 父类名2...)
              pass

注意事项:开发时,应该尽量避免容易产生混淆的情况—— 如果 父类之间存在同名的属性或者方法,应该尽量避免使用多继承。

3.5封装

1.封装是面向对象编程的一大特点
2.面向对象编程的第一步—— 将属性和方法封装到一个抽象的类中
3.外界使用类创建对象,然后让对象调用方法
4.对象方法的细节都被封装在类的内部

模块化和参数化:

假设要实现关于126邮箱的自动化测试项目那么可能每条用例都要有登录和退出动作,大部分测试用例都是在登录后进行的,例如:发邮件、查看、删除、搜索邮件等操作。

此时,创建一个module.py文件来存放登录和退出操作(模块化)。测试数据会不同,将login()方法参数化。

  1. class Mail:
  2. def __init__(self,driver):
  3. self.driver = driver
  4. def login(self,username,password):
  5. """登录"""
  6. login_frame = self.driver.find_element_by_css_selector('iframe[id^="x-URS-iframe"]')
  7. self.driver.switch_to.frame(login_frame)
  8. self.driver.find_element_by_name("email").clear()
  9. self.driver.find_element_by_name("email").send_keys("username")
  10. self.driver.find_element_by_name("password").clear()
  11. self.driver.find_element_by_name("password").send_keys("password")
  12. self.driver.find_element_by_id("dologin").click()
  13. def logout(self):
  14. """退出"""
  15. self.driver.find_element_by_link_text("退出").click()

在test_mail.py中,调用Mail类的login()和logout()方法。

  1. from time import sleep
  2. from selenium import webdriver
  3. from module import Mail
  4. driver = webdriver.Chrome()
  5. driver.get("https://www.126.com/")
  6. #调用Mail类并接受driver驱动
  7. mail = Mail(driver)
  8. #登录账号为空
  9. mail.login("","")
  10. #用户名为空
  11. mail.login("","password")
  12. #密码为空
  13. mail.login("username","")
  14. #用户名/密码错误
  15. mail.login("error","error")
  16. #管理员登录
  17. mail.login("admin","admin123")
  18. #登录之后的操作
  19. sleep(5)
  20. #退出
  21. mail.logout()
  22. driver.quit()

3.6多态

多态:不同的子类对象 调用相同的父类方法,产生不同的执行结果
•多态可以增加代码的灵活度
•以继承和重写父类方法为前提
•是调用方法的技巧,不会影响到类的内部设计

3.7模块和包

模块

①概念

模块是 Python 程序架构的一个核心概念
•每一个以扩展名.py 结尾的 Python源代码文件都是一个模块
•模块名同样也是一个标识符,需要符合标识符的命名规则
•在模块中定义的全局变量 、函数、类都是提供给外界直接使用的工具
•模块就好比是工具包,要想使用这个工具包中的工具,就需要先导入这个模块 

②模块的两种导入方式

import 导入

提示:在导入模块时,每个导入应该独占一行
import 模块名1
import 模块名2 

导入之后 ,通过 模块名. 使用 模块提供的工具——全局变量、函数、类

如果模块的名字太长,可以使用 as 指定模块的名称,以方便在代码中的使用
实现:import 模块名1 as 模块别名          (模块别名应该符合大驼峰命名法)

  1. import game_functions as gf
  2. def run_game():
  3. while True:
  4. gf.check_events(ai_settings,screen,stats,sb,play_button,ship,aliens,bullets)
  5. if stats.game_active:
  6. gf.update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets)
  7. gf.update_aliens(ai_settings,screen,sb,ship,aliens,stats,bullets)
  8. gf.update_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button)
  9. run_game()

from...import 导入

•如果希望 从某一个模块 中,导入 部分 工具,就可以使用 from ... import 的方式
•import 模块名 是 一次性 把模块中 所有工具全部导入,并且通过 模块名/别名 访问

实现:from 模块名1 import 工具名

导入之后 
◦不需要通过模块名.
◦可以直接使用模块提供的工具——全局变量、函数、类

注意:如果两个模块,存在同名的函数,那么后导入模块的函数,会覆盖掉先导入的函数

一旦发现冲突,可以使用 as 关键字 给其中一个工具起一个别名

# 从模块导入所有工具,提示:这种方式不推荐使用,因为函数重名并没有任何的提示,出现问题不好排查
from 模块名1 import *

  1. from settings import Settings
  2. from ship import Ship
  3. def run_game():
  4. ai_settings = Settings()
  5. ship = Ship(ai_settings,screen)
  6. run_game()

③模块的搜索顺序

Python的解释器在导入模块时,会:
1.搜索当前目录指定模块名的文件,如果有就直接导入
2.如果没有,再搜索系统目录 

在开发时,给文件起名,不要和系统的模块文件重名
Python中每一个模块都有一个内置属性 __file__ 可以查看模块的完整路径

④原则——每一个文件都应该是可以被导入的

•一个独立的 Python 文件就是一个模块
•在导入文件时,文件中所有没有任何缩进的代码都会被执行一遍

实际开发场景:

•在实际开发中,每一个模块都是独立开发的,大多都有专人负责
•开发人员通常会在模块下方增加一些测试代码 
   ◦仅在模块内使用,而被导入到其他文件中不需要执行

__name__ 属性

__name__ 属性可以做到,测试模块的代码只在测试情况下被运行,而在被导入时不会被执行!

•__name__ 是 Python 的一个内置属性,记录着一个 字符串
•如果 是被其他文件导入的,__name__ 就是 模块名
•如果 是当前执行的程序 __name__ 是 __main__

if __name__ == '__main__'表示:当模块被直接运行时,下面的代码块将被允许,当模块被其他程序文件调用时,下面的代码块不被运行。

  1. if __name__ == '__main__':
  2. #测试代码

包(Package)

•包是一个包含多个模块的特殊目录
•目录下有一个特殊的文件__init__.py
•包名的命名方式和变量名一致,小写字母 +“ _”

使用import包名可以一次性导入包中所有的模块

__init__.py:要在外界使用包中的模块,需要在__init__.py中指定对外界提供的模块列表。

当用 import 导入该包时,会执行 __init__.py 里面的代码。可以在__init__.py定义__all__ 变量,定义需要导入的模块。比如:

__all__ = ['subpackage_1', 'subpackage_2']
  1. #导入pygame游戏安装包
  2. import pygame
  3. screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
  4. pygame.display.set_caption("Alien Invasion")

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/170890?site
推荐阅读
相关标签
  

闽ICP备14008679号