Python 学习笔记

目录

基础

类型:数字+字符串

字符串

输入input()

数学运算

变量

细节

数据结构

列表(List[ ])

列表截取

列表推导

元组 tuple()

字典 dict{ }

序列

集合 

引用(已有对象赋值给变量)

循环/判断语句

for循环

while 循环

if 条件判断

assert 语句

def 创建函数

可变参数函数

文档字符串 ——DocString

模块(.py )

面向对象编程

关于 self

__init__ 方法(初始化)

类和对象中的变量

魔术方法

继承

文件读写

NumPy IO 方法

异常处理

标准库

Python与MATLAB文件 

Python 导入 MATLAB 数组:

导出mat文件: 

软件开发过程


注意:

Python区分大小写

基础

类型:数字+字符串

数字类型主要有两种:整数(int)和浮点数

没有long类型,int类型可以是任意大小的整数。

字符串

单引号,双引号,三引号(多行字符串),没有char类型

转义序列: 单引号指定为 \'(注意是反斜杠),例如 "What's your name?"

'What\'s your name?'

转义序列 \\ 表示反斜杠本身。

在字符串中,行末尾的单个反斜杠表示字符串在下一行中继续,但不添加换行符(相当于MATLAB中的 ...)

"This is the first sentence.\
This is the second sentence."

等价于 "This is the first sentence. This is the second sentence."

构造字符串:

1、+ 号连接

print内要同类型,不同类型采用强制转换

print(str(2.1)+'apples') >>> 2.1apples

print(float('3.2')+1) >>> 4.2

格式化字符 %s %d (%r 不管什么类型都打印出来)

进一步了解到如果不是测试的代码,不推荐使用%。格式化字符串的其他方式

name='xx'

print('name is %s'%name) >>> name is xx

在python中将右边变量的值带到%s的位置上

2、format() 方法从其它信息中构造字符串,将每个参数值替换到指定的位置。

age = 20
name = 'Swaroop'

print('{0} was {1} years old when he wrote this book'.format(name, age))
print('Why is {0} playing with that python?'.format(name))

输出:

Swaroop was 20 years old when he wrote this book
Why is Swaroop playing with that python?

细节:{ }里面的数字是可选的,可填可不填。可以有更加详细的规范,例如:

# 取十进制小数点后的精度为 3 ,得到的浮点数为 '0.333'
print('{0:.3f}'.format(1.0/3))
# 填充下划线 (_) ,文本居中
# 将 '___hello___' 的宽度扩充为 11 
print('{0:_^11}'.format('hello'))
# 用基于关键字的方法打印显示 'Swaroop wrote A Byte of Python'
print('{name} wrote {book}'.format(name='Swaroop', book='A Byte of Python'))

输出:

0.333
___hello___
Swaroop wrote A Byte of Python

注意 print 总是以一个不可见的 「新的一行」 字符(\n)作为结尾,因此对 print 的重复调用将在每个单独的行上打印输出。为了防止这个换行符被打印输出,你可以指定它以一个空(即,什么都没有)作为 end // 或者可以用空格作为 end :

print('a', end='')
print('b', end='')

输出为:ab

更多的字符串操作:

# 这是一个字符串对象
name = 'Swaroop'

if name.startswith('Swa'):
    print('Yes, the string starts with "Swa"')

if 'a' in name:
    print('Yes, it contains the string "a"')

if name.find('war') != -1:
    print('Yes, it contains the string "war"')

delimiter = '_*_'
mylist = ['Brazil', 'Russia', 'India', 'China']
print(delimiter.join(mylist))

输出:
Yes, the string starts with "Swa"
Yes, it contains the string "a"
Yes, it contains the string "war"
Brazil_*_Russia_*_India_*_China

startswith 方法用于检测字符串是否以给定的字符串开头。

in 方法用于测试给定的字符是否是另一个字符串的一部分。

find 方法用于确定给定子字符串在源字符串中的位置, find 返回 -1 说明找不到给定的字符串。  join 方法,用于将源字符串按给定的字符进行分隔,并返回一个大字符串(列表转换成字符串)

输入input()

a_input = input('please give me a number:')
注意:input的返回值是字符串类型(str) 

数学运算

幂 ** :2**3 >>> 8

取余 %:8%2 >>> 0

除且取整 // :36//5 >>> 7 ;(除:36/5 >>> 7.2)

注意,如果操作数之一为浮点数,则返回值必为浮点数。

变量

变量可以保存不同类型(数据类型)的值。基本类型是数字和字符串。变量可以直接通过赋值来使用,不需要任何声明或者数据类型定义

tips:可以同时定义多个自变量:

a,b,c=1,1,3

可以在自变量中运算自变量:

d=c**3 >>> 27

细节

逻辑行和物理行:物理行是当你写程序的时候,你眼睛 看到 的行。逻辑行是 Python 看到 的一个程序语句。Python 默认每一个 物理行 对应一个 逻辑行 。默认情况下,Python 推荐一行一个语句,这会使代码更具有可读性。(单个物理行中编写更多的逻辑行用分号形式,但不推荐)

反斜杠将一个物理行分解为多个物理行。有时候,有一种隐含的假设,你不需要使用反斜杠。在这种情况下,逻辑行有开始括号、开始方括号或者开始花括号,但是没有结束括号。我们称之为 隐式行连接 。在后面的章节中,当我们使用 list(列表) 编程时,你就可以看到这一点。

缩进 用于确定语句的分组,同一组的语句 必须 有相同的缩进。每一个这样的语句集被称为 语句块 。错误的缩进会导致报错。

数据结构

数据结构基本上是这样的:它们是能够将一些数据组合在一起的一种结构。换句话说,它们是被用来存储相关数据的集合。
Python 中有四种内置的数据结构 - list, tuple, dictionary and set

列表(List[ ])

List 是一种保存有序项集合的数据结构,列表其实也是一个序列。以方括号内逗号分隔值出现,第一个索引从0开始。

创建了列表,可以在列表中增加,删除或者搜索列表中的项,因此称列表是一种可变数据类型

