Python程序设计与科学计算精录&总结Episode.2 Python基础语法:函数、模块、内置数据结构、面向对象知识总结(基于Michael导师Python课程与VS2019)

Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。这个名字就很讲究,Jupyter改自木星的英文单词Jupiter,其中包括了Julia和Python两种主流新兴数据科学编程语言的头两字母。当然,除此以外Jupyter Notebook还可以运行其它四十来种不同的编程语言。但凡上知乎搜,很多技术工作者或者学生都很推荐这个编译环境。

个人认为,这些东西都很难撼动Visual Studio的王者地位。总的来看,不管是VS code还是Pycharm还是Jupyter,编译器是一个工具,工具只是用来实现我们目标的而不是用来把玩的。这就好比做饭,烧菜贵精不贵多,把米其林三星大厨的工具包给我,我也只能做出蛋炒饭来。重点是熟悉一个操作环境的功能,然后一直坚持更新、使用。


文章正式介绍之前,先说说上一章节中代码第一行的注释含义,也就是Python的一个核心常识:编码注释

Python编码注释之 # -*- coding:utf-8 -*-

# -*- coding:utf-8 -*-的主要作用是指定文件编码为utf-8, 因为一般默认的是ASCII码,如果要在文件里面写中文,运行时会出现乱码,加上这句之后会把文件编码强制转换为utf-8运行时会就不会出现乱码了。

声明的语法参考python的PEP,地址如下:

http://www.python.org/dev/peps/pep-0263/

编码注释要点:

1.必须将编码注释放在第一行或者第二行

2.可选格式有

# coding=<encoding name>  
# -*- coding: <encoding name> -*-  
# vim: set fileencoding=<encoding name> :  

3. 标准中给出了只要满足下面这个正则表达式的字符串都有效:

\%^.*\n.∗\?#.*coding[:=]\s*[0-9A-Za-z-_.]\+.*$  

其中的意思就是必须包含#,且#号之前不能有字符换行等其他字符,字符串中必须包含coding后面可以跟:或者=接下来就是编码名称。但是为什么通常这种方式呢?

# -*- coding: <encoding name> -*-  

答案是Emacs等编辑器使用这种方式进行编码声明。这样写可以支持多种编辑器,移植性好。

所以今后的写代码过程中,养成好的习惯,开头添加一行编码注释,使得程序的严谨性可读性有所提升。

 

除此以外,补充一个与别的编程语言十分类似的知识点,循环。由于循环在各种语言中的表达基本相同,所以此处略讲:

1、for循环的语法格式如下:

for iterating_var in sequence:

    statements(s)

例如:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
for letter in 'Python':     # 第一个实例
   print '当前字母 :', letter
 
fruits = ['banana', 'apple',  'mango']
for fruit in fruits:        # 第二个实例
   print '当前水果 :', fruit
 
print "Good bye!"

 输出结果为:

当前字母 : P
当前字母 : y
当前字母 : t
当前字母 : h
当前字母 : o
当前字母 : n
当前水果 : banana
当前水果 : apple
当前水果 : mango
Good bye!

另外一种执行循环的遍历方式是通过索引,如下实例:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
fruits = ['banana', 'apple',  'mango']
for index in range(len(fruits)):
   print '当前水果 :', fruits[index]
 
print "Good bye!"

输出结果为:

当前水果 : banana
当前水果 : apple
当前水果 : mango
Good bye!

以上实例我们使用了内置函数 len() 和 range(),函数 len() 返回列表的长度,即元素的个数。 range返回一个序列的数,其中range函数的标志是:range(start,end,step),分别代表包含在内的start开始点,不含在内的end点和步长step。

在 python 中,for … else 表示这样的意思,for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。例如:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
for num in range(10,20):  # 迭代 10 到 20 之间的数字
   for i in range(2,num): # 根据因子迭代
      if num%i == 0:      # 确定第一个因子
         j=num/i          # 计算第二个因子
         print '%d 等于 %d * %d' % (num,i,j)
         break            # 跳出当前循环
   else:                  # 循环的 else 部分
      print num, '是一个质数'

 输出结果是:

10 等于 2 * 5
11 是一个质数
12 等于 2 * 6
13 是一个质数
14 等于 2 * 7
15 等于 3 * 5
16 等于 2 * 8
17 是一个质数
18 等于 2 * 9
19 是一个质数

2、While循环:

Python 编程中 while 语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务。其基本形式为:

while 判断条件(condition):

    执行语句(statements)……

执行语句可以是单个语句或语句块。判断条件可以是任何表达式,任何非零、或非空(null)的值均为true。当判断条件假 false 时,循环结束。

例如:

#!/usr/bin/python
 
count = 0
while (count < 9):
   print 'The count is:', count
   count = count + 1
 
print "Good bye!"

输出结果为:

The count is: 0
The count is: 1
The count is: 2
The count is: 3
The count is: 4
The count is: 5
The count is: 6
The count is: 7
The count is: 8
Good bye!

