【Python】Python学习笔记

Python基础

一、中文编码、注释与标准文档

1.中文编码

若只需要在单个文件中指定中文编码,只需在文件开始处添加

# _*_ coding: UTF-8 _*_

即可。

如果要在整个工程里设置中文编码,则需要在编辑器中设置工程的编码为UTF-8。

2.单行注释

python使用#来接单行注释

3.多行注释

python使用'''"""(三个单引号或三个双引号)来包含多行注释

如:

# 这是单行注释
'''
这是使用三个单引号的
多行注释
'''
"""
这是使用三个双引号的
多行注释
"""

4.标准文档

官方文档

二、标识符与代码块

1.标识符规则

  • python标识符大小写敏感。
  • python中以下划线开头的标识符有特殊的含义,以单下划线开头的标识符代表不能直接访问的类属性,需要通过类提供的接口进行访问,不能用from xxx import *导入,如:_value。
  • 以双下划线开头的标识符代表类的私有成员,如:__value
  • 以双下划线开头和结尾的标识符代表python里特殊方法的专用标识符,如:__init__()代表类的构造函数。

2.保留字符

and exec not
assert finally or
break for pass
class from print
continue global raise
def if return
del import try
elif in while
else is with
except lambda yield

3.代码块

python与C系列语言最大的不同就是python没有了{}囊括的代码块,而采用了缩进来表示代码块,即在一个代码块中的代码采用同等数量的数量的缩进,缩进的数量按空格的数量计算,采用同一缩进量的代码属于同一格代码块。

如:

if ture:
    a = 1
    b = 2

a=1;b=2同属于if语句的代码块中。

python空行规范

  • 类与其他代码块之间需要空两行

  • 方法体与其他代码块之间需要空一行

  • 全局函数与其他代码块之间需要空两行

    如:

    class Person:
        names = 'aa'
    
        def __init__(self, age, name):
            self.age = age
            self.name = name
            addr = 'beijing'
            names = "bb"
    
        def GetName(self):
            self.sex = 'female'
            print('my name is ' + self.names)
    
        @staticmethod
        def PP():
            print(names)
        
        @classmethod
        def OO(cls):       
            print(cls.names)
    
    
    p = Person(18, 'lusa')
    

4.多行语句

由于python即使用了;来分割同行的不同语句,同时通过新行来结束上一句语句,所以如果代码需要换行的话需要使用 \来分割多行。

如:

a = b \
	+ c \
    + d

例外:包括在[](){}中的语句换行不需要使用\

三、变量及数据结构

python支持

  • Numbers-数字
  • String-字符串
  • List-列表
  • Tuple-原表
  • Dictionary-字典

几种数据类型。

1.Numbers

其中Numbers又分为

Numbers
int
有符号整型
long
长整型-使用小写l或大写L表示
float
浮点型
complex
复数-使用a+bj表示或complex函数生成

需要注意的是python不支持double。

long在python3.x以后被移除。

2.String

使用Python字符串时首先需要明确一点,就是Python不支持单字符,在Python中单字符也被当作字符串使用。

Python的字符串可以使用',",''',"""来标识字符串,有单引号和双引号来表示字符串就够了,那么为什么Python要使用三单引号'''和三双引号"""来标识字符串呢?