使用 for..in 循环来遍历列表中的项(元素)。到目前为止,你必须要意识到

对象和类的简介: 对象和类的简介列表是使用对象和类的一个例子。当我们使用一个变量 i 并为它赋值时,例如将整数 5 赋值给它。我们可以将其看作是创建一个对象 i  (即,实例)的过程,它对应的 类 (即,类型)为 int 。实际上,你可以通过查看 help(int) 来更好地理解这一点。

一个类也可以有方法 ,即只能被该类调用的函数。只有当你拥有该类的对象时,才能使用这些函数。例如, Python 为 列表 类提供了一个 append 函数,它允许你在列表的末尾添加一个元素(或者项)。

一个类也可以有 字段 ,它们只是为该类定义的变量。只有当你拥有该类的对象时,才可以使用这些变量 / 名称。字段也可以用点访问。

Python包含以下方法:

list.append(obj):在列表末尾添加新的对象

list.insert(index, obj):将对象插入列表指定位置  

list.remove(obj):移除列表中某个值的第一个匹配项

list.index(obj) :从列表中找出某个值第一个匹配项的索引位置

list.count(obj) :统计某个元素在列表中出现的次数

list.sort( key=None, reverse=False) : 对原列表进行排序,默认从小到大

  • key -- 主要是用来进行比较的元素,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)。

list.pop() 函数用于移除列表中的一个元素(默认最后一个元素),返回从列表中移除的元素对象。

list1 = ['Google', 'Runoob', 'Taobao']
list1.pop() # 默认删除最后一个元素
print ("列表现在为 : ", list1)
list1.pop(1)
print ("列表现在为 : ", list1)

 输出:

列表现在为 :  ['Google', 'Runoob']
列表现在为 :  ['Google']
# 列表
random = [(2, 2), (3, 4), (4, 1), (1, 3)]

random.sort()
>>[(1, 3), (2, 2), (3, 4), (4, 1)]


# 获取列表的第二个元素
def takeSecond(elem):
    return elem[1]
 
 
# 指定第二个元素排序
random.sort(key=takeSecond)
 
# 输出类别
print ('排序列表:', random)

输出:

排序列表:[(4, 1), (2, 2), (1, 3), (3, 4)]

x[0]代表用key进行排序;x[1]代表用value进行排序。

del list[0]:删除列表中的第一项

列表截取

L=['Google', 'Runoob', 'Taobao']

L[2] # 读取第三个元素:'Taobao'

L[-2] # 从右侧开始读取倒数第二个元素: 'Runoob'

L[1:] # 输出从第二个元素开始后的所有元素:['Runoob', 'Taobao']

L[0:2] = L[:2] # 输出从第0个元素到第二个元素,取不到2对应的第三个元素,左闭右开区间:['Google', 'Runoob']

列表推导

列表推导用于从现有列表中导出新列表。 假设你有一个数字列表,并且你希望获得一个相应的新列表,其中所有数字仅在数字本身大于 2 时乘以 2。列表推导是这种情况的理想选择。

listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print(listtwo)

 输出:[6, 8]

使用列表推导的优点是,当我们循环处理列表的每个元素并将其存储在新列表中时,它减少了所需样板代码的量。

元组 tuple()

元组是由一些特殊的项定义的,这些项在一对可选的圆括号中(不用括号也可以,但显式总比隐式要好),由逗号隔开。

元组用于将多个对象组合在一起。可以将它们近似看作列表,但是没有列表类提供的许多功能。元组的一个重要特征是,它们和字符串一样是不可变的 ,即你不能修改元组。元组通常用于这种情况,也就是语句或者用户自定义的函数可以安全地认为值的集合(即,值的元组)不会改变的情况。

len 函数可以用来获得元组的长度。这也表明元组是一个序列,下标索引从0开始。

包含 0  或 1 个项的元组
一个空的元组是由一对空的圆括号构成的,例如, myempty = () 。然而,只有一个项的元组就没有这么简单了。你必须在且仅在第一个项的后面用一个逗号来指定该元组,这样 Python 就可以区分一个元组和表达式中对象周围的一堆括号之间的区别了。即,如果你想要一个元组只包含一个项:2,那么你就必须用 singleton = (2 , ) 。

请注意, a, b = <某些表达式>  会将表达式的结果解析为两个值组成的元组。
这也意味着在 Python 中交换两个变量的最快方法是:

a = 5; b = 8
>> a, b
(5, 8)
a, b = b, a
>> a, b
(8, 5)

字典 dict{ }

通过 d = {key1 : value1, key2 : value2 } ,就可以指定字典中的键值对。注意,一个键值对中的键与值由冒号隔开,而不同键值对之间是由逗号隔开,所有的键值对以及冒号、逗号都包含在一对花括号中。

字典就像是一个地址簿,只要知道一个人的名字,你就可以找到他 / 她的地址或联系方式,即,我们将(名字)与(详细信息)相关联。注意,键必须是唯一的!就好比是,如果有两个人重名,那就无法找到正确的详细信息一样。

注意,对于字典的键,你只能使用不可变对象(比如字符串),但是对于字典的值,不可变对象或者可变对象都可以使用。这基本上就意味着,对于字典的键,你最好只使用简单点的对象。

记住,字典中的键值对不以任何方式排序(不像列表中的项一样有从小到大递增的索引)。如果你想要得到一个特殊的顺序。那么在使用字典之前,你必须自己对其进行排序。

使用索引操作符来指定字典的键,以此来访问键值对。例如:d['key1'] // del d['key1']

添加新的键值对,只需要直接使用索引操作符访问一个键并为其赋值:d['key3'] = ‘value3’

常用方法:

使用字典的 items 方法 来访问字典中的每一个键值对,该方法返回一个元组列表,其中每一个元组包含一个键值对 —— 键在前值在后。

for name, address in ab.items():
    print('Contact {} at {}'.format(name, address))

可以使用 in 操作符检查键值对是否存在。 