while 语句时还有另外两个重要的命令 continue,break 来跳过循环,continue 用于跳过该次循环,break 则是用于退出循环,此外"判断条件"还可以是个常值,表示循环必定成立,具体用法如下:

# continue 和 break 用法
 
i = 1
while i < 10:   
    i += 1
    if i%2 > 0:     # 非双数时跳过输出
        continue
    print i         # 输出双数2、4、6、8、10
 
i = 1
while 1:            # 循环条件为1必定成立
    print i         # 输出1~10
    i += 1
    if i > 10:     # 当i大于10时跳出循环
        break

 如果条件判断语句永远为 true,循环将会无限的执行下去,如下实例:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
var = 1
while var == 1 :  # 该条件永远为true,循环将无限执行下去
   num = raw_input("Enter a number  :")
   print "You entered: ", num
 
print "Good bye!"

结果就是程序要么无限循环,要么死机,要么被你Ctrl+C中断,要么报错,具体结果视编译器不同而定。写代码的过程中是要尽力避免死循环的。 


一、函数及其相关知识:

1、定义一个函数要使用 def 语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。

2、如果没有return语句,函数执行完毕后也会返回结果,只是结果为 None。

3、函数返回多个值的假象:

诸如下面这个例子,

import math
def move(x, y, step, angle):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny
x, y = move(100, 100, 60, math.pi / 6)
print x, y   #151.961524227 70.0
r = move(100, 100, 60, math.pi / 6)
print r    #(151.96152422706632, 70.0)
【Python函数返回的仍然是单一值,是一个tuple:但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。】

4、在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数

def fact(n):
    if n==1:
        return 1
    return n * fact(n - 1)
print fact(10)  #计算10的阶乘

在调用函数改变变量的问题上,python提供了global全局变量声明与nonlocal非局部变量的声明方式:

(1)global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。如果局部要对全局变量修改,则在局部声明该全局变量。如果局部不声明全局变量,并且不修改全局变量,则可以正常使用:

gcount = 0
def global_test():
    global  gcount
    gcount+=1
    print (gcount)
global_test()

(2) nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量:

def scope_test():
    def do_local():
        spam = "local spam" #此函数定义了另外的一个spam字符串变量,并且生命周期只在此函数内。此处的spam和外层的spam是两个变量,如果写出spam = spam + “local spam” 会报错
    def do_nonlocal():
        nonlocal  spam        #使用外层的spam变量
        spam = "nonlocal spam"
    def do_global():
        global spam
        spam = "global spam"
    spam = "test spam"
    do_local()
    print("After local assignmane:", spam)
    do_nonlocal()
    print("After nonlocal assignment:",spam)
    do_global()
    print("After global assignment:",spam)
scope_test()
print("In global scope:",spam)

这个程序的输出就是:

After local assignmane: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

5、定义函数的时候,还可以有默认参数:

def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s
print power(2)  #默认计算2的平方
print power(2,3)  #计算2的三次方

这就有点类似于C语言中的变量赋初值。由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面。

6、一个函数能接受任意个参数,我们就可以定义一个可变参数:

def fn(*args):
    print args
fn('a')   #('a',)
fn('a', 'b')  #('a', 'b')
fn('a', 'b', 'c')   #('a', 'b', 'c')【可变参数的名字前面有个 * 号,我们可以传入0个、1个或多个参数给可变参数】

7、基本数据类型的参数:值传递,表作为参数:指针传递

8、带*参数,在函数的定义中,带*参数表明在前一个实参获取完成后,后面的满足格式要求的参数都存在这个变量名中变成一个列表。带两个**的参数表明从前一个实参获取完成后,后面的格式要求满足的参数都存在这里变成字典:
 

# -*- coding: utf-8 -*-
def func(*args,**kwargs):
    print(args,'----',kwargs)
print(func(1,3,5,23,7,a=3,b=12,c=34))
print("---------------------------------------")
print(func((1,3,5,23,7),{'a':3,'b':12,'c':34}))
print(func(*(1,3,5,23,7),**{'a':3,'b':12,'c':34}))
print("---------------------------------------")
print(func([9,6,5,0],a=3,b=12,c=34))
print(func(*[9,6,5,0],a=3,b=12,c=34))

这是一个相关带*参数传递的实例。

因为没有return 返回任何结果所以函数值都传回了None。这个不是重点。我们来关注一下我们打印的参数结果。第一个打印print(func(1,3,5,23,7,a=3,b=12,c=34))传递了位置参数和后面的a,b,c带的关键词参数,返回的结果是(1, 3, 5, 23, 7) 这个元组和{'a': 3, 'b': 12, 'c': 34} 这个字典。说明了位置参数是以元组形式传入和关键词参数是以字典的形式传入。

9、Python常用内建函数一览表:

这里有必要强调一点:虽然90%的情况python内建函数不够实现我们的功能需求,但是如果可以尽量使用内建函数,提高效率的同时减少了我们的精力消耗。