'''"""的优点

要想直观的了解三单引号和三双引号的优点,我们首先使用C#字符串来写一个SQL语句

string sql="select xm as 姓名,xb as 性别 from db_table where xm = @xm and xb = @xb and (bm like '%666' or bm like '666%') order by grade > 90 desc";
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@xm", txtName.Text);
cmd.Parameters.AddWithValue("@xb", txtSex.Text);
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();

我们再使用Python写一句同样的SQL语句

sql = '''
select xm as 姓名,xb as 性别 from db_table 
where xm = '{0}' and xb = {1} and (bm like '%666' or bm like '666%') 
order by grade > 90 desc
'''.format(txtName.Text,txtSex.Text)
cuesor = conn.cursor()
cursor.execute(sql)
cursor.close()

有没有发现Python在写sql字符串时十分优雅呢?尤其是在写很长的sql语句时这个效果尤为突出,得益于Python三引号字符串的可换行支持,Python的sql可以在传参的同时保留sql的优雅格式,极大的提高了sql的可阅读性。

python的字符串是不可变的,当我们对字符串进行操作时,python都会生成新的字符串,而不会在旧的字符串的基础上进行修改。

  • 与C系列语言对字符串的操作有些差异的是python使用*来重复字符串,如:
str = 'a'
str2 = str*2 #str2存储的是'aa'
  • String支持从前索引和从后索引,从前索引的首地址索引为0,从后索引的末地址为-1
a b c d
0 1 2 3
-4 -3 -2 -1
  • python支持直接通过索引截取子字符串,如:
str = 'abcd'
str2 = str[1:3] #str2存储的是'bc'

转移字符

字符 说明
\(在行尾时) 续行符
\ 反斜杠符号
单引号
" 双引号
\a 响铃
\b 退格(Backspace)
\e 转义
\000
\n 换行
\v 纵向制表符
\t 横向制表符
\r 回车
\f 换页
\oyy 八进制数,y 代表 0~7 的字符,例如:\012 代表换行
\xyy 十六进制数,以 \x 开头,yy代表的字符,例如:\x0a代表换行
\other 其它的字符以普通格式输出

两个特殊的字符串运算符

字符 说明 实例
r/R 原始字符串 - 原始字符串:所有的字符串都是直接按照字面的意思来使用,没有转义特殊或不能打印的字符。 原始字符串除在字符串的第一个引号前加上字母r(可以大小写)以外,与普通字符串有着几乎完全相同的语法。 print(r’/n’)
输出结果:
/n
% 格式字符串
u 在字符串的前面加上一个字母u即表示创建Unicode字符串,可以通过\u+Unicode编码向字符串中插入任何Unicode支持的字符 print(u’a\u2201a’)
输出结果:
a⤀a

字符串格式化

Python中的字符串格式化和C基本保持一致,插入整型也是用的%d

符号 说明
%c 格式化字符及其ASCII码
%s 格式化字符串
%d 格式化整数
%u 格式化无符号整型
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 作用同%e,用科学计数法格式化浮点数
%g %f和%e的简写
%G %F 和 %E 的简写
%p 用十六进制数格式化变量的地址

格式化操作辅助指令

符号 说明
* 定义宽度或者小数点精度
- 用做左对齐
+ 在正数前面显示加号( + )
<sp> 在正数前面显示空格
# 在八进制数前面显示零(‘0’),在十六进制前面显示’0x’或者’0X’(取决于用的是’x’还是’X’)
0 显示的数字前面填充’0’而不是默认的空格
% ‘%%‘输出一个单一的’%’
(var) 映射变量(字典参数)
m.n. m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)

String内置函数

方法 描述
string.capitalize() 把字符串的第一个字符大写
string.center(width) 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
string.count(str, beg=0, end=len(string)) 返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
string.decode(encoding=‘UTF-8’, errors=‘strict’) 以 encoding 指定的编码格式解码 string,如果出错默认报一个 ValueError 的 异 常 , 除非 errors 指 定 的 是 ‘ignore’ 或 者’replace’
string.encode(encoding=‘UTF-8’, errors=‘strict’) 以 encoding 指定的编码格式编码 string,如果出错默认报一个ValueError 的异常,除非 errors 指定的是’ignore’或者’replace’
string.endswith(obj, beg=0, end=len(string)) 检查字符串是否以 obj 结束,如果beg 或者 end 指定则检查指定的范围内是否以 obj 结束,如果是,返回 True,否则返回 False.
string.expandtabs(tabsize=8) 把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8。
string.find(str, beg=0, end=len(string)) 检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1
string.format() 格式化字符串
string.index(str, beg=0, end=len(string)) 跟find()方法一样,只不过如果str不在 string中会报一个异常.
string.isalnum() 如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False
string.isalpha() 如果 string 至少有一个字符并且所有字符都是字母则返回 True,否则返回 False
string.isdecimal() 如果 string 只包含十进制数字则返回 True 否则返回 False.
string.isdigit() 如果 string 只包含数字则返回 True 否则返回 False.
string.islower() 如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
string.isnumeric() 如果 string 中只包含数字字符,则返回 True,否则返回 False
string.isspace() 如果 string 中只包含空格,则返回 True,否则返回 False.
string.istitle() 如果 string 是标题化的(见 title())则返回 True,否则返回 False
string.isupper() 如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
string.join(seq) 以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
string.ljust(width) 返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
string.lower() 转换 string 中所有大写字符为小写.
string.lstrip() 截掉 string 左边的空格
string.maketrans(intab, outtab]) maketrans() 方法用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
max(str) 返回字符串 str 中最大的字母。
min(str) 返回字符串 str 中最小的字母。
string.partition(str) 有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分 成 一 个 3 元 素 的 元 组 (string_pre_str,str,string_post_str),如果 string 中不包含str 则 string_pre_str == string.
string.replace(str1, str2, num=string.count(str1)) 把 string 中的 str1 替换成 str2,如果 num 指定,则替换不超过 num 次.
string.rfind(str, beg=0,end=len(string) ) 类似于 find() 函数,返回字符串最后一次出现的位置,如果没有匹配项则返回 -1。
string.rindex( str, beg=0,end=len(string)) 类似于 index(),不过是从右边开始.
string.rjust(width) 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
string.rpartition(str) 类似于 partition()函数,不过是从右边开始查找
string.rstrip() 删除 string 字符串末尾的空格.
string.split(str="", num=string.count(str)) 以 str 为分隔符切片 string,如果 num 有指定值,则仅分隔 num+ 个子字符串
string.splitlines(keepends) 按照行(’\r’, ‘\r\n’, \n’)分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
string.startswith(obj, beg=0,end=len(string)) 检查字符串是否是以 obj 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查.
string.strip(obj) 在 string 上执行 lstrip()和 rstrip()
string.swapcase() 翻转 string 中的大小写
string.title() 返回"标题化"的 string,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
string.translate(str, del="") 根据 str 给出的表(包含 256 个字符)转换 string 的字符,要过滤掉的字符放到 del 参数中
string.upper() 转换 string 中的小写字母为大写
string.zfill(width) 返回长度为 width 的字符串,原字符串 string 右对齐,前面填充0

3.Tuple

==元组类似与C#中readonly List,是一个只读列表,但是python的元组的元素可以是不同的类型,python用()来表示元组。==元组支持存储不同类型元素,如:

t = ('a',1,3.14)

这里的元组只读及元素不可修改

创建空元组

t = ()

创建一个值的元组

t = (12,)//逗号不可省略

需要特别注意的是,不可省略,如果省略了,t=(12)就等于t=12

元组的分片操作

t = (1,2,3,4,5,6)
print(t[1:3])
#输出结果为2,3

分片操作可以批量的取元组中的数据,值不能取到3号索引,只能取到3号索引的前一位。

Tuple的+和*操作

和字符串一样,列表的+运算用于组合列表,列表的*运算用于重复列表,如:

tu1 = (1, 2)
tu2 = tu1 + tu1
print(tu2)
tu3 = tu1*3
print(tu3)

输出结果:

[1, 2, 1, 2]
[1, 2, 1, 2, 1, 2]  

Tuple的无关分隔符

任意无符号对象,只要以,分隔,Python都将其是为元组,如

print 1, 2, 'a', 3.14
tu = x, y = 1, 'b'

1, 2, 'a', 3.14,会被视为一个元组,及print打印的事实上是一个元组,tu也会被Python默认转换成一个元组,当然x,y还是可以才开使用的。

Python内置元组操作函数

方法 描述
cmp(tuple1, tuple2) 比较两个元组元素。
len(tuple) 计算元组元素个数。
max(tuple) 返回元组中元素最大值。
min(tuple) 返回元组中元素最小值。
tuple(seq) 将列表转换为元组。

4.List

List就和C#中的List基本一致,但是python的List更灵活

List初始化

List的初始化使用[],我们可以使用‘数字’、‘字符串’、‘元组’或‘列表’来初始化一个列表,列表也支持分片操作。

python的列表可以在一个列表中存储不同类型的元素。

并且提供一些基础函数

  • index:从列表中找出某个元素的位置,如果有多个相同的元素,则返回第一个元素的位置,如果没有找到则抛出异常。

  • count:统计某个元素在列表中出现的次数。

  • append:列表末尾增加新的元素。

  • extend:将一个新列表的元素添加到原列表中。

    注意到,虽然 append 和 extend 可接收一个列表作为参数,但是 append 方法是将其作为一个元素添加到列表中,而 extend 则是将新列表的元素逐个添加到原列表中。

  • insert:将某个元素添加到某个位置。

  • pop:移除列表中的一个元素(默认是最后一个),并且返回该元素的值。

  • remove:移除列表中的某个匹配元素,如果有多个匹配,则移除第一个。

  • reverse:将列表中的元素进行反转。

  • sort:对列表进行排序,注意该方法会改变原来的列表,而不是返回新的排序列表,另外,sort 方法的返回值是空。

    如果要使用sort对列表进行排序,那么列表中元素应该保持同一类型。

  • clear:清空列表。

列表的集合运算

Python提供内置的set()函数来对元素集进行集合运算,set函数支持所有可迭代的对象,包括list和tuple。只要是set函数支持的对象,尽管进行运算的两个对象不是相同类型也依旧可以进行集合运算,如:

取交集

l1 = [1, 'a', True, 2, 3]
l2 = (1, 'a', True, 4, 5)
print(set(l1) & set(l2))

输出结果:

{
    
    11, 'a'}

注意:当bool值进行集合运算时会被转换成0和1,但是这个0和1不会和数字的0和1重复。

Python集合运算符

运算符 说明
| 取并集
& 取交集
- 取差集
^ 取对称差集

集合运算符支持set()函数返回的set集合作为运算对象。

List的+和*操作

和字符串一样,列表的+运算用于组合列表,列表的*运算用于重复列表,如:

li = [1, 2]
li2 = li + li
print(li2)
li3 = li*3
print(li3)

输出结果:

[1, 2, 1, 2]
[1, 2, 1, 2, 1, 2]  

Python内置列表操作函数

函数 描述
cmp(list1, list2) 比较两个列表的元素
len(list) 列表元素个数
max(list) 返回列表元素最大值
min(list) 返回列表元素最小值
list(seq) 将元组转换为列表

List内置函数

方法 描述
list.append(obj) 在列表末尾添加新的对象
list.count(obj) 统计某个元素在列表中出现的次数
list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list.index(obj) 从列表中找出某个值第一个匹配项的索引位置
list.insert(index, obj) 将对象插入列表
[list.pop(index=-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
list.remove(obj) 移除列表中某个值的第一个匹配项
list.reverse() 反向列表中元素
list.sort(cmp=None, key=None, reverse=False) 对原列表进行排序

5.Dictionary

Python的字典和C#中的字典的用法基本一致,不同的时Python使用{}来创建字典,使用:来连接键值对,使用,来分割元素。如:

dic = {
    
    'a': True, 2: "Py", "bb": 3}

Python自定更强大的地方在于,Python字典在一个字典里支持不同类型的键和值。

字典的键只能是数字、字符串或元组类型,而值没有任何要求。

Python内置字典操作函数

函数 描述
cmp(dict1, dict2) 比较两个字典元素。
len(dict) 计算字典元素个数,即键的总数。
str(dict) 输出字典可打印的字符串表示。
type(variable) 返回输入的变量类型,如果变量是字典就返回字典类型。

Dictionary内置函数

函数 描述
dict.clear() 删除字典内所有元素
dict.copy() 返回一个字典的浅复制
[dict.fromkeys(seq, val]) 创建一个新字典,以序列 seq 中元素做字典的键,val 为字典所有键对应的初始值
dict.get(key, default=None) 返回指定键的值,如果值不在字典中返回default值
dict.has_key(key) 如果键在字典dict里返回true,否则返回false
dict.items() 以列表返回可遍历的(键, 值) 元组数组
dict.keys() 以列表返回一个字典所有的键
dict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
dict.update(dict2) 把字典dict2的键/值对更新到dict里
dict.values() 以列表返回字典中的所有值
[pop(key,default]) 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
popitem() 返回并删除字典中的最后一对键和值。

6.日期和时间

Python的日期时间函数被放在了timedatetimecalender模块下,这里有几个点是需要注意的

time.time()

time.time()函数返回的是从1970年1月1日午夜到当前时间所经过的总时长。

import time
print(time.time())
#当前时间为:2021.2.6 09:51

输出结果:

1612576137.817901

time.localtime()

那么如何输出当前时间呢?答案就是使用time.localtime(time.time())来计算当前时间。

import time
print(time.localtime(time.time()))

输出结果:

time.struct_time(tm_year=2021, tm_mon=2, tm_mday=6, tm_hour=9, tm_min=51, tm_sec=39, tm_wday=5, tm_yday=37, tm_isdst=0)

可以看到,函数返回的不是格式化的2021.2.6 9:51而是一个struct_time时间元组,什么是时间元组?

时间元组

很多Python函数用一个元组装起来的9组数字处理时间:

序号 字段
0 4位数年 2008
1 1 到 12
2 1到31
3 小时 0到23
4 分钟 0到59
5 0到61 (60或61 是闰秒)
6 一周的第几日 0到6 (0是周一)
7 一年的第几日 1到366 (儒略历)
8 夏令时 -1, 0, 1, -1是决定是否为夏令时的旗帜

而struct_time就是其中之一,struct_time的结构:

序号 属性
0 tm_year 2021
1 tm_mon 1 到 12
2 tm_mday 1 到 31
3 tm_hour 0 到 23
4 tm_min 0 到 59
5 tm_sec 0 到 61 (60或61 是闰秒)
6 tm_wday 0到6 (0是周一)
7 tm_yday 1 到 366(儒略历)
8 tm_isdst -1, 0, 1, -1是决定是否为夏令时的旗帜

获取格式化时间

那么如何获取格式化时间呢?

print(time.asctime(time.localtime(time.time())))

输出结果:

Sat Feb  6 10:28:09 2021

time.localtime()返回的是一个字符串,除此之外我们看还可以使用time.strftime()函数来自定义时间格式化格式,如:

print(time.strftime("%H:%M:%S %Y-%m-%d", time.localtime()))

输出结果:

10:51:12 2021-02-06

时间日期格式化符号

符号 描述
%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 当前时区的名称
%% %号本身

time与datetime库

python处理时间处理time模块还可以使用datetime模块,那么time和datetime之间有什么区别呢?

在 Python 文档里,time是归类在Generic Operating System Services中,换句话说, 它提供的功能是更加接近于操作系统层面的。通读文档可知,time 模块是围绕着 Unix Timestamp 进行的。

该模块主要包括一个类 struct_time,另外其他几个函数及相关常量。 需要注意的是在该模块中的大多数函数是调用了所在平台C library的同名函数, 所以要特别注意有些函数是平台相关的,可能会在不同的平台有不同的效果。另外一点是,由于是基于Unix Timestamp,所以其所能表述的日期范围被限定在 1970 - 2038 之间,如果你写的代码需要处理在前面所述范围之外的日期,那可能需要考虑使用datetime模块更好。

datetime 比 time 高级了不少,可以理解为 datetime 基于 time 进行了封装,提供了更多实用的函数。

描述
timedelta 主要用于计算时间跨度
tzinfo 时区相关
time 只关注时间
date 只关注日期
datetime 同时有时间和日期

calendar库

calendar库主要用于处理日历,如:打印2021年2月的日历

print(calendar.month(2021, 1))

输出结果:

    January 2021
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

time库内置函数

函数 描述
time.altzone 返回格林威治西部的夏令时地区的偏移秒数。如果该地区在格林威治东部会返回负值(如西欧,包括英国)。对夏令时启用地区才能使用。
time.asctime([tupletime]) 接受时间元组并返回一个可读的形式为"Tue Dec 11 18:07:14 2008"(2008年12月11日 周二18时07分14秒)的24个字符的字符串。
time.clock( ) 用以浮点数计算的秒数返回当前的CPU时间。用来衡量不同程序的耗时,比time.time()更有用。
time.ctime([secs]) 作用相当于asctime(localtime(secs)),未给参数相当于asctime()
time.gmtime([secs]) 接收时间戳(1970纪元后经过的浮点秒数)并返回格林威治天文时间下的时间元组t。注:t.tm_isdst始终为0
time.localtime([secs]) 接收时间戳(1970纪元后经过的浮点秒数)并返回当地时间下的时间元组t(t.tm_isdst可取0或1,取决于当地当时是不是夏令时)。
time.mktime(tupletime) 接受时间元组并返回时间戳(1970纪元后经过的浮点秒数)。
time.sleep(secs) 推迟调用线程的运行,secs指秒数。
time.strftime(fmt[,tupletime]) 接收以时间元组,并返回以可读字符串表示的当地时间,格式由fmt决定。
time.strptime(str,fmt=’%a %b %d %H:%M:%S %Y’) 根据fmt的格式把一个时间字符串解析为时间元组。
time.time( ) 返回当前时间的时间戳(1970纪元后经过的浮点秒数)。
time.tzset() 根据环境变量TZ重新初始化时间相关设置。

两个time库重要属性

属性 描述
time.timezone 属性 time.timezone 是当地时区(未启动夏令时)距离格林威治的偏移秒数(>0,美洲<=0大部分欧洲,亚洲,非洲)。
time.tzname 属性time.tzname包含一对根据情况的不同而不同的字符串,分别是带夏令时的本地时区名称,和不带的。

calendar内置函数

函数 描述
calendar.calendar(year,w=2,l=1,c=6) 返回一个多行字符串格式的year年年历,3个月一行,间隔距离为c。 每日宽度间隔为w字符。每行长度为21* W+18+2* C。l是每星期行数。
calendar.firstweekday( ) 返回当前每周起始日期的设置。默认情况下,首次载入 calendar 模块时返回 0,即星期一。
calendar.isleap(year) 是闰年返回 True,否则为 False。>>> import calendar >>> print(calendar.isleap(2000)) True >>> print(calendar.isleap(1900)) False
calendar.leapdays(y1,y2) 返回在Y1,Y2两年之间的闰年总数。
calendar.month(year,month,w=2,l=1) 返回一个多行字符串格式的year年month月日历,两行标题,一周一行。每日宽度间隔为w字符。每行的长度为7* w+6。l是每星期的行数。
calendar.monthcalendar(year,month) 返回一个整数的单层嵌套列表。每个子列表装载代表一个星期的整数。Year年month月外的日期都设为0;范围内的日子都由该月第几日表示,从1开始。
calendar.monthrange(year,month) 返回两个整数。第一个是该月的星期几的日期码,第二个是该月的日期码。日从0(星期一)到6(星期日);月从1到12。
calendar.prcal(year,w=2,l=1,c=6) 相当于 print calendar.calendar(year,w=2,l=1,c=6)
calendar.prmonth(year,month,w=2,l=1) 相当于 print calendar.month(year,month,w=2,l=1)
calendar.setfirstweekday(weekday) 设置每周的起始日期码。0(星期一)到6(星期日)。
calendar.timegm(tupletime) 和time.gmtime相反:接受一个时间元组形式,返回该时刻的时间戳(1970纪元后经过的浮点秒数)。
calendar.weekday(year,month,day) 返回给定日期的日期码。0(星期一)到6(星期日)。月份为 1(一月) 到 12(12月)。

7.set集合

python的set集合和C++的set集合的用法基本是一样的,set集合是一个无序不重复序列,python使用{}set()函数来创建set集合,区别字典的地方是{}包括的元素不是键值对,需要注意的是,创建空集合只能通过set()函数。

8.类型转换

Python提供了大量内置类型转换函数:

函数 描述
int(x ,[base]) 将x转换为一个整数
long(x ,[base] ) 将x转换为一个长整数
float(x) 将x转换到一个浮点数
complex(real [,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个序列 (key,value)元组。
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
unichr(x) 将一个整数转换为Unicode字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串

四、运算符

1.算术运算符

Python的算术运算基本和C系列语言没什么区别,唯一的区别在于Python将C系列语言的求幂函数和取整函数直接内置到了Python的运算符里了,如:

运算符 描述
** 求幂运算符,二元运算符,a**b表示求a的b次幂
// 取整运算符,二元运算符,a//b表示a对b取整,如9//4 = 2

2.赋值运算符

和算数运算符一样,Python也将求幂运算和取整运算的赋值运算内置到运算符里。

运算符 描述
**= 幂赋值运算符
//= 取整赋值运算符

3.逻辑运算符

由于Python的底层是用C写的所有C的逻辑运算符(&,|,!)在Python中就不能再使用了,所以Python使用(and,or,not)来做逻辑运算符,用法和&,|,!一样。

4.成员运算符

和前面一样,Python也将判断函数直接内置到运算符中了,Python成员运算符作用就是判断指定序列中是否包含某个指定元素,序列支持字符串,列表和元组。

in 如果指定元素在指定序列中则返回True
not in 如果指定元素不在指定序列中则返回True
li = [1,2,3,4,5]
tu = (1,2,3,4,5)
st = “12345”
a = 1
b = ‘1’
print(a in li)
print(a not in tu)
print(b in st)

返回结果:

True
False
True

5.身份运算符

is 判断两个对象是否来自同一引用
is not 判断两个对象是否不同的引用

Pyhton的身份运算符和C#的is是不一样的,Python的is用于判断两个对象是否来引用同一引用,而C#的is则是判断某一对象是否是指定类型。

使用案例:

a  = 1
b = a
print(a is b)
b = 2
print(a is not b)
c = 2
print(b is c)

输出结果:

True
True
True

这里出现了一个疑问,为什么b和c来自同一引用呢?
我们查看一下b和c的内存地址

print(id(b))
print(id(c))

输出结果:

2324527120200
2324527120200

可以看到b和c指向了同一内存地址,原来Python在对程序优化的时候会将程序中的内容相同的常量存储到一个存储地址中。

五、控制语句

Python的条件语句与C系列语言最大的不同是,Python的条件语句可以不使用()来包含条件表达式,当然也可以是使用,大多数情况下还是建议使用(),以使代码的阅读性更高。

1.if语句

当条if-else语句的用法和C系列基本一致。

if True:
	a=1
	b=1
else:
	a=2
	b=2

其中:是必须的
Python中比较特殊的是else if语句,在Python中使用 elif表示。

2.while循环语句

Python的while循环可以搭配esle使用,当循环跳出时执行else语句,个人感觉没什么实际用处。

a = 0
while a<3:
	print(a)
	a += 1
else:
	print(“循环结束”)

输出结果:

0
1
2
循环结束

3.for循环

在写循环语句之前有一点是需要明确的,及根据Python的设计理念Python已经不使用自增++自减--运算符了,所以需要自增时应使用a += 1

for in

for in的用法和C#的foreach一致,可以遍历任何序列,如:

li = [1,2,3,4,5]
for item in li:
	print(item)
else:
	print(“for end”)

和while一样for也可以配合else使用

for in range()

for in range()就是不同的for循环,通过下标来遍历序列,如:

li = [1,2,3,4,5]
for i in range(len(li)):
	print(li[i])
else:
	print(“for end”)

需要注意实际上for in中是不包含range()的,range只是一个辅助函数,用于确定下标的范围。如果我们直接像下面那样写是会报语法错误的,如:

for i in 4:
	#code

如果我们想让循环只跑4轮,应该用range(4)来确定下标范围,如:

for i in range(4):

continue、break和pass

Python的continue和break的用法和C系列语言基本一致,Python中新增了pass语句,pass语句就是C系列语言中;及空语句,一般用于空循环中维护代码的结构性。

六、函数

1.函数定义

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号**()**。
  • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

如:

def fun(a):
    "打印a的平方并返回"
    b = a*a
    print(b)
    return b

2.函数调用

在调用Python函数时有一点是需要特别注意的,由于Python是解释型语言,Python脚本在运行时是一行一行地放入解释器中进行解释的,因此Pyhton不支持函数的声明定义的分离,所有Python的函数调用必须在定义之后,否则将会报函数未定义。

3.参数传递

在讨论函数参数之前,我们需要了解两个概念:

  • 不可变对象:不可变对象都是不可变类型,Python的不可变类型有数字、字符串、元组,不可变对象指向的内存地址上的内容是不可更改的,如需操作其内容Python会开辟一个新的内存地址来存储编辑后的内容。

  • 可变对象:可变对象都是可变类型,不是不可变类型的类型都是可变类型,包括列表、字典、自定义类型等,可变类型对象指向的内存地址的内容是可更改,操作可变对象的内容时Python不会开辟新的内存,而是直接修改原地址内容。

函数传入不可变对象的原理和C++的传值原理是一样的,函数传入可变对象的原理和C++传址原理是一样的。

传参原理

由于Python的变量都是若类型的,参数也不例外,函数在定义参数时只有名字没有类型,所以Python在调用函数时,参数的传递是根据实参的顺序来给形参赋值的。

关键字参数

Python的函数支持关键字传参,关键字传参的原理是指定实参来赋值指定形参,所以可以无视参数的传入顺序。如:

def fun(a,b,c):
    print(a+b+c)
fun(b = 1,c = 2,a = 3)

默认参数

Python的函数也支持默认参数,原理和C++一样。

单*号不定长参数

Python的不定长参数和C++则有些不同,Python使用*来标识不定长参数,所有形参匹配之外的参数都将存储到不定长参数中,如:

def fun(a,b,*c):
    d = a + b
    for item in c:
        d += item
    print(d)
fun(1,2,3,4)

在这个过程中,1被赋予a,2被赋予b,3和4被赋予c

Python支持不定长参数的单独使用,如:

def fun(*param):
    pass

如果函数的参数只有一个不定长参数,那么函数传入的任何参数都会存储到不定长参数里。

*号不定长参数会将传入的所有参数封装在一个元组里,且单*号不定长参数只支持参数的顺序传入,不支持关键字传入。

当函数只有单*号不定长参数时,单*号不定长参数因该放在最后一个参数,如果不放在最后将会报错:

def fun(*c, t):
    c[0][0] = 5
    print(c[0])
    print(t)

报错:

Traceback (most recent call last):
  File "d:\Codes\Python\MyFirstPython.py", line 9, in <module>
    fun(li, 2)
TypeError: fun() missing 1 required keyword-only argument: 't'

双*号不定长参数

除了单*号不定长参数外,Python还支持双*号不定长参数,*号不定长参数支持关键字传入,不支持顺序传入,双*号不定长参数会将传入的参数封装在一个字典里,其中关键字的名字存入字典的键中,关键字的值存入字典的值中。如:

def fun(t,**d):
    print(t)
    print(d['x'])
    print(d['y'])
fun(1,x=2,y=3)

输出结果:

1
2
3

当函数中同时存在单*号不定长参数和双*号不定长参数时,双*号不定长参数应放在最后一个参数位置,单*号参数应放在倒数第二个参数位置。

4.匿名函数

Python的匿名函数的使用场景是,当函数体只由比较简单的Lambda表达式组成时才使用。匿名函数除了没有函数名,其他的和有名函数没有什么区别。如:

f = lambda a,b=1: a+b
print(f(1))

输出结果:

2

在lambda表达式的结构中,:之前的为参数,:号之后有且只有一条语句,这是由Python语句分割的方式决定的。从上面的例子我们还可以发现,lambda表达式支持默认参数,且自带返回值,lambda表达式将表达式的结果作为返回值,需要注意的是,lambda表达式中不能进行复制操作,否则将报语法错误。

七、模块

一个Python文件就是一个Python模块,一个Python包也是一个Python模块。

1.导入模块(包)

整模块导入

Python使用import+模块名来导入模块,如:

import MyFirstPython

当我们将一个Python作为模块导入到另一个文件时,Python会在工程文件夹下的__pycache文件夹下生成一个模块名对应的pyc文件,如上面的例子则会生成一个PyFirstPython.cpython-39.pyc其中cpython-39为python版本号,这个文件是做什么用的呢?pyc文件是一个二进制文件,且已经经过Python加密,直接打开会显示乱码,pyc的主要作用就是加快模块的导入速度,注意这里是导入速度而非运行速度,pyc文件可以通过反编译器重新反编译成可执行的Python文件。

python支持使用,来分割模块,达到同时导入多个包的目的,如:

import MyfirstPython,MySecondPython

单函数导入

python除了支持整个文件的模块导入,同时也支持只导入模块中的一个函数,python使用from 模块名 import 函数名来从指定模块导入单个函数,如:

from MySecondPython import fun as f

同时,python在导入模块或模块中的函数时可以使用as关键字为模块或函数起别名。

form import还可以使用*来达到import的效果,如:

from MyFirstPython import * #相当于import MyFirstPython

python导入模块时的路径搜索顺序

  • 1、当前目录
  • 2、如果不在当前目录,Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。
  • 3、如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/。

python使用导入模块的全局变量

有一点十分不方便的就是在当前文件下无法直接使用导入模块的全局变量,只能通过为指定变量编写读写函数才能操作全局变量,这是由python的变量规则决定的。

Pyhton模块打包

Python提供了多个打包工具,我使用的是python3.9内置的setuptools库,setuptools库中提供了一个setup函数用于打包模块,具体操作如下:

  • 1.在工程目录下新建一个setup.py文件,这个文件用于配置一些包的必要信息,配置信息都由关键字参数的形式传入setup函数中,具体参数信息如下;

    setup(
        name=about["__title__"],  # 包名称
        version=about["__version__"],  # 包版本
        description=about["__description__"],  # 包详细描述
        long_description=readme,   # 长描述,通常是readme,打包到PiPy需要
        author=about["__author__"],  # 作者名称
        author_email=about["__author_email__"],  # 作者邮箱
        url=about["__url__"],   # 项目官网
        packages=packages,    # 项目需要的包
        data_files=file_data,   # 打包时需要打包的数据文件,如图片,配置文件等
        include_package_data=True,  # 是否需要导入静态数据文件
        python_requires=">=3.0, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3*",  # Python版本依赖
        install_requires=requires,  # 第三方库依赖
        zip_safe=False,  # 此项需要,否则卸载时报windows error
        classifiers=[    # 程序的所属分类列表
            'Development Status :: 5 - Production/Stable',
            'Intended Audience :: Developers',
            'Natural Language :: English',
            'Programming Language :: Python',
            'Programming Language :: Python :: 3',
            'Programming Language :: Python :: 3.4',
            'Programming Language :: Python :: 3.5',
            'Programming Language :: Python :: 3.6',
            'Programming Language :: Python :: 3.7',
            'Programming Language :: Python :: Implementation :: CPython',
            'Programming Language :: Python :: Implementation :: PyPy'
        ],
    )
    

    当然这里面所有的参数都不是非必须,如果我们一个参数都不传入,则pyhton会生成一个名为UNKNOW-0.0.0.tar.gz的包。

  • 2.使用cmd进入setup.py所在目录,使用python setup.py sdist命令之后,python会在此目录下生成一个dist目录和一个包名.egg-info目录,包名及setup函数中name指定的名称,为命名则为UNKNOWN.egg-info,这个文件夹下是一些包的详细信息文件。

如此包便打包完成了,这中间踩了一写坑,记录一下:

使用python setup.py sdist命令无反应,然后使用python -v发现也不输出python版信息,此时打开此电脑/属性/高级系统设置/高级/环境变量,发现path中都以存在python目录,可是使用python -v就是无反应。

解决方案:在cmd下使用set PATH=Python完成目录;%PATH%,不知道为什么需要使用命令行配置一下系统环境才行。

当然不同的打包工具,打包过程略有不同,这里就详细展开了。

八、Python的内置函数

1.数学函数

函数 描述
abs() 返回数字的绝对值,如abs(-10) 返回 10
cmp() 如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1
max() 返回给定参数的最大值,参数可以为序列
min() 返回给定参数的最小值,参数可以为序列
pow() x^y 运算后的值,及求x的y次幂
round(x [,n]) 返回浮点数x的四舍五入值,如给出n值,则代表舍入到小数点后的位数
sum() 对序列求和
round() 返回浮点数x的四舍五入值

5.反射函数

函数 描述
dir() dir函数返回一个包含了一个模块里所定义的所有模块、变量和函数,dir函数只是列出名称,无其他实际意义,其中以__开头的是模块相关的默认属性,如:__name__指向模块的名字,__file__指向模块文件的名字,dir函数可以传入模块名称,则输出的是模块相关的信息,如果不传入参数则输出当前作用域的相关信息
globals() 在函数内使用则返回一个包含该函数能访问的所有全局名字的字典,在函数外使用效果和在函数内使用一样
locals() 在函数内使用则返回一个包含该函数内的全部局部名字的字典,在函数外使用效果和globals()函数一样
callable() 检查一个对象是否是可调用的。如果返回 True,object 仍然可能调用失败;但如果返回 False,调用对象 object 绝对不会成功。

6.类型转换函数

函数 描述
bool() 将对象转换为bool类型,对于空元组和空列表将转换为false
float() 在python中没有double类型,python的float精度就已经达到了double的精度
int() 转整型
long() 转长整型
str() 将对象转换成字符串,支持任何对象
eval() eval函数可以用来做字符串转列表、元组和字典等,如:a = eval('[1,2]')b = eval('(1,2)'),a是一个列表,b是一个元组,其中字典需要注意的是要使用纯字符串,如:c = eavl(r"{'a':1,'b':2}"),c就是一个字典了,除此之外,eval函数还可以用来运行字符串命令,如:eval('bool(1)'),输出为True
list() 将可迭代序列(包括元组,字符串,字典等)转换成列表,如:字符串转列表a = list('abc')则a列表内容为['a','b','c']、字典转列表则会返回一个key值列表
tuple() 将可迭代序列(包括元组,字符串,字典等)转换成元组,如:字符串转元组a = tuple('abc')则a列表内容为('a','b','c')、字典转元组则会返回一个key值元组
dict() dict函数支持三种转换形式,其一使用关键字的形式,关键字名称为键,关键字的值为值,如:a=dict(a=1,b=1)则a就是字典{'a':1,'b':2},其二使用zip函数的形式,zip函数将两个可迭代序列按位置打包成二元元组,dict函数则将二元元组的第一个元素作为键,第二个元素作为值创建字典,如:a=dict(zip(['a','b'],[1,2])),其中zip函数返回值为[('a',1),('b',2)],dict函数返回值为{'a':1,'b':2},其三使用可迭代对象的形式,如:a=dict([('a',1),('b':2)])其中可迭代对象可以是任何子成员为二元序列的对象
chr() 将数字转换成对应的字符

6.其他内置函数

详情见菜鸟教程

九、文件IO

1.标准输出

print()在终端打印,这里需要注意的是python3已经不支持print 'aa'这种打印方式了。

2.标准输入

input()从终端输入,有时我们会看到row_input函数或input函数接收python表达式的标准输入,这些都是ptrhon2的标准输入函数和输入特性,在python3中python只保留了一个input函数作为标准输入,且input函数不在支持python表达式的输入,而是把所有的输入当作是字符串。

3.文件读写

python的文件读写通过内置类型file类型来进行操作,而file类型对象的创建需要通过内置函数open来创建。

open函数

open(file_name ,access_mode, buffering)
  • file_name:文件路径

  • access_mode:打开模式,默认为只读,具体模式如下:

    字符 含义
    'r' 读取(默认)
    'w' 写入,并先截断文件
    'x' 排它性创建,如果文件已存在则失败
    'a' 写入,如果文件存在则在末尾追加
    'b' 二进制模式
    't' 文本模式(默认)
    '+' 更新磁盘文件(读取并写入)

    python3以后删除了很多打开模式,只保留了上面几种,所以如果在python3环境中使用+打开模式就会报错。

  • buffering:是否寄存行,可选参数,具体取值如下:

    取值 描述
    0 取0,不寄存行
    1 取1,寄存行
    >1 取大于1的值,寄存行,且设置寄存区的缓冲大小为当前值
    <0 取小于0的值,寄存行,且设置寄存区的缓冲大小为系统默认值
  • 返回值:open函数打开文件,读取文件内容到内存并一个可操作文件的file类型对象。

file类型对象内置函数

序号 方法及描述
file.close() 关闭文件。关闭后文件不能再进行读写操作。
file.flush() 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
file.fileno() 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
file.isatty() 如果文件连接到一个终端设备返回 True,否则返回 False。
file.read([size]) 从文件读取指定的字节数,如果未给定或为负则读取所有。
file.readline([size]) 读取整行,包括 “\n” 字符。
file.readlines([sizeint]) 读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。
file.seek(offset[, whence]) 移动文件读取指针到指定位置
file.tell() 返回文件当前位置。
file.truncate([size]) 从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小。
file.write(str) 将字符串写入文件,返回的是写入的字符长度。
file.writelines(sequence) 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。

file类型对象内置属性

属性 描述
file.closed 返回true如果文件已被关闭,否则返回false。
file.mode 返回被打开文件的访问模式。
file.name 返回文件的名称。
file.softspace 如果用print输出后,必须跟一个空格符,则返回false。否则返回true。

4.文件及目录操作

这里的文件操作不是对文件的内容进行增删改操作而是在文件级别进行重命名删除设置权限等操作,对文件做这些操作需要用到os模块,os模块提供大量的函数对文件进行操作,文件数量过多这里就不贴出来了,具体见菜鸟教程:

os文件操作函数

十、异常

1.异常处理语句

Python的异常处理语句是try/except,需要监测异常的代码放在try:块下,在异常发生后需要执行的代码放在except:块下,except后可以接异常类型也可以不接,如:

try:
    a = 1/0
except ZeroDivisionError:
    print('0不可以做除数')
else:
    print('没有异常')
finally:
    print('有没有异常都会执行')

可以看到,和条件语句一样try/except语句也可以接else分支,else分支在没有异常发生时执行。、

2.抛出异常

python使用raise语句来抛出异常,需要注意的是,raise必须抛出一个异常类,如:

try:
    a = 1/0
except ZeroDivisionError:
    raise ZeroDivisionError('0不可以做除数')

3.标准异常

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

4.自定义异常

python的自定义异常只需要将自定义异常类继承自python标准异常类即可。

十一、面向对象

python在设计之初就已经是一门面向对象的语言了,在python中一切皆对象,包括所有的基础类型也是对象,这使得python在创建类和对象时十分容易,但是这也导致python十分消耗内存空间,因为哪怕只创建一个整型也会消耗对于C语言的内存空间。

1.定义类

和大多数语言一样,python也使用class关键字来标识类,使用同等量的缩进来标识类的范围,如:

class Person:
    age = 0
    name = ''
    __id = 1
    _sex = 'female'

    def __init__(self, age, name):
        self.age = age
        self.name = name

    def GetName(this):
        print('my name is ' + this.name)
    
    def __SetId():
        id = 001


p = Person(18, 'lusa')
p.GetName()

2.成员变量

私有成员变量

由于python无法使用public,private等关键字,所以python使用双下划线开头来标识私有成员变量。如上面代码中的__id

保护成员变量

python使用单下划线开头来标识保护成员变量,如上面代码中的_sex

公有成员变量

不带有任何前缀的变量的就是公有成员变量。

3.成员函数

私有函数、保护函数和公有函数

和变量一样,python使用双下划线来前缀来标识私有函数,用单下划线前缀来标识保护函数,无前缀函数表示公有函数。

self参数

与其他语言不同的是,python的函数都必须带有一个self参数,self参数的在效果上与C++的this指针很像,但是python的self参数不是类自带的,在定义函数时需要手动显示表示,且必须放在函数的第一个参数位置,self参数的名字不一定非得叫self也可以叫其他的名字,如上面代码中的GetName函数的this,但是按照python的规范建议将都是用self命名,self参数指向当前类实例,类的实例变量都必须使用self参数才能访问,直接使用是无法访问的,如:

class Person:
    age = 0

    def __init__(self, param):
        age = param

不通过self参数访问类的成员变量将直接报语法错误。

4.类变量、实例变量和局部变量

类变量

定义在类的内部且定义在方法体外的变量,如上面代码中age,类变量可以被类直接访问,也可以被实例直接访问,同时可以被实例方法和类方法方法访问,但是不可以被静态方法访问。如:

class Person:
    names = 'aa'

    def __init__(self, age, name):
        self.age = age
        self.name = name
        addr = 'beijing'
        names = "bb"

    def GetName(self):
        self.sex = 'female'
        print('my name is ' + self.names)

    @staticmethod
    def PP():
        print(names)
    
    @classmethod
    def OO(cls):       
        print(cls.names)


p = Person(18, "lusa")
print(p.names)
p.names = "cc"
p.GetName()
print(Person.names)
Person.names = "dd"
Person.OO()
print(p.names)
Person.PP()

输出结果:

aa
my name is cc
aa
dd
cc
Traceback (most recent call last):
  File "d:\Codes\Python\MyFirstPython.py", line 31, in <module>
    Person.PP()
  File "d:\Codes\Python\MyFirstPython.py", line 16, in PP
    print(names)
NameError: name 'names' is not definedd

可以看到,类变量names初始值为aa,我们的本意是在构造函数中再赋值bb但是再实际输出中names的值依旧是aa,当我们使用实例给类变量names赋值为cc时,输出GetName函数输出就变为了cc,然而直接通过类名访问的结果依旧是aa,当我们通过类名赋值names为dd时,类方法输出的结果就变为了dd,然而用实例访问的结果依旧时cc,最终运行到类的静态方法PP处则报错了,由上结果可得出结论:

  • 类在创建实例时会拷贝一份类变量到实例中,实例中类变量和类中的类变量互相独立
  • 构造函数不可以初始化类变量,当我们在构造函数初始化一个类变量的同名变量时,实际上python初始化的是一个和类变量同名的局部变量
  • 同一个类变量既可以被类实例访问也可以被类名直接访问,但二者内存地址时两个内存地址
  • 静态方法不可以访问类变量

实例变量

实例变量是定义在构造函数内部且通过self引出的变量,这两点十分重要,如果一个变量不是在构造函数里创建即使通过self引出也依旧不是实例变量,或一个变量在构造函数中创建但不是由self引出,那它也不是实例变量,而是函数的局部变量,如:上面代码中self.sex,和构造函数里的addr和names,我们是不可以使用实例访问的。

局部变量

在构造函数中创建的不由self引出的变量或在其他方法中创建的变量,如上面代码中GetName啊哈桑农户里的self.sex和构造函数里的addr和names

5.类方法、实例方法和静态方法

@classmethod修饰的方法就是类方法,被@staticmethod修饰的方法就是静态方法,除此之外其余的方法都是实例方法。类方法和静态方法也有保护级。

类方法

类方法属于类,可以直接通过类型访问,也可以同通过实例访问,访问效果是一样的。在创建类方法时必须至少需要一个参数,一般命名为cls,用于python传递默认参数–类。如:

@classmethod
def OO(cls):
    print(cls.names)

cls不可省略,在类方法中只能通过cls来访问类变量,且只能访问类变量。

静态方法

静态方法同类方法很相似,也可以被类名和实例直接访问。不同的是,静态方法不需要cls参数,python不会传递默认参数到静态方法,静态方法不可以直接访问类的任何成员。

嵌套函数

python支持方法中嵌套创建方法,如:

def funa():
    a = 1
    print(a)

    def funb():
        nonlocal a
        a += 1
        print(a)
   
    funb()


funa()

十二、作用域

python的作用域大部分与C系列语言的作用域差不多,只是有三点比较特殊:

  • python中只有类、函数、模块才会引入新的作用域,控制语句不会引入新的作用域,也就是说,在控制语句中创建的变量可以在控制语句外部被访问

    如:

    for i in range(3):
        print(i)
    
    print(i)
    

    输出结果:

    0
    1
    2
    2
    
  • 如果要在函数内部访问全局变量需要在在函数内部使用global申明,否则python将创建一个同名的局部变量而不是引用全局变量

    如:

    a = 1
    
    
    def fun():
        a += 1
    

    python会直接报语法错误,因为我们使用了一个未定义的局部变量,但是当我们使用global申明之后,我们访问的就是全局变量了,如:

    a = 1
    
    
    def fun():
        global a
        a += 1
    
  • 如果要在嵌套函数中访问外层函数的变量需要使用nonlocal申明,否则python也会创建一个同名的局部函数,如:

    a = 1
    
    
    def fun():
        global a
        a += 1
        b = 2
    
        def funb():
            global a
            nonlocal b
            b += 1
            print(a)
            print(b)
    
        funb()
    
    
    fun()
    

    输出结果:

    2
    3
    

猜你喜欢

转载自blog.csdn.net/qq_39108291/article/details/114358887