Lambda 格式

lambda 语句用于定义一个匿名函数。 基本上, lambda +参数,冒号后跟一个表达式,为函数体。 新函数返回此表达式的值。

points = [{'x': 2, 'y': 3},
          {'x': 4, 'y': 1}]
points.sort(key=lambda i: i['y'])
print(points)

 输出:[{'x': 4, 'y': 1}, {'x': 2, 'y': 3}]

d= {'a':24,'g':52,'i':12,'k':33}
sorted(d.items(),key=lambda x:x[1]) # 以value值排序

 x[0]代表用key进行排序;x[1]代表用value进行排序。

序列

列表,元组和字典都是序列的一种,但序列是什么,为什么它们这么特别呢?
序列的主要特征是:成员测试 (例如:in 与 not in 表达式) 和 索引操作,这两种操作让我们可以直接从序列中提取特定的部分
上面提到了三种序列:列表、元组和字典。它们还有另一种特殊的操作 —— 切片 ,切片操作让我们可以得到序列的一部分。

Python的索引从0开始,用-1索引最后一位,-2为倒数第二个元素。

切片操作通过在序列名称的后面加上一个方括号,方括号中有一对可选的数字,用冒号分割。记住数是可选的,而冒号是必须的。切片操作中冒号之前的第一个数表示切片开始的位置,冒号之后的第二个数表示切片到哪里终止。如果不指定第一个数,Python 会从序列首开始,不指定第二个数则到序列尾结束。注意返回的切片从开始位置 开始在结束位置之前 结束,即一个左闭右开区间因此 A[1:3]是只有两个元素的原序列切片。

也可以用负数位置做切片。负数从序列尾部开始计算位置。例如:A[:-1] 会返回除了最后一个元素外的其余序列切片。也可以在切片时提供第三个参数:步长,默认的步长为 1。

shoplist = ['apple', 'mango', 'carrot', 'banana']
shoplist[::1]
['apple', 'mango', 'carrot', 'banana']
shoplist[::2] // 步长为2
['apple', 'carrot']
shoplist[::3]
['apple', 'banana']
shoplist[::-1] //从序列尾部开始
['banana', 'carrot', 'mango', 'apple']

集合 

集合(set)是简单对象的无序的集合(collection)。当对象在集合中的存在比对象在集合中的顺序或者比对象在集合中出现的次数更为重要时,我们就会用到集合(set)。可以使用集合(set)来测试成员资格,看看它是否是另一个集合(set)的子集,找到两个集合之间的交集,等等。

关于 set 和 collection 的翻译。在数学上, set 和 collection 的区别是是否具有互异性,即,包含的元素是否可以重复出现。set 中的元素具有互异性,而 collection 中的元素不具有互异性。比如,{1,2,3} 既是 collection 又是 set ,而 {1,2,3,3} 只是 collection 不是 set 。因为后者(即 {1,2,3,3})有重复的元素(就是那两个 3),这不符合 set 的互异性要求。————————————————
转自链接:2.9. 数据结构 | 正文 |《Python 简明教程 2018》| Python 技术论坛

引用(已有对象赋值给变量)

当你创建了一个对象,并把它赋值给一个变量时,这个变量只是 引用 了这个对象,变量并不能代表对象自身!因此,你可以把变量名当作一个指针,它指向储存对象的那一块计算机内存。

print('Simple Assignment')
shoplist = ['apple', 'mango', 'carrot', 'banana']
# mylist 只是指向同一个对象的另一个别名!
mylist = shoplist

# 我买下了第一件商品,所以把它从列表中移除
del shoplist[0]

print('shoplist is', shoplist)
print('mylist is', mylist)

shoplist is ['mango', 'carrot', 'banana']
mylist is ['mango', 'carrot', 'banana']
# 注意到 shoplist 和 mylist 产生了同样的输出
# 输出的都是没有 'apple' 的相同列表
# 这验证了它们都指向着同一个对象

print('Copy by making a full slice')
# 通过全切片来获得一个副本
mylist = shoplist[:]
# 移除第一个元素
del mylist[0]

print('shoplist is', shoplist)
print('mylist is', mylist)

shoplist is ['mango', 'carrot', 'banana']
mylist is ['carrot', 'banana']
# 注意到现在这两个列表有差异了

总结:如果你想要获得列表、或者类似的序列、或更复杂对象的副本,只要不是像整数一样简单的 对象,你都需要通过切片操作来获得它的副本如果你直接把一个变量名赋值给另一个,它们两个都会引用同一个对象。在赋值时你需要注意这一点,不然可能会造成意想不到的结果,从而带来麻烦

循环/判断语句

没有花括号和end,通过冒号和四个空格/Tap构建结构。冒号 —— 在向 Python 表明后面跟着一个语句块。

for循环

for..in 循环可以遍历序列中的的每个项。如一个列表或者一个字符串,可以直接输出元祖或列表里面的值。【这一点与MATLAB不同,MATLAB中for后面是指定要循环的范围:for i=1:1:length(RELH)。补充:才发现MATLAB也可以直接遍历数组,如:for v = matrix,v也是依次遍历matrix中的值。在C语言中:for (int i = 0; i < 5; i++) 在Python中:for i in range(0,5) 】

for letter in 'Python':     # 第一个实例
   print("当前字母: %s" % letter)

Python中的for循环也可以用range()指定循环次数,函数会返回从第一个数字开始到第二个数字结束的数字序列。如:for i in range(1,3): // for index in range(len(fruits)): 但注意range(1,3)的范围是[1,2],取不到3 (返回的序列的范围 不 包含第二个数字)

fruits = ['banana', 'apple',  'mango']
for index in range(len(fruits)):
   print ('index=',index,'当前水果 :',fruits[index])
----------------------------------------------------------
index= 0 当前水果 : banana
index= 1 当前水果 : apple
index= 2 当前水果 : mango

while 循环

