《Selenium2自动化测试实战基于Python语言》读书笔记--第3章

第3章 Python基础

由于作者写的这本书完全是以Python语言为基础的,所以需要读者具备一定的Python编程能力。如果说最好的Python基础教程,那应该说是《笨方法学Python》了。

3.1 Python哲学

Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>> 

翻译为中文就是:

  • 优美胜于丑陋
  • 明了胜于晦涩
  • 简单胜过复杂
  • 扁平胜于嵌套
  • 间隔胜于紧凑
  • 可读性很重要
  • 即使假错特例的实用性之名,也不违背这些规则
  • 虽然实用性次于纯度
  • 错误不应该被无声的忽略
  • 除非明确的沉默
  • 当存在多种可能时,不要尝试去猜测
  • 应该有一个,最好只有一个,很明显可以做到这一点
  • 虽然这种方式可能不容易,除非你是Python之父
  • 现在做总比不做好
  • 虽然过期从未比现在好
  • 如果这个实现不容易解释,那么它肯定是坏主意
  • 如果这个实现容易解释,那么它很可能是个好主意
  • 命名空间是一种绝妙的理念,应当多加利用

3.2 输出与输入

3.2.1 print打印

Python提供print()方法来打印信息:

>>>print ("hello python")
hello python

打印变量:

>>> name = "zhangsan"
>>> print ("hello %s , Nice to meet you!" % name)
hello zhangsan , Nice to meet you!
>>> name = "Lisi"
>>> print ("hello %s , Nice to meet you!" % name)
hello Lisi , Nice to meet you!

%s 只能打印字符串,如果想要打印数组,需要使用%d:

>>> age = 27
>>> print ("You are %d !" % age)
You are 27 !

如果不知道自己打印的类型,可以使用%r:

>>> age = 27
>>> print ("You are %d !" % age)
You are 27 !
>>> 
>>> n =100
>>> print ("You print is %r ." % n)
You print is 100 .
>>> n = "abc"
>>> print ("You print is %r ." % n)
You print is 'abc' .
>>> name = "zhangsan"
>>> age = 22
>>> print ("student info: %s %d ." % (name, age))
student info: zhangsan 22 .

3.2.2 input输入

如果希望打印的是程序运行过程中由用户来决定的内容,可以使用input()方法:

n = input("Enter any content: ")
print "Your input is %r" % n

运行上述脚本时,用户输入的信息就会被打印出来。

3.2.3 引号与注释

Python不区分单引号、双引号,都可以用来表示一个字符串:

>>> print ("hello")
hello
>>> print ('hello')
hello

单引号和双引号可以相互嵌套使用,但不能交叉使用:

>>> print ("你说:'早上你好'")
你说:'早上你好'
>>> print ('我说:"今天天气不错"')
我说:"今天天气不错"
>>> print ("你微笑着'向我道别"')

SyntaxError: invalid syntax

Python的单行注释使用“#”表示:

>>>#单行注释
>>>print ("hello world") #打印hello world
hello world

多行注释使用三对引号表示,同样不区分单、双引号:

"""
我们实现一个伟大的程序
那么是
print 一行数据 ^_^
"""
'''
This is a
Multi line comment
'''
print ("Hello World")

3.3 分支与循环

结构化程序实质上是由有限个顺序、分支和循环三种基本结构排列、嵌套而成。

3.3.1 if语句

if实现分支判断,一般语法为:if…else…

>>>a = 2
>>>b = 3
>>>if a > b:
    print ("a max!")
else:
    print ("b max!")

b max!

注意: Python没有像其他语言一样使用“{}”表示语句体,而是通过语句的缩进来判断语句体,缩进默认为4个空格。

if语句通过“==”运算符判断相等:

>>>student = "xiaoming"
>>>if student == "xiaoming":
    print ("xiaoming, You are on duty today.")
else:
    print ("Please call xiaoming to duty")

xiaoming, You are on duty today.

if语句通过“!=”运算符判断不相等;

if语句还可以使用“in”、“not in”表示包含关系:

>>>hi = "hello world"
>>>if "hello" in hi:
    print ("Contain")
else:
    print ("Not Contain")

Contain

if语句还可以进行布尔类型的判断:

>>>a = True
>>>if a:
    print ("a is True")
else:
    print ("a is not True")

a is True

练习:

results = 72

if results >= 90:
    print ("优秀")
elif results >= 70:
    print ("良好")
elif results >= 60:
    print ("及格")
else:
    print ("不及格")

答案:良好。

3.3.2 for语句

Python提供了两种循环:while循环、for循环。

for循环的使用更加灵活、简单,可以直接对一个字符串进行遍历:

>>> for i in "hello world":
    print (i)


h
e
l
l
o

w
o
r
l
d

对一个字典进行遍历:

>>> fruits = ['banana', 'apple', 'mango']
>>> for fruit in fruits:
    print fruit


banana
apple
mango

使用range()函数来进行指定次数的循环:

>>> for i in range(5):
    print (i)


0
1
2
3
4

注意: range()函数默认从0开始循环。

指定起始位置和步长的循环:

>>> for i in range(1, 10, 2):
    print (i)


1
3
5
7
9

range(start, end[, step])
start表示开始位置、end表示结束位置、step表示每一次循环的步长。

python2:range() 是一个生成器,xrange()是一个数组,功能完全一样,性能后者优于前者;
python3:range()和xrange()相同,都是一个数组。

3.4 数组与字典

3.4.1 数组

数组:用方括号[]表示,里面的每一项用逗号“,”分隔。

>>> lists = [1, 2, 3, 'a', 5]
>>> lists
[1, 2, 3, 'a', 5]
>>> lists[0]
1
>>> lists[4]
5
>>> lists[4] = 'b'
>>> lists[4]
'b'
>>> lists.append('c')
>>> lists
[1, 2, 3, 'a', 'b', 'c']

注意:

  • Python允许在数组里任意地防止数字或字符串
  • 数组下标是从0开始
  • append()函数可以向数组末尾追加新项

3.4.2 字典

字典:用花括号{}表示,里面的项是成对出现,一个key对应一个value,key与value之间用冒号分隔,不同的项之间用逗号“,”分隔。

>>> dicts = {"username":"zhangsan",'password':123456}
>>> dicts.keys()
['username', 'password']
>>> dicts.values()
['zhangsan', 123456]
>>> dicts.items()
[('username', 'zhangsan'), ('password', 123456)]
>>> for k,v in dicts.items():
    print ("dicts keys is %r" % k)
    print ("dicts values is %r" % v)


dicts keys is 'username'
dicts values is 'zhangsan'
dicts keys is 'password'
dicts values is 123456

注意: Python规定一个字典中的key必须独一无二,valuekey相同。

  • keys()函数:返回字典key的列表
  • values()函数:返回字典value的列表
  • items()函数:将所有的字典项以列表方式返回

按存放的顺序输出字典:

# 通过zip方法合并两个List为Dictionary
# 遍历会按原先的顺序
keys = ["b", "a", "c", "e", "d"]
values = ["2", "1", "3", "5", "4"]

for key,value in zip(keys, values):
    print (key, value)

输出结果:
b 2
a 1
c 3
e 5
d 4

3.5 函数、类和方法

3.5.1 函数

Python通过def关键字来定义函数:

>>> def add(a, b):
    print (a + b)


>>> add(3, 5)
8

通常函数不会直接打印结果,而是将结果通过return关键字返回:

>>>def add(a, b):
    return a + b
>>>add(3, 5)
8

如果在调用函数时不想传参,可以为函数设置默认参数:

>>> def add(a=1, b=2):
    return a + b

>>> add()
3
>>> add(3, 5)
8

3.5.2 类和方法

在面向对象编程的世界里,一切皆为对象,抽象的一组对象就是类。

eg:汽车是一个类,而张三家的奇瑞汽车就是一个具体的对象。

Python使用class关键字来创建类。

class A(object):

    def add(self, a, b):
        return a + b

count = A()
print (count.add(3, 5))

输出结果为:8

对上述代码分析:

  • 创建一个类A(在Python 3中object为所有类的基类,所有类在创建时默认继承object,所以不声明继承object也可以)
  • 在类下面创建一个add()方法,注意,方法的第一个参数必须是存在的,一般习惯命名为self,但在调用这个方法时不需要为这个参数传值

一般在创建类时会首先声明初始化方法__init__(),注意,init的两侧是双下划线,当我们在调用该类时,可以用来进行一下初始化工作:

class A(object):

    def __init__(self, a, b):
        self.a = int(a)
        self.b = int(b)

    def add(self):
        return self.a + self.b

count = A('4', 5)
print (count.add())

输出结果为:9

对上述代码分析:

  • 当调用A类时首先会执行它的__init__()方法,所以需要对其进行传参
  • 初始化的工作就是将输入的参数类型转化为int类型,保证程序容错性
  • add()方法可以直接拿初始化方法的self.a和self.b两个数进行计算
  • 所以在调用A类下面的add()方法时,不需要再传参

Python中类的继承:

class A():

    def add(self, a, b):
        return a + b

class B(A):

    def sub(self, a, b):
        return a - b

print (B().add(4, 5))

输出结果为:9

对上述代码分析:

  • 创建一个A类,在下面创建add()方法用于计算两个参数相加
  • 创建一个B类,继承A类,并且又继续创建sub()方法用于计算两个参数相减
  • 因为B类继承了A类,所以B类自然也拥有了add()方法,从而可以直接通过B类调用add()方法

3.6 模组

模组=类库、模块。

3.6.1 引用模块

通过:import…或者from…import…的方式引用模块,eg:

>>> import time
>>> print time.ctime()
Mon Mar 19 16:20:26 2018

如果确定只需要使用time下面的ctime()方法,还可以这样引用,eg:

>>> from time import ctime
>>> print ctime()
Mon Mar 19 16:22:00 2018

现在使用时就不必告诉Python,ctime()方法是time模块所提供的了。
但是实际情况,可能是我们还需要使用time模块下的sleep()方法,我们也可以这样引入进来,但是还有其他方法呢,所以我们可以一次性把time模块下的所有方法都引入进来,eg:

from time import *

print ctime()
print "休眠两秒"
sleep(2)
print ctime()

最终输出结果是:

Mon Mar 19 16:46:22 2018
休眠两秒
Mon Mar 19 16:46:24 2018

其中,星号(*),代表了模块下的所有方法。通过导入模块后,可以使用help查看模块的doc,eg:

import time
help(time)

pip所安装的Python第三方库或框架,都可以使用这种方式来查看。

3.6.2 模块调用

一个软件项目不可能把所有代码都放在一个文件中实现,一般会按照一定规则在不同的目录和文件中实现。

创建一个目录project,并在目录下创建两个文件,结构如下:

project/
    |--pub.py
    |--count.py

在pub.py文件中创建add函数:

def add(a, b):
    return a + b

在count.py文件中调用pub.py文件中的add()函数:

from pub import add

print add(4, 5)

输出结果为:9

这样就实现了跨文件的函数调用。

注意: 以下情况会在你使用Python3.5版本中出现,在project目录下,多了一个__pycache__/pub.cpython-35.pyc文件,它的作用是为了提高模块加载的速度,每个模块都会在__pycache__文件夹中放置该模块的预编译模块,命名为module.version.pyc,version是模块的预编译版本编码,通常会包含Python的版本号,例如在CPython发行版3.5中,pub.py文件的预编译文件就是:__pycache__/pub.cpython-35.pyc。

3.6.3 跨目录模块调用

如果调用文件与被调用文件在一个目录下面,那么可以使用上面的方法,但是如果不在同一个目录下,假设文件目录结构如下:

project/
    |--model/
        |--pub.py
    |--count.py

如果还还想在count.py中调用add方法,则需要将目录的完整路径补全,eg:

from model.pub import add

print add(4, 5)

运行结果,依然是:9

3.6.4 进一步讨论跨目录模块调用

目录结构更加复杂的情况:

project/
    |--model/
        |--count.py
        |--new_count.py
    |--test.py

count.py代码如下:

class A():

    def add(self, a, b):
        return a + b

new_count.py代码如下:

from count import A

class B(A):

    def sub(self, a, b):
        return a - b
resule = B().add(2, 5)
print resule

输出结果:7

上述结果没问题,接下来与model目录平级创建test.py文件:

from model import new_count

test = new_count()
test.add(2, 5)

输出结果,会出现:ImportError: No module named 'count'

通过提示信息,在new_count.py文件中,找不到“count”模块,可刚才在执行new_count.py时是可以正常运行的,那么,要想弄清楚错误的原因,首先要知道当Python执行import时到底做了哪些操作?

重点:

当Python在执行import语句时,执行了如下操作:

  • 第1步:创建一个新的module对象(它可能包含多个module);

  • 第2步:把这个module对象插到sys.module中;

  • 第3步:装载module的代码(如果需要,则必须先编译);

  • 第4步:执行新的module中对应的代码;

在执行第3步的时候,首先需要找到module程序所在的位置,搜索的顺序是:

当前路径(以及从当前目录指定的sys.path),PythonPATH,再后是Python安装时设置的相关的默认路径。正因为存在这样的顺序,所以如果当前路径或PythonPATH中存在于标准module同样的module,则会覆盖标准module。也就是说,如果当前目录下存在xml.py,那么在执行import xml时导入的就是当前目录下的module,而不是系统标准的xml。

了解了这些后,我们就可以先构建一个package,以普通module的方式导入,这样即可直接访问此package中各个module,注意,Python2中的package必须包含一个__init__.py的文件。

所以上面问题的错误原因就是:

站在new_count.py的位置,执行from count import A,可查看当前目录下是否存在“count”名字的文件或目录,是可以找到的,但是站在test.py的位置,执行from count import A时,在当前目录下是找不到“count”名字的文件或目录的,所以抛出异常。

解决办法:

最简单的办法就是将导入方法修改为from .count import A,在“count”前面加个点,用来告诉程序count是相对于new_content.py的一个导入。

上面解决办法引入的新的问题:

修改new_count.py代码如下:

from .count import A

class B(A):

    def sub(self, a, b):
        return a - b

result = B().add(2, 5)
print result

当再次执行test.py代码时,出现了新的错误:

Traceback (most recent call last):
  File "/tmp/project/model/new_count.py", line 1, in <module>
    from .count import A
[Finished in 0.1s with exit code 1]SystemError: Parent module '' not loaded, cannot perform relative import

这句话的意思是:“未加载父模块,不能执行相对导入”。

解决办法:

需要将导入模块所在目录添加到系统环境变量PATH目录下才可以。

修改test.py的代码:

import sys
sys.path.append("./model")  #将model目录添加到系统环境变量path下
from model import new_count

test = new_count()
test.add(2, 5)

输出结果:7,注意如果是python2版本需要在model目录下创建init文件才行。

3.7 异常

Python用异常对象(exception object)来表示异常情况。遇到错误后,会引发异常,如果异常对象并未被处理或者捕捉,则程序就会用所谓的回溯(Traceback,一种错误信息)来终止执行。

3.7.1 认识异常

看下面的代码:

>>> open("abc.txt", 'r')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'abc.txt'

错误很明显,我们根本没创建这个文件,自然也无法open操作。我们可以视线捕捉这个异常:Python通过try…except…语句来接收并处理这个异常。

>>> try:
...     open("abc.txt", "r")
... except IOError:
...     print "异常了"
... 
异常了

注意: 我们这里使用的仍然是Python2版本,所以和书中的Python3版本略有不同,以下都是按Python2版本进行演示的。

再来看下面的例子:

>>> try:
...     print aa
... except IOError:
...     print "异常了"
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: name 'aa' is not defined

上面的例子,虽然捕捉异常,但是由于捕捉的异常和实际异常的错误类型并不相符,所以导致失效。

只需要更换一个正确的接收异常的类型就可以了:

>>> try:
...     print aa
... except NameError:
...     print "异常了"
... 
异常了

那么,程序是怎么抛出不同类型的错误呢?

异常的抛出机制:

  1. 如果在运行时发生异常,则解释器会查找相应的处理语句(称为handler);
  2. 如果在当前函数里没有找到的话,则它会将异常传递给上层的调用函数,看看那里能不能处理;
  3. 如果在最外层(全局main)还是没有找到的话,那么解释器就会退出,同时打印出Traceback,以便让用户找到错误产生的原因。

注意: 异常不一定等于错误,有时候它只是一个警告,有时候它只是一个终止信号,例如退出循环等。

Python中所有异常都集成Exception,所以可以使用它来接收所有类型的异常:

try:
    open("abc.txt", "r")
except Exception:
    print "异常了"

异常了

从Python 2.5之后,所有的异常类都有了新的基类BaseException,Exception同样也继承自BaseException,所以我们可以使用BaseException来接收所有类型的异常:

>>> try:
...     open("abc.txt", "r")
...     print aa
... except BaseException:
...     print "异常了"
... 
异常了

对于这个例子来说,只要其中一行出现了异常就会打印出异常信息,但是如何才能准确知道是哪一行代码引起的异常呢,又如何让Python直接告诉我们异常的原因呢?

>>> try:
...     open("abc.txt", "r")
...     print aa
... except BaseException, e:
...     print e
... 
[Errno 2] No such file or directory: 'abc.txt'

这样就可以打印出异常的详细信息了。

注意: Python 2中使用“, e”这种方式来捕捉异常详细信息,而Python 3中使用“as msg”的方式,这是两者的区别。

Python常见的异常

异常描述
BaseException新的所有异常类的基类
Exception所有异常类的基类,但继承BaseException类
AssertionErrorassert语句失败
FileNotFoundError试图打开一个不存在的文件或目录
AttributeError试图访问的对象没有属性
OSError当系统函数返回一个系统相关的错误,包括I/O故障,如“找不到文件”或“磁盘已满”时,引发此异常
NameError使用一个还未赋值对象的变量
IndexError当一个序列超出了范围
SyntaxError当解析器遇到一个语法错误时引发
KeyboardInterruptCtrl+C被按下,程序被强行终止
TypeError传入的对象类型与要求不符

3.7.2 更多异常用法

异常的更多用法:try...except...else

try:
    aa = "异常测试:"
    print aa
except Exception as msg:
    print msg
else:
    print "没有异常!"

输出结果:

异常测试:
没有异常!

上面代码是因为没有异常所以执行了else,但是例如文件的关闭、锁的释放、把数据库连接返还给连接池等操作,这些操作无论是否异常都希望可以被执行,就需要用到:try...except...finally...

try:
    print aa
except Exception as e:
    print e
finally:
    print "不管是否异常,我都会被执行。"

输出结果:

name 'aa' is not defined
不管是否异常,我都会被执行。

修改上述代码,定义aa变量:

try:
    aa = "异常测试:"
    print aa
except Exception as e:
    print e
finally:
    print "不管是否异常,我都会被执行。"

输出结果:

异常测试:
不管是否异常,我都会被执行。

3.7.3 抛出异常

print方法只是打印异常,而raise方法可以抛出一个异常信息。

from random import randint

# 生成一个1到9之间的随机整数
number = randint(1, 9)

if number % 2 == 0:
    raise NameError("%d is even" % number)
else:
    raise NameError("%d is odd" % number)

输出结果:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
NameError: 3 is odd

判断奇偶数与NameError之间没有任何关系,这里只是为了演示如何通过raise方法抛出各种类型的异常。

注意: raise只能使用Python中所提供的异常类,如果自定义一个abcError,会提示错误abcError未定义。

总结

本章内容只是Python语法的入门的入门,如果想要开始后面的教程,还需要有Python基础,而最佳快速入门的就是《笨方法学Python》了,有兴趣的同学可以搜索并学习。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果Windows 10任务栏出现异常,您可以尝试以下解决方法来修复问题: 1. 重启Windows资源管理器:右键点击任务栏,选择“任务管理器”。在“进程”选项卡,找到“Windows资源管理器”,右键点击并选择“重新启动”。 2. 检查任务栏设置:右键点击任务栏,选择“任务栏设置”。确保“自动隐藏任务栏”选项未勾选,并确保所需的图标和功能在任务栏上显示。 3. 清除任务栏图标缓存:按下Win + R键,打开运行对话框,输入以下命令并按下回车键: ``` %appdata%\..\Local\Microsoft\Windows\Explorer ``` 在打开的文件夹,找到并删除名为"IconCache.db"的文件。然后按下Ctrl + Shift + Esc组合键,打开任务管理器,在“进程”选项卡找到“Windows资源管理器”,右键点击并选择“结束任务”。在任务管理器,点击“文件”菜单,选择“运行新任务”,输入“explorer.exe”并按下回车键,重新启动资源管理器。 4. 执行系统文件检查:按下Win + X键,选择“命令提示符(管理员)”或“Windows PowerShell(管理员)”。在命令提示符或PowerShell窗口,输入sfc /scannow并按下回车键。等待系统文件检查完成,并修复任何受损的系统文件。 5. 重新创建用户账户:如果以上方法都没有解决问题,您可以尝试创建一个新的用户账户,并查看任务栏是否正常显示。如果新账户的任务栏正常工作,可能是原用户账户配置文件出现问题。 如果问题仍然存在,建议您联系Windows官方客服或寻求专业技术支持以获取更详细的帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值