(1)基本操作函数与随机数生成函数:

abs(x)

返回数字的绝对值,如abs(-10) 返回 10。

ceil(x)

返回数字的上入整数,如math.ceil(4.1) 返回 5。

cmp(x, y)

如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1。Python 3 已废弃 。使用 使用 (x>y)-(x<y) 替换。

exp(x)

返回e的x次幂(ex),如math.exp(1) 返回2.718281828459045

fabs(x)

返回数字的绝对值,如math.fabs(-10) 返回10.0。

floor(x)

返回数字的下舍整数,如math.floor(4.9)返回 4。

log(x)

如math.log(math.e)返回1.0,math.log(100,10)返回2.0。

log10(x)

返回以10为基数的x的对数,如math.log10(100)返回 2.0。

max(x1, x2,...)

返回给定参数的最大值,参数可以为序列。

min(x1, x2,...)

返回给定参数的最小值,参数可以为序列。

modf(x)

返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示。

pow(x, y)

x**y 运算后的值。

round(x [,n])

返回浮点数x的四舍五入值,如给出n值,则代表舍入到小数点后的位数。

sqrt(x)

返回数字x的平方根。

choice(seq)

从序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数。

randrange ([start,] stop [,step])

从指定范围内,按指定基数递增的集合中获取一个随机数,基数缺省值为1。

random()

随机生成下一个实数,它在[0,1)范围内。

seed([x])

改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。

shuffle(lst)

将序列的所有元素随机排序。

uniform(x, y)

随机生成下一个实数,它在[x,y]范围内。

 (2)三角函数:

acos(x)

返回x的反余弦弧度值。

asin(x)

返回x的反正弦弧度值。

atan(x)

返回x的反正切弧度值。

atan2(y, x)

返回给定的 X 及 Y 坐标值的反正切值。

cos(x)

返回x的弧度的余弦值。

hypot(x, y)

返回欧几里德范数 sqrt(xx + yy)。

sin(x)

返回的x弧度的正弦值。

tan(x)

返回x弧度的正切值。

degrees(x)

将弧度转换为角度,如degrees(math.pi/2) , 返回90.0。

radians(x)

将角度转换为弧度。

 


二、面向对象的编程:

1、类通过class关键字定义。类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。类也要细致命名,像“AddrBookEntry”,“RepairShop”等等就是很好的名字,Python 并不支持纯虚函数(像 C++)或者抽象方法(如在 JAVA 中)

2、有了Person类的定义,就可以创建出具体的xiaoming、xiaohong实例。创建实例使用类名+(),类似函数调用的形式创建:Python 规范推荐使用骆驼记法的下划线方式,比如,“update_phone”“update_email”。

3、由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值

4、构造函数__init__()方法:

__init__()方法的第一个参数必须是self(也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定,和定义函数没有任何区别。相应地,创建实例时,就必须要提供除self以外的参数。

定义Person类的__init__方法,除了接受 name、gender 和 birth 外,还可接受任意关键字参数,并把他们都作为属性赋值给实例。要定义关键字参数,使用 **kw;除了可以直接使用self.name = 'xxx'设置一个属性外,还可以通过 setattr(self, 'name', 'xxx') 设置属性。

class Person(object):
    def __init__(self, name, gender, birth, **kw):
        self.name = name
        self.gender = gender
        self.birth = birth
        for k, v in kw.iteritems():
            setattr(self, k, v)
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
print xiaoming.name   #输出Xiao Ming
print xiaoming.job   #输出Student

5、析构函数:_del_方法,由于 Python 具有垃圾对象回收机制(靠引用计数),这个函数要直到该实例对象所有的引用都被清除掉后才会执行。所以很少用到。

6、Python对属性权限的控制是通过属性名来实现的,如果一个属性由双下划线开头(__),该属性就无法被外部访问

但是,如果一个属性以"__xxx__"的形式定义,那它又可以被外部访问了,以"__xxx__"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"__xxx__"定义。以单下划线开头的属性"_xxx"可以在子类中使用,不应该被外部访问,理解为保护成员。"__xxx"可以理解为私有成员,但实质并不是,不建议访问。

class Person(object):
    def __init__(self, name):
        self.name = name
        self._title = 'Mr'
        self.__job = 'Student'
p = Person('Bob')
print p.name   # => Bob
print p._title   # => Mr
print p._Person__job  # => Student  #所以实际上并不是严格的私有成员
print p.__job   # => Error

7、 类属性是直接绑定在类上的,所以,访问类属性不需要创建实例,就可以直接访问。

8、在实例变量上修改类属性:


当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。而其他不变

 9、访问类的属性:

有两种方法。最简单的是使用 dir()内建函数。另外是通过访问类的字典属性__dict__,这是所有类都具备的特殊属性之一。

 10、实例的方法:

实例的方法就是在类中定义的函数,它的第一个参数永远是self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的:在其他语言中,self就是this。

class Person(object):
    def __init__(self, name):
        self.__name = name
    def get_name(self):
        return self.__name
p1 = Person('Bob')
print p1.get_name()  # self不需要显式传入  # => Bob
print p1.__dict__  # {'_Person__name': 'Bob'}
print p1._Person__name  # => Bob

 在实例方法内部,可以访问所有实例属性,这样,如果外部需要访问私有属性,可以通过方法调用获得,这种数据封装的形式除了能保护内部数据一致性外,还可以简化外部调用的难度。

11、方法也分实例方法和类方法。

@classmethod  调用的时候用类名而不是某个对象。在class中定义的全部是实例方法,实例方法第一个参数self是实例本身。

要在class中定义类方法,需要这么写:

class Person(object):
    count = 0
    @classmethod
    def how_many(cls):
        return cls.count
    
    def __init__(self, name):
        self.name = name
        Person.count = Person.count + 1

print Person.how_many()  #0
p1 = Person('Bob')
print Person.how_many()  #1

通过标记一个@classmethod,该方法将绑定到Person类上,而非类的实例。类方法的第一个参数将传入类本身,通常将参数名命名为cls,上面的cls.count实际上相当于Person.count。因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。

12、类的继承:

一定要用super(Student, self).__init__(name, gender)去初始化父类,否则,继承自Person的Student将没有name和gender。

函数super(Student, self)将返回当前类继承的父类,即Person,然后调用__init__()方法,注意self参数已在super()中传入,在__init__()中将隐式传递,不需要写出(也不能写)

使用super()的漂亮之处在于,你不需要明确给出任何基类名字,这意味着如果你改变了类继承关系,你只需要改一行代码(class语句本身)而不必在大量代码中去查找所有被修改的那个类的名字。

一个实例可以看成它本身的类型,也可以看成它父类的类型。

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)  #初始化
        self.score = score

 13、多重继承:

class A(object):
    def __init__(self, a):
        print 'init A...'
        self.a = a
class B(A):
    def __init__(self, a):
        super(B, self).__init__(a)
        print 'init B...'
class C(A):
    def __init__(self, a):
        super(C, self).__init__(a)
        print 'init C...'
class D(B, C):
    def __init__(self, a):
        super(D, self).__init__(a)
        print 'init D...'

像这样,D 同时继承自 B 和 C,也就是 D 拥有了 A、B、C 的全部功能。多重继承通过super()调用__init__()方法时,A 虽然被继承了两次,但__init__()只调用一次:多重继承的目的是从两种继承树中分别选择并继承出子类,以便组合功能使用。

 14、多态:

用一个类继承多个类,调用同一个方法,会有不同的反应,因为被重写了。 


三、模块:

1、概念介绍

#test.py  自身模块名test

import p1.util  引用p1包的模块util

print p1.util.f(2)  调用p1.util的函数f()

如何区分包和普通目录 包下面有个__inti__.py文件

2、如果我们只希望导入用到的math模块的某几个函数,而不是所有函数,可以用下面的语句:

from math import pow, sin, log

3、可以给函数起个“别名”来避免冲突:as

from math import log
from logging import log as logger   # logging的log现在变成了logger
print log(10)   # 调用的是math的log
logger(10, 'import from logging')   # 调用的是logging的log

4、如果导入的模块不存在,Python解释器会报 ImportError 错误:

5、第三方模块管理系统

-easy_install

-pip(推荐,已内置到Python2.7.9)

 

6、Python中的常用模块:

这是一个非常大的话题,我会利用多篇文章介绍多种常用模块极其运用方法,这里只是对python系统基本操作常用模块的一个简单的列举,详细的科学计算模块、文件操作模块、爬虫模块、人工智能模块、办公模块等等均放在后面的文章详细分析。以下总结来自于@changaspl的文章。


sys模块:

sys.argv 命令行参数List,第一个元素是程序本身路径 
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 
sys.modules.keys() 返回所有已经导入的模块列表
sys.modules 返回系统导入的模块字段,key是模块名,value是模块 
sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
sys.exit(n) 退出程序,正常退出时exit(0)
sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0
sys.version 获取Python解释程序的版本信息
sys.platform 返回操作系统平台名称
sys.stdout 标准输出
sys.stdout.write(‘aaa‘) 标准输出内容
sys.stdout.writelines() 无换行输出
sys.stdin 标准输入
sys.stdin.read() 输入一行
sys.stderr 错误输出
sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息 
sys.exec_prefix 返回平台独立的python文件安装的位置 
sys.byteorder 本地字节规则的指示器,big-endian平台的值是‘big‘,little-endian平台的值是‘little‘ 
sys.copyright 记录python版权相关的东西 
sys.api_version 解释器的C的API版本 
sys.version_info ‘final‘表示最终,也有‘candidate‘表示候选,表示版本级别,是否有后继的发行 
sys.getdefaultencoding() 返回当前你所用的默认的字符编码格式 
sys.getfilesystemencoding() 返回将Unicode文件名转换成系统文件名的编码的名字 
sys.builtin_module_names Python解释器导入的内建模块列表 
sys.executable Python解释程序路径 
sys.getwindowsversion() 获取Windows的版本 
sys.stdin.readline() 从标准输入读一行,sys.stdout.write(“a”) 屏幕输出a
sys.setdefaultencoding(name) 用来设置当前默认的字符编码(详细使用参考文档) 
sys.displayhook(value) 如果value非空,这个函数会把他输出到sys.stdout(详细使用参考文档)