while 语句可以让你重复执行一个语句块,只要条件为真( Python 将变量中的 0 、 None 、空数组和空集合都视为 False)。 一个 while 语句可以有一个可选的 else 从句。else 语句块会在 while 循环的条件变为 False 时执行。如果 while 循环中有一个 else 从句,它总是会执行到(因为在非死循环下总有一次会不满足while条件),除非用 break 语句跳出循环 [for 循环同理]

if 条件判断

if...elif...else:从前到后的顺序执行,如果碰到一个满足条件,直接跳出整个if判断语句。

elif 和 else 语句同样在逻辑行的结尾处有一个冒号,后面跟着相应的语句块。

Python 中没有 switch 语句。你可以用一个 if..elif..else 语句完成相同的操作(在某些情况下,你还可以用 字典(dictionary) 快速地完成相同操作)。

continue 语句

continue 语句用来告诉 Python 跳过当前循环语句块中的其余部分,然后 继续 执行循环的下一个迭代。

assert 语句

assert 语句用于断言某值为 True 。

例如,如果您非常确定您正在使用的列表中至少有一个元素并且想要检查它,并且如果不是 True 则引发错误,那么 assert 语句在这种情况下是理想的。 当 assert 语句失败时,会引发 AssertionError 。assert 语句应该是明智地使用。 大多数情况下,最好能捕获异常、处理问题或向用户显示错误消息然后退出。

def 创建函数

通过使用函数名,可以随时调用这个语句块。在术语上,函数定义时括号中的参数叫做形参,而调用函数时提供的参数叫实参

def function_name(a,b):
  ...:     c=a+b
  ...:     return c

print(function_name(1,2))    # 调用函数 or print(function_name(a=1,b=2))
>>> 3

在定义函数时,可以让某些形参是可选的,并在用户没有指定这些形参的值时,使用默认值。通过默认形参值实现:def function_name(b,a=1):

注意:形参的默认值必须是常数,且必须定义在后面,这是因为给形参赋值是按照实参的顺序进行的。

这样调用的时候可以只写第一个参数的值:

function_name(2)   # 但我认为这样代码不够清楚,还是使用:function_name(b=2)【关键字参数:使用名字(关键字)给函数指定实参】

综合实例:

def func(a, b=5, c=10):
    print('a is', a, 'and b is', b, 'and c is', c)

func(3, 7)
func(25, c=24)
func(c=50, a=100)

输出:
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50

在函数内,可以通过global语句定义全局变量,还可以给在函数外定义的变量赋值

x = 50

def func():
    global x

    print('x is', x)
    x = 2
    print('Changed global x to', x)

func()
print('Value of x is', x)

输出:

x is 50
Changed global x to 2
Value of x is 2

可变参数函数

定义一个参数个数可变的函数,可以通过使用星号 * 来实现这个功能。

当我们声明一个带星号的参数 *param 时,从这个参数开始,之后的所有参数都会被收集进入一个名为 param 的元组中。
类似的,当我们定义了一个带两个星号的参数 **param 时,从这个参数开始,之后的所有参数都会被收入名为 param 的字典中。

def total(a=5, *numbers, **phonebook):
    print('a', a)

    # 遍历元组中的所有项
    for single_item in numbers:
        print('single_item', single_item)

    # 遍历字典中的所有项
    for first_part, second_part in phonebook.items():
        print(first_part,second_part)

print(total(10,1,2,3,Jack=1123,John=2231,Inge=1560))

输出:
a 10
single_item 1
single_item 2
single_item 3
Inge 1560
John 2231
Jack 1123
None 

细节:如果函数没有 return 语句,系统会自己在函数的结尾添加 return None 语句。

None 在 Python 是一种代表「没有任何东西」特殊的类型。例如:如果一个变量的值是 None,则说明这个变量尚未被赋值或值已被清空。

使用一个元组,可以返回函数中两个不同的值

def get_error_details():
...     return (2, 'details')
...
errnum, errstr = get_error_details()
>> errnum
2
>> errstr
'details'

文档字符串 ——DocString

文档字符串 (documentation strings),通常简称为 DocStrings。对函数实现的功能/关键点进行说明。实例:

def print_max(x, y):
    '''Prints the maximum of two numbers.

    The two values must be integers.'''
    # 如果有必要,将参数转为整数
    x = int(x)
    y = int(y)

    if x > y:
        print(x, 'is maximum')
    else:
        print(y, 'is maximum')

print_max(3, 5)
print(print_max.__doc__)

输出:
5 is maximum
Prints the maximum of two numbers.

    The two values must be integers.

这个函数逻辑上第一行的字符串是这个函数的 DocStrings。注意到 模块 和 类 都有各自的 DocStrings。DocStrings 的书写惯例是:首行首字母大写,结尾有句号;第二行为空行;第三行以后为详细的描述。建议在编写任何非平凡函数时都遵守这种惯例,那些只有几行的平凡函数可以不遵守这个惯例。
可以通过 print_max 函数的 __doc__ 属性来访问它的 DocStrings,注意:属性 doc 的前后都有两个下划线。

help() 函数可以抓取对应函数的 __doc__ 属性,并以美观的方式打印出来。例如:help(print_max) 。记住 按 q 可以退出 help。

输出:

Help on function print_max in module __main__:
print_max(x, y)
    Prints the maximum of two numbers.
    
    The two values must be integers.

a = 5; b = 8
a, b
(5, 8)
a, b = b, a
a, b
(8, 5)

模块(.py )

可包括大量可重复调用函数并以 .py 为扩展的文件。一个模块会被引入(import)到一个程序,模块中的变量可以通过点表示法来访问。(module.Variable name)

dir() 函数 能以列表的形式返回某个对象定义的一系列标识符。如果这个对象是个模块,返回的列表中会包含模块内部所有的函数、类和变量。

这个函数接收一个可选的参数。当参数是模块名时,函数会返回对应模块的标识符列表。没有参数时则会返回当前模块的标识符列表。

字节码文件 .pyc