string模块:

str.capitalize() 把字符串的第一个字符大写
str.center(width) 返回一个原字符串居中,并使用空格填充到width长度的新字符串
str.ljust(width) 返回一个原字符串左对齐,用空格填充到指定长度的新字符串
str.rjust(width) 返回一个原字符串右对齐,用空格填充到指定长度的新字符串
str.zfill(width) 返回字符串右对齐,前面用0填充到指定长度的新字符串
str.count(str,[beg,len]) 返回子字符串在原字符串出现次数,beg,len是范围
str.decode(encodeing[,replace]) 解码string,出错引发ValueError异常
str.encode(encodeing[,replace]) 解码string
str.endswith(substr[,beg,end]) 字符串是否以substr结束,beg,end是范围
str.startswith(substr[,beg,end]) 字符串是否以substr开头,beg,end是范围
str.expandtabs(tabsize = 8) 把字符串的tab转为空格,默认为8个
str.find(str,[stat,end]) 查找子字符串在字符串第一次出现的位置,否则返回-1
str.index(str,[beg,end]) 查找子字符串在指定字符中的位置,不存在报异常
str.isalnum() 检查字符串是否以字母和数字组成,是返回true否则False
str.isalpha() 检查字符串是否以纯字母组成,是返回true,否则false
str.isdecimal() 检查字符串是否以纯十进制数字组成,返回布尔值
str.isdigit() 检查字符串是否以纯数字组成,返回布尔值
str.islower() 检查字符串是否全是小写,返回布尔值
str.isupper() 检查字符串是否全是大写,返回布尔值
str.isnumeric() 检查字符串是否只包含数字字符,返回布尔值
str.isspace() 如果str中只包含空格,则返回true,否则FALSE
str.title() 返回标题化的字符串(所有单词首字母大写,其余小写)
str.istitle() 如果字符串是标题化的(参见title())则返回true,否则false
str.join(seq) 以str作为连接符,将一个序列中的元素连接成字符串
str.split(str=‘‘,num) 以str作为分隔符,将一个字符串分隔成一个序列,num是被分隔的字符串
str.splitlines(num) 以行分隔,返回各行内容作为元素的列表
str.lower() 将大写转为小写
str.upper() 转换字符串的小写为大写
str.swapcase() 翻换字符串的大小写
str.lstrip() 去掉字符左边的空格和回车换行符
str.rstrip() 去掉字符右边的空格和回车换行符
str.strip() 去掉字符两边的空格和回车换行符
str.partition(substr) 从substr出现的第一个位置起,将str分割成一个3元组。
str.replace(str1,str2,num) 查找str1替换成str2,num是替换次数
str.rfind(str[,beg,end]) 从右边开始查询子字符串
str.rindex(str,[beg,end]) 从右边开始查找子字符串位置 
str.rpartition(str) 类似partition函数,不过从右边开始查找
str.translate(str,del=‘‘) 按str给出的表转换string的字符,del是要过虑的字符

random模块:

random.random() 产生0-1的随机浮点数
random.uniform(a, b) 产生指定范围内的随机浮点数
random.randint(a, b) 产生指定范围内的随机整数
random.randrange([start], stop[, step]) 从一个指定步长的集合中产生随机数
random.choice(sequence) 从序列中产生一个随机数
random.shuffle(x[, random]) 将一个列表中的元素打乱
random.sample(sequence, k) 从序列中随机获取指定长度的片断

types模块:

保存了所有数据类型名称。
if type(‘1111‘) == types.StringType:
MySQLdb模块:
MySQLdb.get_client_info() 获取API版本
MySQLdb.Binary(‘string‘) 转为二进制数据形式
MySQLdb.escape_string(‘str‘) 针对mysql的字符转义函数
MySQLdb.DateFromTicks(1395842548) 把时间戳转为datetime.date对象实例
MySQLdb.TimestampFromTicks(1395842548) 把时间戳转为datetime.datetime对象实例
MySQLdb.string_literal(‘str‘) 字符转义
MySQLdb.cursor()游标对象上的方法

re模块:

①常用正则表达式符号和语法:
'.' 匹配所有字符串,除\n以外
‘-’ 表示范围[0-9]
'*' 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
'+' 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+
'^' 匹配字符串开头
‘$’ 匹配字符串结尾 re
'\' 转义字符, 使后一个字符改变原来的意思,如果字符串中有字符*需要匹配,可以\*或者字符集[*] re.findall(r'3\*','3*ds')结['3*']
'*' 匹配前面的字符0次或多次 re.findall("ab*","cabc3abcbbac")结果:['ab', 'ab', 'a']
‘?’ 匹配前一个字符串0次或1次 re.findall('ab?','abcabcabcadf')结果['ab', 'ab', 'ab', 'a']
'{m}' 匹配前一个字符m次 re.findall('cb{1}','bchbchcbfbcbb')结果['cb', 'cb']
'{n,m}' 匹配前一个字符n到m次 re.findall('cb{2,3}','bchbchcbfbcbb')结果['cbb']
'\d' 匹配数字,等于[0-9] re.findall('\d','电话:10086')结果['1', '0', '0', '8', '6']
'\D' 匹配非数字,等于[^0-9] re.findall('\D','电话:10086')结果['电', '话', ':']
'\w' 匹配字母和数字,等于[A-Za-z0-9] re.findall('\w','alex123,./;;;')结果['a', 'l', 'e', 'x', '1', '2', '3']
'\W' 匹配非英文字母和数字,等于[^A-Za-z0-9] re.findall('\W','alex123,./;;;')结果[',', '.', '/', ';', ';', ';']
'\s' 匹配空白字符 re.findall('\s','3*ds \t\n')结果[' ', '\t', '\n']
'\S' 匹配非空白字符 re.findall('\s','3*ds \t\n')结果['3', '*', 'd', 's']
'\A' 匹配字符串开头
'\Z' 匹配字符串结尾
'\b' 匹配单词的词首和词尾,单词被定义为一个字母数字序列,因此词尾是用空白符或非字母数字符来表示的
'\B' 与\b相反,只在当前位置不在单词边界时匹配
'(?P<name>...)' 分组,除了原有编号外在指定一个额外的别名 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{8})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '19930614'}
[] 是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示相应位置的字符要匹配英文字符和数字。[\s*]表示空格或者*号。
②常用的re函数:
方法/属性 作用
re.match(pattern, string, flags=0) 从字符串的起始位置匹配,如果起始位置匹配不成功的话,match()就返回none
re.search(pattern, string, flags=0) 扫描整个字符串并返回第一个成功的匹配
re.findall(pattern, string, flags=0) 找到RE匹配的所有字符串,并把他们作为一个列表返回
re.finditer(pattern, string, flags=0) 找到RE匹配的所有字符串,并把他们作为一个迭代器返回
re.sub(pattern, repl, string, count=0, flags=0) 替换匹配到的字符串

math模块:

ceil:取大于等于x的最小的整数值,如果x是一个整数,则返回x
copysign:把y的正负号加到x前面,可以使用0
cos:求x的余弦,x必须是弧度
degrees:把x从弧度转换成角度
e:表示一个常量
exp:返回math.e,也就是2.71828的x次方
expm1:返回math.e的x(其值为2.71828)次方的值减1
fabs:返回x的绝对值
factorial:取x的阶乘的值
floor:取小于等于x的最大的整数值,如果x是一个整数,则返回自身
fmod:得到x/y的余数,其值是一个浮点数
frexp:返回一个元组(m,e),其计算方式为:x分别除0.5和1,得到一个值的范围
fsum:对迭代器里的每个元素进行求和操作
gcd:返回x和y的最大公约数
hypot:如果x是不是无穷大的数字,则返回True,否则返回False
isfinite:如果x是正无穷大或负无穷大,则返回True,否则返回False
isinf:如果x是正无穷大或负无穷大,则返回True,否则返回False
isnan:如果x不是数字True,否则返回False
ldexp:返回x*(2**i)的值
log:返回x的自然对数,默认以e为基数,base参数给定时,将x的对数返回给定的base,计算式为:log(x)/log(base)
log10:返回x的以10为底的对数
log1p:返回x+1的自然对数(基数为e)的值
log2:返回x的基2对数
modf:返回由x的小数部分和整数部分组成的元组
pi:数字常量,圆周率
pow:返回x的y次方,即x**y
radians:把角度x转换成弧度
sin:求x(x为弧度)的正弦值
sqrt:求x的平方根
tan:返回x(x为弧度)的正切值
trunc:返回x的整数部分  

hashlib模块:

hashlib.md5(‘md5_str‘).hexdigest() 对指定字符串md5加密
md5.md5(‘md5_str‘).hexdigest() 对指定字符串md5加密

 

Python模块千千万,不可能每个模块每个函数的用法都给记住。有些时候因为客观原因又不能查资料,那么如何在断网的情况下学会python模块的使用方式呢?

dir()函数,括号内参数可以是任何东西,包括函数、类、模块、包。直接输入并用控制台运行打印。那么控制台会直接显示你所输入的对象中含有哪些东西,并且简略告诉你使用方式。当然也可以参照上述总结的几个常用模块的知识。


三、Python内嵌数据结构:

 

序列综述:

1、序列有两种: list (可变列表) 和tuple(不可变元组)