导入模块是一个相对而言开销较大的操作,因此,Python 试用了一些手段来使得导入模块的操作更加快速。其中一个方法,就是创建以 .pyc 为扩展名的 字节码 文件。(Python 不需要编译成二进制。你可以直接从源代码 运行 程序。在内部,Python 会转换成一种被称为字节码的中间形式,然后将字节码转换成你的计算机的机器语言,然后运行它。)

当你下一次想要在另外一个程序代码中导入模块的时候,这个 .pyc 文件就很有用 —— 导入操作会很快完成,这是因为导入模块所必须的一部分操作已经被事先完成了。此外,这些字节码文件都是平台无关的。
注意:这些 .pyc 文件一般会被创建在与它对应的 .py 文件相同的文件目录下。如果 Python 没有在该文件夹下写文件的权限,那么 .pyc 文件将不会被创建。

————————————————
原文作者:Python 技术论坛文档:《Python 简明教程(2018)》
转自链接:https://learnku.com/docs/byte-of-python/2018/modules/3345

程序包(__init__.py 文件

变量通常在函数的内部,全局变量和函数通常在模块的内部。如何组织模块呢?这就是程序包出场的时候了。程序包就是一个装满模块的文件夹,它有一个特殊的 __init__.py 文件,这个文件告诉 Python 这个文件夹是特别的,因为它装着 Python 的模块。

面向对象编程

使用函数、模块来操作我们的数据,这叫做面向过程的方式进行编程。然而还有另外一种方式来组织你的程序:把数据和函数结合起来,并将其置入一种叫做对象的东西。这就叫做 面向对象 编程范式。在大多数情况下,你可以使用面向过程的编程,但是当写大型程序或者遇到了一些更加适合这种方法的时候,你可以使用基于对象的编程技术。
类和对象是面向对象编程的两个主要概念一个类创造了一种新的 类型 ,而对象就是类的实例。一种观点是:你可以把 int 类型的变量翻译为存储着整型的变量,这个变量是 int 类的一个实例。

注意整型被看待为一个 int 类的对象。这一点与 C++ 和 Java ( 早于 1.5 版本)不同。在这些语言中,整型被看成一种基本数据类型。

属于对象或者类的变量被称作。一个对象可以通过使用 属于 类的函数实现一定的功能。这些函数被称作类的方法。这个术语是非常重要的,因为它帮助我们区分独立的函数和变量及属于对象或者类的变量和函数。总的来说,域和方法可以被看作类的属性

域有两种类型 - 它们可以属于每一个类的实例(也就是对象),也可以属于类本身。他们被分别称作实例变量和类的变量。

————————————————
原文作者:Python 2.11. 面向对象编程 | 正文 |《Python 简明教程 2018》| Python 技术论坛

使用 class 关键字来创建一个类。命名:首字母大写 + 冒号(:)

在类中定义属性和功能,def() 定义功能。

class Calculator:

    # 类的固有属性
    name='Good calculator' 

    # 初始化
    def __init__(self, name, price):
        self.name=name   # 固有属性会被初始化的定义覆盖
        self.p=price     # 可以不同名,只要赋了值就行。

    # 类的功能,如同定义函数 
    def add(self,x,y):    # self 在类中默认的参数,会被传递下来
        print(self.name)    
        result=x+y
        print(result)
    def minus(self,x,y): 
        result= x-y
        print(result)

实例化:通过调用类名的方式创建实例:

calcul=Calculator('Bad calculator' , 12)

calcul.name
>>>'Bad calculator'

固有属性会被初始化的定义覆盖。

calcul.add(2,6)

>>> Good calculator
>>> 8

关于 self

类的方法与普通的函数相比只有一个区别: 他们在入口参数表的开头必须有一个额外的形式参数self ,但是当你调用这个方法的时候,你不会为这个参数赋予任何一个值,Python 会提供给它。这个特别的参数指向对象本身这就是 self 特殊的地方。这也意味着如果你有一个不声明任何形式参数的方法,却仍然有一个入口参数 —— self 。

Python 中的 self 和 C++ 中的 this 指针以及 Java 和 C# 中的 this 引用等价。

在调用这个类的实例化对象(calcul)的方法(如add)的时候,Python 会把调用的语句自动的转换成Calculator.add(calcul, arg1, arg2) 

__init__ 方法(初始化)

__init__ 方法将在类的对象被初始化(也就是创建)的时候自动的调用。这个方法将按照你的想法初始化 对象(通过给对象传递初始值)。请注意这个名字的开头和结束都是双下划线。

这个方法除了通常的 self 变量之外,还有一个参数 name。带点的标记 self.name 表示有一个叫做“name” 的域是这个类的一部分,而另外一个 name 是一个局部变量。只能通过 self 来指向同一个对象的变量和方法。这被称为 属性引用 (attribute reference) 。

“实例化”操作和调用函数很相似。Python在实例化操作时的一系列工作如下:

1.Python看到了Calculator()并且知道了它是你定义过的一个类。
2. Python创建了一个空对象,里边包含了你在该类中用def创建的所有函数。
3.然后Python回去检查你是不是在里边创建了一个_init_函数,如果有创建,它就会调用这个函数,从而对你新创建的空对象实现了初始化。
4.在Calculator的_init_函数里,有一个多余的函数叫做self,这就是Python为我们创建的空对象,而我们可以为它设置一些变量进去,还可以加几个函数,如:self.add(1,2)
5.最后Python将这个新建的对象赋给一个叫calcul的变量,以供后面使用。

类像一种模板,然后可以用它创建和这个类有相同属性的副本并将它赋予给一个对象(实例化)。

类和对象中的变量

类和对象中的数据的部分(也就是域)并不是什么特别的东西,只是一些 绑定 到类或者对象命名空间的普通的变量。这意味着这些变量只在和这些类和对象有关的上下文中有效。这就是为什么他们被称作 命名空间 。有两种类型的 域 – 类变量和对象变量。这是通过他们是 属于 类还是 属于 对象这一点来区分的。

类变量是共享的 – 他们可以通过所有这个类的对象来访问。类变量只有一份拷贝,这意味着当一个对象改变了一个类变量的时候,改变将发生在所有这个类的对象中。(例如前面Calculator类中的name)

所有的类成员都是公共的。只有一种情况除外:如果你使用 双下划线前缀 (例如 __privatevar )时,Python 会使用命名粉碎规则 (name-mangling) 作用于这个变量,并使其变为私有变量

对象变量属于每一个对象(实例)自身。在这种情况下,每一个对象都有属于它自己的域(在不同的对象中,这些变量不是共享的,它们也并不相关,仅仅是名称相同。

给 C++/Java/C# 使用者的提示
在 Python 中,所有的成员(包括数据成员)都是 公共的 ,所有的方法都是 虚拟的。

————————————————
原文作者:Python 技术论坛文档:《Python 简明教程(2018)》
转自链接:https://learnku.com/docs/byte-of-python/2018/oop/3348#b25130

classmethod 类方法

classmethod修饰符@classmethod修饰符 是一个函数修饰符,它表示接下来的是一个类方法,对应的函数不需要实例化,不需要 self 参数(不需要外部参数,需要self的是实例方法),但第一个参数需要表示自身类cls 参数,可以调用类的属性,类的方法,实例化对象等。

class A(object):
    bar = 1
    def func1(self):  
        print ('foo') 
    @classmethod
    def func2(cls):
        print ('func2')
        print (cls.bar)
        cls().func1()   # 调用 foo 方法
 
A.func2()               # 不需要实例化,直接类名.方法名()来调用

staticmethod 静态方法

@staticmethod不需要表示自身对象的self,还不需要自身类的cls参数,就跟使用函数一样。

class C(object):
    @staticmethod
    def f():
        print('runoob');
 
C.f();          # 静态方法无需实例化
cobj = C()
cobj.f()  

魔术方法

有一些方法,如 __init__和__del__ 方法,它们在类中具有特殊意义。

魔术方法用于模仿内置类型的某些行为。 例如,如果你想为你的类使用 x[key] 索引操作(就像你列表和元组使用它一样),那么你所要做的就是实现 __getitem __() 方法,这样你的工作就已经完成了。 如果你思考一下,这就是 Python 本身为 list 类所做的事情!

下表列出了一些有用的魔术方法:

    __init__(self, ...)
        在返回新创建可以使用的对象之前调用此方法。

    __del__(self)
        在对象被销毁之前调用(具有不可预测时机,所以避免使用它)

    __str__(self)
        当我们使用 print 函数或使用 str() 时调用。

    __lt__(self, other)
        使用小于( less than )运算符(<)时调用。 同样,所有运算符都有特殊的方法(+,> 等)

    __getitem__(self, key)
        使用 x[key] 索引操作时调用。

    __len__(self)
        当内置的 len() 函数用于序列对象时调用。

————————————————
原文作者:Python
转自链接:2.15. 更多知识 | 正文 |《Python 简明教程 2018》| Python 技术论坛

继承

面向对象编程的主要优势之一就是代码的重用,一种获得代码重用的主要方式就是继承体系。继承可以被想象成为类之间的一种类型和子类型的关系的实现。

可能存在一类数据,它们有一些共同的特征,可能涉及到共同添加新的属性,因此可以构造一个共同的类去继承,使得操作更灵活。一个子类型的对象可以被当作父类型的实例。

假设你想要写一个程序来跟踪一所大学之中的老师和同学。他们有一些共同的特征,比如名字、年龄、地址等。他们还有一些独有的特征,比如对老师来说有薪水、课程、离开等,对学生来说有成绩和学费。你当然可以为这两种类型构建两种独立的类来驱动程序。但是当需要添加一个共同的属性的时候,意味着需要在这两个独立的类中同时添加。这很快就会变得非常笨拙。
一个更好的办法就是构造一个共同的类  SchoolMember ,然后在让老师和学生分别 继承 这个类。换句话说,他们都是这个类型(类)的子类型,之后我们也可以为这些子类型添加独有的属性。

class SchoolMember:
    '''代表了学校中的任何一个成员'''
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print('(Initialized SchoolMember: {})'.format(self.name))

    def tell(self):
        '''告诉我细节'''
        print('Name:"{}" Age:"{}"'.format(self.name, self.age), end=" ")

class Teacher(SchoolMember):
    '''表征一个老师'''
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)
        self.salary = salary
        print('(Initialized Teacher: {})'.format(self.name))

    def tell(self):
        SchoolMember.tell(self)
        print('Salary: "{:d}"'.format(self.salary))

class Student(SchoolMember):
    '''表征一个学生'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)
        self.marks = marks
        print('(Initialized Student: {})'.format(self.name))

    def tell(self):
        SchoolMember.tell(self)
        print('Marks: "{:d}"'.format(self.marks))

t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 25, 75)

# 输出一个空行
print()

members = [t, s]
for member in members:
    # 所有的老师和学生都可用
    member.tell()

 为了使用继承,在类名之后的括号中指明父类的类名

之后我们可以看到在 __init__ 方法中,通过  self 变量显式的调用了父类的 __init__ 方法来初始化子类对象中属于父类的部分。这非常重要,请记住 – 既然我们在  Teacher 和 Student 子类中定义了 __init__ 方法,Python 不会自动的调用父类 SchoolMember 中的构造方法,你必须显式的调用。相反的,如果我们不定义子类的 __init__ 方法,Python 将会自动地调用父类中的构造方法。

在每个子类之中定义了另一个新的 tell 方法,调用 Teacher.tell 的时候, Python 将会使用子类中 tell 方法,而非父类的。然而,如果我们没有在子类中定义 tell 方法,Python 将使用父类中的方法。Python 总是首先在实际的子类中寻找方法,如果不存在,将会按照子类声明语句中的顺序,依次在父类之中寻找(在这里我们只有一个父类,但是你可以声明多个父类)。

(Initialized SchoolMember: Mrs. Shrividya) //初始化父类
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)
//先完成父类的tell,设置其print后不换行
Name:"Mrs. Shrividya" Age:"40" Salary: "30000" 
Name:"Swaroop" Age:"25" Marks: "75"

注意术语 – 如果有超过一个类被列在继承元组之中,这就叫做多重继承。

————————————————
原文作者:Python 技术论坛文档:《Python 简明教程(2018)》
转自链接:https://learnku.com/docs/byte-of-python/2018/oop/3348#2dde30
版权声明:翻译文档著作权归译者和 LearnKu 社区所有。转载请保留原文链接

文件读写

使用 read, readline 或 write 中的恰当方法可以读取或写入文件。对文件的读写能力取决于你打开文件时选择的模式。当你处理完文件后,你可以使用 close 方法告诉 Python 你已经使用完文件了。

open() 方法

open(name,mode) 打开文件,并返回(file)文件对象。

text='add the information'
text2=open('file_name.txt','w') 
text2.write(text)
text2.close()  # 打开的文件要关闭

# 例2
f = None
f = open("poem.txt")
# 我们通常读取文件的语句
while True:
    line = f.readline()
    if len(line) == 0:
        break
    print(line, end='')

注意:使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。

open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。mode 决定了打开文件的模式:

‘w’:打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。(文件默认保存到当前程序的文件夹中)

write方法不会在字符串的结尾添加换行符('\n'),需要自行添加。

‘a’:(append)打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。

‘r’:以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。

更多……

file 对象常用的函数:

file.read([size]):从文件读取指定的字节数,如果未给定或为负则读取所有。

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

os.sep 变量 - 它会根据你的操作系统变换目录分隔符,比如 GNU/Linux,Unix,macOS 下是 '/', Windows 下就会是 '\\'。使用 os.sep 代替直接用某个分割符可以让我们的程序具有移植性,也就是可能跨所有平台使用。
原文作者: 2.10. 解决问题的思路 | 正文 |《Python 简明教程 2018》| Python 技术论坛

Unicode

英语和非英语字符都可以用 Unicode 码表示(请参阅本节末尾的文章了解更多信息),默认情况下 Python 3 使用 Unicode 存储字符串变量(想想所有我们用单或双或三重引号包裹的文本引号)。

注意:如果你使用的是 Python 2 ,并且我们希望能够读取和编写其他非英语语言,我们需要使用 unicode 类型,所有内容都以字符 u 开头,例如:u"hello world" 。

当数据通过网络发送时,我们需要以字节为单位发送数据...... 这是计算机易于理解的方式。 将 Unicode 码(这是 Python 在存储字符串时使用的)转换为字节的规则称为编码。 一种流行的编码方式是 UTF-8 。 我们可以通过在 open 函数中使用一个简单的关键字参数来读写 UTF-8 。

# encoding=utf-8
import io

f = io.open("abc.txt", "wt", encoding="utf-8")
f.write(u"Imagine non-English language here")
f.close()

text = io.open("abc.txt", encoding="utf-8").read()
print(text)

我们使用 io.open 然后在第一个 open 语句中使用 encoding 参数对信息进行编码,然后在解码信息时再在第二个 open 语句中使用该参数。 请注意,我们应该只在文本模式下使用 open 语句时的使用编码。
每当我们编写一个使用 Unicode 文字的程序(通过在字符串之前放置一个 u )就像我们上面使用的那样,我们必须确保 Python 本身被告知我们的程序使用 UTF-8,我们必须把 # encoding=utf-8 注释在我们程序的顶部。

————————————————
原文作者:Python 转自链接:2.12. 输入与输出 | 正文 |《Python 简明教程 2018》| Python 技术论坛

Pickle

Python 提供了一个标准模块 pickle,你可以使用该模块将任何简单的 Python 对象存储在文件中,然后可再次取回。这个过程也被称为持久化存储对象。

import pickle

# 这里我们将存储对象的文件的名称
shoplistfile = 'shoplist.data'
# 要买的东西的清单
shoplist = ['apple', 'mango', 'carrot']

# 写入文件
f = open(shoplistfile, 'wb')
# 将对象存储到文件
pickle.dump(shoplist, f)
f.close()

# 销毁 shoplist 变量
del shoplist

# 从存储中读回
f = open(shoplistfile, 'rb')
# 从文件加载对象
storedlist = pickle.load(f)
print(storedlist)

要将对象存储在文件中,必须先以二进制写入模式  open 文件,然后调用 pickle  模块的 dump 函数将对象保存到文件  file 中去,这个过程叫做 pickling。

之后,我们可使用 pickle  模块的 load 函数来检索对象并返回。此过程称为 unpickling 。

NumPy IO 方法

NumPy IO | 菜鸟教程

Numpy 可以读写磁盘上的文本数据或二进制数据。

NumPy 为 ndarray 对象引入了一个简单的文件格式:npy。npy 文件用于存储重建 ndarray 所需的数据、图形、dtype 和其他信息。

常用的 IO 函数有:

  • load() 和 save() 函数是读写文件数组数据的两个主要函数,默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为 .npy 的文件中。
  • savez() 函数用于将多个数组写入文件,默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为 .npz 的文件中。
  • loadtxt() 和 savetxt() 函数处理正常的文本文件(.txt 等)

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。 

NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。

Numpy 可以读写磁盘上的文本数据或二进制数据。NumPy 为 ndarray 对象引入了一个简单的文件格式:npy。

异常处理

我们将所有可能引发异常或错误的语句放入 try 语句块中,然后将对应错误或异常的处理程序放入  except 子句(程序块)中。  except 子句会处理单个特定的错误或异常,或是一个带括号的错误或异常列表。 如果没有提供错误或异常的名字, 它将处理 所有的 错误和异常。
请注意,每个 try 子句之后,至少要有一个与之关联的 except 子句。不然,一个单独的 try 语句块没有什么意义。

class ShortInputException(Exception):
    '''用户定义的异常对象'''
    def __init__(self, length, atleast):
        Exception.__init__(self)
        self.length = length
        self.atleast = atleast

try:
    text = input('Enter something --> ')
    if len(text) < 3:
        raise ShortInputException(len(text), 3)
    # 其他程序可以在这里正常执行
except EOFError:
    print('Why did you do an EOF on me?')
except ShortInputException as ex:
    print(('ShortInputException: The input was ' +
           '{0} long, expected at least {1}')
          .format(ex.length, ex.atleast))
else:
    print('No exception was raised.')

引发异常:可以用 raise 语句 引发( raise ) 异常,需要提供错误或异常的名字以及被 抛出( thrown ) 的异常对象。错误的类通过 as 把错误或异常对应的对象储存到了命名的变量中。这类似于函数调用中的变量和参数。

输出:

Enter something --> a
ShortInputException: The input was 1 long, expected at least 3

Enter something --> abc
No exception was raised.

可以使用一个与 try..except 语句块关联的 else 子句。  else 子句在没有错误发生时将会执行。

如果有任何未处理的错误和异常,默认的 Python 处理程序将被调用,它只会终止程序运行并打印出一条异常信息。

Try … Finally

假设要在程序中读取一个文件。如何保证无论是否引发错误,文件对象都被正确关闭? 可以在最后使用 finally 语句块来完成。

with 语句

with 语句和 open 函数一起使用 —— with open 实现自动完成文件关闭。

with open("poem.txt") as f:
    for line in f:
        print(line, end='')

with 语句隐藏地使用了一个规则。它获取了 open 语句返回的对象,这里我们称之为 “thefile” 。 

它开始它下面的这个代码块前 总是 调用 thefile.__enter__ 函数,在离开这个代码块后 总是 调用 thefile.__exit__ 。因此,被我们写入 finally 语句块的代码会被 __exit__ 方法自动完成。这避免我们重复地显示使用 try..finally 语句。

标准库

sys 模块

sys 模块包含特定系统的功能。

sys.argv 列表包含了命令行参数。

sys. version_info 给出版本信息的元组。

logging 模块

如果你希望将一些调试消息或重要消息存储在某个地方,以便你可以检查你的程序是否按照预期运行,可以将这些信息「存在某地」,这可以用 logging 模块收集。

import os
import platform
import logging

if platform.platform().startswith('Windows'):
    logging_file = os.path.join(os.getenv('HOMEDRIVE'),
                                os.getenv('HOMEPATH'),
                                'test.log')
else:
    logging_file = os.path.join(os.getenv('HOME'),
                                'test.log')

print("Logging to", logging_file)
# 配置 logging 模块将所有信息以特定格式写入指定文件。
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s : %(levelname)s : %(message)s',
    filename=logging_file,
    filemode='w',
)

logging.debug("Start of the program")
logging.info("Doing something")
logging.warning("Dying now")

输出:

Logging to /Users/swa/test.log

$ cat /Users/swa/test.log
2014-03-29 09:27:36,660 : DEBUG : Start of the program
2014-03-29 09:27:36,660 : INFO : Doing something
2014-03-29 09:27:36,660 : WARNING : Dying now

配置 logging 模块将所有信息以特定格式写入指定文件。 

os 模块:与操作系统进行交互的模块。

常见:os.path.join() 组合路径,使用特殊函数而不仅仅是将字符串拼接到一起的原因是,这个函数将确保完整位置与操作系统预期的格式相同。注意:我们在这里使用的 join() 方法是 os 模块的一部分,它与我们在本书的其他地方使用的字符串方法 join() 不同。

Python与MATLAB文件 

Python 导入 MATLAB 数组:

方法一:将数组导出为text文件格式(fprint),再使用NumPy IO 方法的loadtxt()函数导入。

方法二:from scipy.io import savemat,loadmat

filename = "E:/系统漂移/MATLAB/mat/20201018.mat"
data2 = loadmat(filename)

出现 Please use HDF reader for matlab v7.3 files 错误,采用第三种方法。

方法三:import h5py,导入mat文件

import h5py
#导入cell
myfile = h5py.File('20201018signalLine.mat', 'r') 
ky=myfile['temp_ss2'] # temp_ss2是myfile.key
data = [] 
for i in range(0,ky.size):
    a = [myfile[element[i]][:] for element in myfile['temp_ss2']]
    data.append(a)

# 导入普通数组
data2 = myfile['temp_st2'][:]

导出mat文件: 

SciPy Matlab 数组 | 菜鸟教程 :

NumPy 提供了 Python 可读格式的数据保存方法。

SciPy 提供了与 Matlab 的交互的方法。SciPy 的 scipy.io 模块提供了很多函数来处理 Matlab 的数组。

savemat() 方法可以导出 Matlab 格式的数据。该方法参数有:

  • filename - 保存数据的文件名。
  • mdict - 包含数据的字典。
  • do_compression - 布尔值,指定结果数据是否压缩。默认为 False。

将数组作为变量 "vec" 导出到 mat 文件:

from scipy import io
import numpy as np
arr = np.arange(10)
io.savemat('arr.mat', {"vec": arr})

注意:MATLAB的有效变量名称以字母开头,后跟字母、数字或下划线MATLAB区分大小写,因此 A 和 a 不是同一变量。 

将python中数据保存为matlab数据格式.mat(嵌套list转变为cell格式)_碧海蓝天-CSDN博客

软件开发过程

  1. 需求(分析需求)
  2. 规格(确定规格)
  3. 编写(编写代码)
  4. 测试(测试与调试)
  5. 使用(操作或部署)
  6. 维护(优化与重构)

上面编写备份脚本的过程是一种推荐的编写程序的流程:一开始进行需求分析和系统设计,然后实现一个简单的版本,对它进行测试,有 bug 就进行调试。接着使用它,确保它能像设计的那样正常工作。再增加你想要的新功能,并继续重复编写 - 测试 - 使用的循环,直到软件实现预期的功能。
记住:

软件是生长出来的,不是构建出来的。—— Bill de hÓra

————————————————
原文作者:Python 2.10. 解决问题的思路 | 正文 |《Python 简明教程 2018》| Python 技术论坛

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值