2、定义:序列是一组有顺序的元素的集合,可以包含一个或多个元素,也可以没有任何元素。

由于Python是动态语言,所以list中包含的元素并不要求都必须是同一种数据类型。

3、序列的通用操作:

倒数第一个元素的索引是-1。倒序切片包含起始索引,不包含结束索引。

4、可变的列表(list):

list = [0,1,2,3,4,5]
list.append(7)   #append()总是把新元素添加到list的尾部
print list  # [0, 1, 2, 3, 4, 5, 7]
list.insert(0,-1)  #insert()接受两个参数,第一个是索引,第二个是元素
print list  # [-1, 0, 1, 2, 3, 4, 5, 7]
list.insert(-1,6) #insert(-1)是最后一个元素之前,即倒数第二个元素,因为insert()前插
print list  # [-1, 0, 1, 2, 3, 4, 5, 6, 7]
list.pop()  #pop()方法总是删掉最后一个元素
print list   # [-1, 0, 1, 2, 3, 4, 5, 6]
list.pop(0) #参数为索引
print list  # [0, 1, 2, 3, 4, 5, 6]
list[6]=7 #对list中的某一个索引赋值,就可以直接用新的元素替换掉原来的元素
print list  # [0, 1, 2, 3, 4, 5, 7]
list[0],list[-1]=list[-1],list[0] #第一与最后位置调换
print list  # [7, 1, 2, 3, 4, 5, 0]

在使用可变对象的方法如 sort(),extend()和 reverse()的时候要注意,这些操作会在列表中原地执行操作,也就是说现有的列表内容会被改变,但是没有返回值!

5、不可变的元组(tuple):

字符串是一种特殊的元组没有 app,没有 append()方法,也没有insert()和pop()方法,也不能赋值

print (1,) #一个元素的元祖。

Tuple 比 list 操作速度快.如果您定义了一个值的常量集,并且唯一要用它做的是不断地遍历它,请使用 tuple 代替 list.如月份,星期。

因为()既可以表示tuple,又可以作为括号表示运算时的优先级,结果 (1) 被Python解释器计算出结果 1,导致我们得到的不是tuple,而是整数 1。正是因为用()定义单元素的tuple有歧义,所以 Python 规定,单元素 tuple 要多加一个逗号“,”,这样就避免了歧义。

P.S.可变元组的创建方式:tuple的元素指向list,而list内的值可变

6、序列中的一些内置功能:

(1)序列切片:

一个完整的切片表达式包含两个“:”,用于分隔三个参数(start_index、end_index、step)。当只有一个“:”时,默认第三个参数step=1;当一个“:”也没有时,start_index=end_index,表示切取start_index指定的那个元素。

切片操作基本表达式:object[start_index:end_index:step]

step:正负数均可,其绝对值大小决定了切取数据时的‘‘步长”,而正负号决定了“切取方向”,正表示“从左往右”取值,负表示“从右往左”取值。当step省略时,默认为1,即从左往右以步长1取值。“切取方向非常重要!”“切取方向非常重要!”“切取方向非常重要!”,重要的事情说三遍!

start_index:表示起始索引(包含该索引对应值);该参数省略时,表示从对象“端点”开始取值,至于是从“起点”还是从“终点”开始,则由step参数的正负决定,step为正从“起点”开始,为负从“终点”开始。

end_index:表示终止索引(不包含该索引对应值);该参数省略时,表示一直取到数据“端点”,至于是到“起点”还是到“终点”,同样由step参数的正负决定,step为正时直到“终点”,为负时直到“起点”。

(2)序列排序:

方法一是调用列表序列中自带的sort函数对象,即:

Name.sort() 

进行正序排序,注意只能用于列表,这是因为元组不可以改变,而这些内置函数功能都是在列表自己原地进行操作的。

方法二是调用python的内置函数sorted,即:

sorted(Name)

进行正序排序

sorted(Name, reverse=True)

进行逆序排序。

 

字典:

1、字典的元素没有顺序。你不能通过下标引用元素。字典是通过键来引用,用大括号

dict优点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样。而list的查找速度随着元素增加而逐渐下降。

dict的缺点是占用内存大,还会浪费很多内容

dict是按 key 查找,所以,在一个dict中,key不能重复

作为 key 的元素必须不可变

2、已知两个列表,一个是名字,一个是成绩,要根据名字找到对应的成绩用两个list不方便,如果把名字和分数关联起来,组成类似的查找表,即 Python中的dict

用 dict 表示“名字”-“成绩”的查找表如下:

dic = {'tom':11, 'sam':57,'lily':100}
print type(dic)   #<type 'dict'>

d = {
    'Adam': 95,
    'Lisa': 85,
    'Bart': 59
}
print d   #{'Lisa': 85, 'Adam': 95, 'Bart': 59}

3、我们把名字称为key,对应的成绩称为value,dict就是通过 key 来查找 value。

4、花括号 {} 表示这是一个dict,然后按照 key: value, 写出来即可。最后一个 key: value 的逗号可以省略。

5、由于dict也是集合,len()函数可以计算任意集合的大小:

print len(d)  #运算结果为3,因为一个 key-value 算一个,从而,dict大小为3。

6、可以简单地使用 d[key] 的形式来查找对应的 value,这和 list 很像,不同之处是,list 必须使用索引返回对应的元素,而dict使用key:

print d['Adam'] #95

注意: 通过 key 访问 dict 的value,只要 key 存在,dict就返回对应的value。如果key不存在,会直接报错:KeyError。要避免 KeyError 发生,有两个办法: 一是先判断一下 key 是否存在,用 in 操作符;二是使用dict本身提供的一个 get 方法,在Key不存在的时候,返回None:

print d.get('Bart') #59

print d.get('Paul') #None

7、在字典中增添一个新元素的方法:

d = {
    'Adam': 95,
    'Lisa': 85,
    'Bart': 59
}
print d   #{'Lisa': 85, 'Adam': 95, 'Bart': 59}
d['lilei'] = 99
print d   #{'lilei': 99, 'Lisa': 85, 'Adam': 95, 'Bart': 59}

8、循环调用:

for key in d:   #或for key in d.keys()
    print d[key]
# 结果
# 99
# 85
# 95
# 59

 9、字典的常用方法:

print d.keys()          # 返回d所有的键

print d.values()         # 返回d所有的值

print d.items()         # 返回d所有的元素(键值对)

d.clear()            # 清空d,dict变为{}

del d[‘xxx’]                   # 删除 d 的‘xxx’元素

for key, value in d.items():
   print key, ':', value

10、cmp()比较

(1)先比较字典长度

(2)再比较字典的键

(3)最后比较字典的值

(4)都一样就相等

 

 集合:因为使用少,所以这里略过,只需要记住集合中不会有重复元素即可


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 基于Python实现的强化学习的智能体小车+项目说明+模型.zip 此无人车AI项目使用的Deep Q-learning算法,是DeepMind在2013年发明的深度强化学习算法,将Q-learning的思想与神经网络算法结合,也算是现代强化学习算法的源头了。研究者用这个算法在2015年让计算机学会了49种Atari游戏,并在大部分游戏中击败了人类。从适用性上来讲,我们不需要告诉AI具体的规则,只要让它不断摸索,它就能慢慢从中找到规律,完成许多之前被认为只有人类能完成的智力活动。 既然是Q-learning和Deep learning的结合,就先结合无人车AI来讨论什么是Q-learning。 Q-learning是一种强化学习算法,无人车需要根据当前状态来采取动作,获得相应的奖励之后,再去改进这些动作,使得下次再到相同的状态时,无人车能做出更优的选择。我们用Q(S,A)表示在S状态时,采取A动作所获得的**效用值**。下面用字母R代表奖励(Rewards),S'代表采取A动作后到达的新位置。(奖励值R与效用值Q的区别在于,R表示的是这个**位置**的奖励,比如对于无人车而言障碍物的位置奖励是-100,河流的位置奖励是-120,柏油路的奖励是100,沙路的奖励是50,目标点的奖励是10000。而Q代表的是,采取这个**动作**的效用值,用于评价在特定状态下采取这个动作的优劣,可以将之理解为无人车的大脑,它是对所有已知状态的综合考虑) 伪代码如下: ``` Initialize Q arbitrarily // 随机初始化Q值 Repeat (for each episode): // 每一次尝试,从车子出发到撞墙是一个episode Initialize S // 车辆出发,S为初始位置的状态 Repeat (for each step of episode): Q(S,A) ← (1-α)*Q(S,A) + α*[R + γ*maxQ(S',a)] // Q-learning核心贝尔曼方程,更新动作效用值 S ← S' // 更新位置 until S is terminal // 位置到达终点 ``` 贝尔曼方程(Bellman Equation)中,γ为折扣因子,α为学习速率。γ越大,无人车会越重视以前的经验,越小就更重视眼前利益。α取值范围为0~1,取值越大,保留之前训练的效果就越少。可以看出当α取值为0时,无论如何训练AI也无法学习到新Q值;α取值为1时,新Q值将完全取代旧Q值,每次训练得到新值就会完全忘记之前的训练结果。这些参数值都是人为设定的,需要根据经验慢慢调整。 然后我们将Q-learning算法与深度学习结合。从High Level来看,Q-learning已经实现无人车基本的躲避路障功能,而深度学习算法可以让无人车自动总结并学习特征,减少人为设定特征的不完备性,以更好的适应非常复杂的环境条件。 首先,用一个深度神经网络来作为Q值的网络,地图上每个点有坐标(X1, X2),将此状态输入神经网络来预测每个方向的Q值(图中假设有四个actions对应四个方向,所以一共得到4个新的Q值)。Q-target表示上一次到达该状态时所得到的Q值,然后使用均方差(mean-square error)来定义Loss Function。 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值