1.Python应用场景
0.Web应用开发
Python经常被用于Web开发。
比如,通过mod_wsgi模块,Apache可以运行用Python编写的Web程序。
Python定义了WSGI标准应用接口来协调Http服务器与基于Python的Web程序之间的通信。
一些Web框架,如Django,TurboGears,web2py,Zope等,可以让程序员轻松地开发和管理复杂的Web程序。
1.操作系统管理、服务器运维的自动化脚本
在很多操作系统里,Python是标准的系统组件。 大多数Linux发行版以及NetBSD、OpenBSD和Mac OS X都集成了Python,可以在终端下直接运行Python。
有一些Linux发行版的安装器使用Python语言编写,比如Ubuntu的Ubiquity安装器,Red Hat Linux和Fedora的Anaconda安装器。
Gentoo Linux使用Python来编写它的Portage包管理系统。
Python标准库包含了多个调用操作系统功能的库。
通过pywin32这个第三方软件 包,Python能够访问Windows的COM服务及其它Windows API。
使用IronPython,Python程序能够直接调用.Net Framework。
一般说来,Python编写的系统管理脚本在可读性、性能、代码重用度、扩展性几方面都优于普通的shell脚本。
2.科学计算
NumPy,SciPy,Matplotlib可以让Python程序员编写科学计算程序。
3.桌面软件
PyQt、PySide、wxPython、PyGTK是Python快速开发桌面应用程序的利器。
4.服务器软件(网络软件)
Python对于各种网络协议的支持很完善,因此经常被用于编写服务器软件、网络爬虫。
第三方库Twisted支持异步网络编程和多数标准的网络协议(包含客户端和服务器),并且提供了多种工具,被广泛用于编写高性能的服务器软件。
5.游戏
很多游戏使用C++编写图形显示等高性能模块,而使用Python或者Lua编写游戏的逻辑、服务器。
相较于Python,Lua的功能更简单、体积更小;而Python则支持更多的特性和数据类型。
6.构思实现,产品早期原型和迭代
YouTube、Google、Yahoo!、NASA都在内部大量地使用Python。
1.1交互式python开发
除了python官方的交互式python开发外, 还有其他交互式开发命令:
python3的话, 在linux下输入ipython3命令, 此时进入交互式开发场景:
---支持自动补全
---支持缩进
---支持bash shell命令
---内置了很多有用的功能和函数
若要退出ipython, 则直接输入exit或者ctrl+D即可退出
1.2程序运行原理
程序运行之前, 程序是保存在内存中的
当一个程序要运行时, 操作系统会首先让CPU把程序从硬盘复制到内存中, 然后CPU执行内存中的程序代码
即程序要执行, 首先要被加载到内存
1.3python文件代码结构示意图
shebang
import 模块
全局变量
函数定义
执行代码
2.基础语法
2.1注释
# 单行注释
print("一个井号表示单行注释")
'''
多行注释
'''
print('三个单引号包裹的多行注释')
"""
这也是多行注释
"""
print("三个双引号包裹的多行注释")
2.2python程序中,中文支持
# -*- coding:utf-8 -*-
![](https://img.haomeiwen.com/i7810227/c4821c7851760611.png)
2.3命名
2.3.1文件名:
- 建议只使用小写字母,数字和下划线
- 文件名不能以数字开头
- 在等号的左右各保留一个空格(保证代码格式)
2.3.2标识符
标示符是开发人员在程序中自定义的一些符号和名称,如变量名 、函数名等:
标示符由字母、下划线和数字组成,且数字不能开头
python中的标识符是区分大小写的
见名知意
小驼峰式命名法(lower camel case): 第一个单词以小写字母开始;第二个单词的首字母大写,例如:myName、aDog
大驼峰式命名法(upper camel case): 每一个单字的首字母都采用大写字母,例如:FirstName、LastName
下划线命名法: 用“_”来连接所有的单词,比如send_buf
2.3.3关键字
python一些具有特殊功能的标示符,这就是所谓的关键字
关键字,是python已经使用的了,所以不允许开发者自己定义和关键字相同的名字的标示符
查看关键字
![](https://img.haomeiwen.com/i7810227/62602470e4cab6ca.png)
[
'False', 'None', 'True', 'and', 'as', 'assert', 'break',
'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise',
'return', 'try', 'while', 'with', 'yield'
]
with关键字
对于系统资源如文件、数据库连接、socket 而言,
应用程序打开这些资源并执行完业务逻辑之后,
必须做的一件事就是要关闭(断开)该资源。
Python 提供了 with 语法用于简化资源操作的后续清除操作,
是 try/finally 的替代方法,实现原理建立在上下文管理器之上。
此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。
一种优雅的方式就是:
def m3():
with open("output.txt", "r") as f:
f.write("Python之禅")
上下文管理器
任何实现了 __enter__() 和 __exit__() 方法的对象都可称之为上下文管理器,
上下文管理器对象可以使用 with 关键字。
显然,文件(file)对象也实现了上下文管理器。
定义上下文管理器方法一:
class File():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("entering")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, *args):
print("will exit")
self.f.close()
定义上下文管理器方法二:
from contextlib import contextmanager
@contextmanager
def my_open(path, mode):
f = open(path, mode)
yield f
f.close()
2.3.4公有/私有变量
xx: 公有变量, 可继承
_x: 单前置下划线,私有化属性或方法,from somemodule import *禁止导入,类对象和子类可以访问, 这种类型的变量、函数、类在使用from xxx import *时都不会被导入
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到), 父类中属性名为__名字的,子类不继承,子类不能访问
__xx__:双前后下划线,用户名字空间的魔法对象或属性。公有属性或方法, 可继承. 例如:__init__ , __ 不要自己发明这样的名字
xx_:单后置下划线,用于避免与Python关键词的冲突
2.4格式化输出
2.4.1常用的格式符号
格式符号 | 转换 |
---|---|
%c | 字符 |
%s | 通过str() 字符串转换来格式化 |
%i | 有符号十进制整数 |
%d | 有符号十进制整数 |
%u | 无符号十进制整数 |
%o | 八进制整数 |
%x | 十六进制整数(小写字母) |
%X | 十六进制整数(大写字母) |
%e | 索引符号(小写'e') |
%E | 索引符号(大写“E”) |
%f | 浮点实数 |
%g | %f和%e 的简写 |
%G | %f和%E的简写 |
如:
age = 18
name = "xiaohua"
print("我的姓名是%s,年龄是%d"%(name,age))
2.4.2换行输出
在输出的时候,如果有\n那么,此时\n后的内容会在另外一行显示
print("1234567890-------") # 会在一行显示
print("1234567890\n-------") # 一行显示1234567890,另外一行显示-------
2.5输入(input()函数)
a = input("请输入:")
print(a)
2.6变量类型
可以使用type(变量的名字),来查看变量的类型
![](https://img.haomeiwen.com/i7810227/d01360f45777dfbb.png)
2.6.1常用的数据类型转换
函数 | 说明 |
---|---|
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 转换为一个列表 |
chr(x ) | 将一个整数转换为一个字符 |
unichr(x ) | 将一个整数转换为Unicode字符 |
ord(x ) | 将一个字符转换为它的整数值 |
hex(x ) | 将一个整数转换为一个十六进制字符串 |
oct(x ) | 将一个整数转换为一个八进制字符串 |
a = '100' # 此时a的类型是一个字符串,里面存放了100这3个字符
b = int(a) # 此时b的类型是整型,里面存放的是数字100
print("a=%d"%b)
2.6.2下标与切片
符串、列表、元组都支持下标索引。
切片是指对操作的对象截取其中一部分的操作。字符串、列表、元组都支持切片操作。
下标
name = 'tom'
print(name[1])
切片
切片的语法:[起始:结束:步长]
注意:
选取的区间属于左闭右开型,
即从"起始"位开始,到"结束"位的前一位结束(不包含结束位本身)。
name = 'tommyly'
print(name[0:2]) # 取下标0-1 的字符
print(name[2:4]) # 取下标为2、3 的字符
print(name[2:]) # 取下标为2开始到最后的字符
print(name[1:-1]) # 取下标为1开始到倒数第2个之间的字符
print(name[:3]) # 取下标为0-2的字符
print(name[::2]) # 取下标为0,2,4,6,...的字符, 每隔2个取一个, 步长是2
print(name[::-1]) # 倒叙排列
print(name[1:5:2]) #
print(name[5:1:2]) #
print(name[5:1:-2]) #
2.6.3字符串常用操作
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
bytes是Python 3中特有的,Python 2 里不区分bytes和str。
在Python 2中由于不区分str和bytes所以可以直接通过encode()和decode()方法进行编码解码。
python3中:
str 使用encode方法转化为 bytes
bytes通过decode转化为str
"""
var01 = "hello"
print(type(var01), var01.encode("utf-8").decode()) # <class 'str'> hello
print(type(var01.encode("utf-8")), var01.encode()) # <class 'bytes'> b'hello'
test = 'hello world worlD python!'
# find()
print(test.find('world', 0, len(test))) # 检测world 是否包含在test中,如果是返回首次出现的索引值,否则返回-1
# rfind()
print(test.rfind('worl')) # 类似于 find()函数,不过是从右边开始查找.
# index()
print(test.index('p', 0, len(test))) # 跟find()方法一样,只不过如果mm不在test中会报一个异常.
# rindex()
print(test.rindex('w')) # 类似于 index(),不过是从右边开始.
# count()
print(test.count('o')) # 返回 o在test里面出现的次数
# replace()
print(test.replace('o', 'z', 2)) # 把 test 中的 o 替换成 z,如果 count 指定,则替换不超过 count 次.
# split()
print(test.split(" ")) # 以 str 为分隔符切片 mystr,如果 maxsplit有指定值,则仅分隔 maxsplit 个子字符串
# capitalize()
print(test.capitalize()) # 把字符串的第一个字符大写
# title()
print(test.title()) # 把字符串的每个单词首字母大写
# startwith()
print(test.startswith('he')) # 检查字符串是否是以 obj 开头, 是则返回 True,否则返回 False
# endswith()
print(test.endswith('python!')) # 检查字符串是否以obj结束,如果是返回True,否则返回 False.
# lower()
print(test.lower()) # 转换 mystr 中所有大写字符为小写
# upper
print(test.upper()) # 转换 mystr 中的小写字母为大写
# ljust()
print(test.ljust(30)) # 返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
# rjust()
print(test.rjust(30)) # 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
# center()
print(test.center(30)) # 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
# lstrip()
print(' lll '.lstrip()) # 删除 mystr 左边的空白字符
# rstrip()
print(' lll '.rstrip()) # 删除 mystr 字符串末尾的空白字符
# strip()
print(' lll '.strip()) # 删除mystr字符串两端的空白字符
# partition()
print(test.partition('worlD')) # 把mystr以str分割成三部分,str前,str和str后
# rpartition()
print(test.rpartition('worlD')) # 类似于 partition()函数,不过是从右边开始.
# splitlines()
print('hello\nworld'.splitlines()) # 按照行分隔,返回一个包含各行作为元素的列表
# isalpha()
print('hello123'.isalpha()) # 如果 mystr 所有字符都是字母 则返回 True,否则返回 False
# isdigit()
print('hello123'.isdigit()) # 如果 mystr 只包含数字则返回 True 否则返回 False.
# isalnum()
print('hello123'.isalnum()) # 如果 mystr 所有字符都是字母或数字则返回 True,否则返回 False
# isspace()
print('h '.isspace()) # 如果 mystr 中只包含空格,则返回 True,否则返回 False.
# join()
print('_'.join('hello world tommy'.split(' '))) # mystr 中每个字符后面插入str,构造出一个新的字符串
2.6.4列表常见操作
应用场景
通常用来保存一组相同类型数据
列表格式如下:
names = ['tom', 'jerry', 'john', 'mary']
比C语言的数组强大的地方在于列表中的元素可以是不同类型的:
testList = [1, 'a']
>>>>>>>>>>>>>>>>>循环遍历<<<<<<<<<<<<<<<<<<<
names = ['tom', 'jerry', 'john', 'mary']
# 遍历方法1:
for name in names:
print(name, end = ' ')
print('')
# 遍历方法2:
names_size = len(names)
i = 0
while i < names_size:
print(names[i], end=' ')
i += 1
print('')
# 嵌套for循环
schoolNames = [['北京大学','清华大学'],['南开大学','天津大学','天津师范大学'],['南京大学','东南大学']]
for schools in schoolNames:
for school in schools:
print(school, end=',')
print('')
>>>>>>>>>>>>>>>>>增加<<<<<<<<<<<<<<<<<<<<<
# append() 增加一个列表元素
names.append('tommy')
for name in names:
print(name, end=' ')
print('-------')
nameList = ['bianzuizi', 'jiaozi']
# extend() 增加一个列表元素, 等价于<==>list1 += list2
# 若是names.append(nameList) , 则print出来的是: tom jerry john mary tommy ['bianzuizi', 'jiaozi']
names.extend(nameList)
for name in names:
print(name, end=' ') # tom jerry john mary tommy bianzuizi jiaozi
print('-------')
# insert(index, object) 在指定位置index前插入元素object
names.insert(2, 'trump')
for name in names:
print(name, end=' ') # tom jerry trump john mary tommy bianzuizi jiaozi
print('-------')
############################### 删除 #################################
# pop() 删除最后一个元素
names.pop()
for name in names:
print(name, end=' ') # tom jerry trump john mary tommy bianzuizi
print('--------')
# del list[i] 根据下标进行删除
del names[1]
for name in names:
print(name, end=' ') # tom trump john mary tommy bianzuizi
print('-----------')
# remove(object) 根据元素的值进行删除
names.remove('trump')
for name in names:
print(name, end=' ') # tom john mary tommy bianzuizi
print('-----------')
# names.clear() 清空列表
############################### 修改 #################################
# 根据下标来修改元素值
names[1] = 'john_update'
for name in names:
print(name, end=' ') # tom john_update mary tommy bianzuizi
print('-----------')
############################### 查询 #################################
# in, 如果某元素在list中, 返回True
b1 = 'tom' in names
print(b1)
# not in, 如果某元素不在list中, 返回True
b2 = 'tom' not in names
print(b2)
# index(), 返回某个元素在list中首次出现的下标
n1 = names.index('tom')
print(n1)
# count(), 返回某个元素在list中出现的次数
n2 = names.count('tom')
print(n2)
############################### 查询 #################################
# 正序排列
names.sort()
print(names) # ['bianzuizi', 'john_update', 'mary', 'tom', 'tommy']
# 倒序排列
names.reverse()
print(names) # ['tommy', 'tom', 'mary', 'john_update', 'bianzuizi']
2.6.5元组
应用场景
可用来保存不同类型数据
可用来保存不可修改的数据
可用用作函数的参数和返回值
可用格式化字符串 tupleA = (i, j, i * j) print('%d * %d = %-2d '%tupleA, end='')
# 元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。
tupleA = ('a', 'b', 'c')
# 根据下标访问元组中的某个元素
print(tupleA[1])
# index(), 返回某个元素在元组中首次出现的下标
print(tupleA.index('c'))
# count(), 返回某个元素在元组中出现的次数
print(tupleA.count('a'))
元组与列表的转换
names = ['tom', 'jerry']
tup = tuple(names) # 列表转为元组
print(tup)
list1 = list(tup) # 元组转为列表
print(list1)
2.6.6字典(类似于json类型)
应用场景
通常用于存储一个物体相关的信息
stu= {'name':'tom', 'id':10, 'gender':'male', 'address':'tokyo'}
字典和列表一样,也能够存储多个数据
列表中找某个元素时,是根据下标进行的
字典中找某个元素时,是根据'名字'(就是冒号:前面的那个值,例如上面代码中的'name'、'id')
字典的每个元素由2部分组成,键:值。例如 'name':'tom'
字典是无序对象集合, 列表是有序对象集合
# 字典
stu= {'name':'tom', 'id':10, 'gender':'male', 'address':'tokyo'}
############################### 查询 #################################
# 根据键访问值: 若访问不存在的键,则会报错
print(stu['name'], '------') # tom
# 不确定字典中是否存在某个键而又想获取其值时,可以使用get方法,还可以设置默认值
print(stu.get('grade')) # grade不存在, 返回None
print(stu.get('grade', 'senior one')) # grade不存在时, 设置默认值
# len() 字典中键值对的个数
print(len(stu))
# keys() 返回一个包含字典所有KEY的列表
print(stu.keys())
# values() 返回一个包含字典所有value的列表
print(stu.values())
# items() 返回一个包含所有(键,值)元祖的列表
print(stu.items())
# 查看某个Key是否在字典汇总
if 'ddd' in stu:
print(True)
else:
print(False)
############################### 修改 #################################
stu['id'] = 101
print(stu)
############################### 增加 #################################
stu['grade'] = 'middle one'
print(stu)
############################### 删除 #################################
# del
del stu['grade'] # 删除某个元素
print(stu)
# clear() 清空整个字典
stu.clear()
print(stu)
# 删除整个字典, 删除后无法访问, 变量消失
del stu
# 删除字典中的某个键值对
stu.pop()
# 合并两个字典
dict01 = {'name': 'tom'}
dict02 = {'age': 30}
dict01.update(dict02) # 合并两个字典
print(dict01)
2.6.7各类型数据的遍历
############################### 遍历 #################################
# 通过for ... in ...:的语法结构,我们可以遍历字符串、列表、元组、字典等数据结构。
# 遍历字符串
for char in 'hello world':
print(char, end=',')
print('------')
# 遍历列表
hello_world = ['hello', 'world']
for ele in hello_world:
print(ele, end=',')
print('-------')
# 带下标的遍历
for i, ele in enumerate(hello_world):
print(i, '>>>>>>>>', ele, end=',')
print('----------')
# 遍历元组
tuple_hello_wolrd = ('tuple', 'hello', 'world')
for tup in tuple_hello_wolrd:
print(tup, end=',')
print('--------')
dict_hello_world = {'id': 1, 'name': 'jerry', 'age': 30}
# 遍历字典的key
for k in dict_hello_world.keys():
print(k, end=',')
print('---------')
# 遍历字典的value
for v in dict_hello_world.values():
print(v, end=',')
print('---------')
# 遍历字典的item
for item in dict_hello_world.items():
print(item, end=',')
print('--------')
# 遍历字典的Key-value
for key, value in dict_hello_world.items():
print(key, '-->', value, end=',')
print('----------')
2.6.8公共方法
运算符 | Python 表达式 | 结果 | 描述 | 支持的数据类型 |
---|---|---|---|---|
+ | [1, 2] + [3, 4] | [1, 2, 3, 4] | 合并 | 字符串、列表、元组 |
* | 'Hi!' * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | 复制 | 字符串、列表、元组 |
in | 3 in (1, 2, 3) | True | 元素是否存在 | 字符串、列表、元组、字典 |
not in | 4 not in (1, 2, 3) | True | 元素是否不存在 | 字符串、列表、元组、字典 |
2.6.9python内置函数
序号 | 方法 | 描述 | 备注 |
---|---|---|---|
1 | cmp(item1, item2) | 比较两个值 | cmp在比较字典数据时,先比较键,再比较值。python3取消了该函数 |
2 | len(item) | 计算容器中元素个数 | len在操作字典数据时,返回的是键值对个数。 |
3 | max(item) | 返回容器中元素最大值 | - |
4 | min(item) | 返回容器中元素最小值 | - |
5 | del(item) 或者 del加空格 | 删除变量 | - |
2.6.10引用传递
在python中,值是靠引用来传递来的。
我们可以用id()来判断两个变量是否为同一个值的引用。
我们可以将id值理解为那块内存的地址标示。
a = 1
b = a
print(id(a)) # 注意两个变量的id值相同
print(id(b)) # 注意两个变量的id值相同
a = 2
print(id(a)) # 注意a的id值已经变了
print(id(b)) # b的id值依旧
2.6.11可变类型与不可变类型
可变类型,值可以改变:
(使用方法如.clear等不会改变内存地址,
使用赋值语句, 会改变内存地址)
列表 list
字典 dict
(字典的key只能是不可变类型数据, 不能是可变类型数据)
不可变类型,值不可以改变:
数值类型 int, long, bool, float
字符串 str
元组 tuple
2.7运算符
2.7.1算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | 两个对象相加 a + b 输出结果 30 |
- | 减 | 得到负数或是一个数减去另一个数 a - b 输出结果 -10 |
* | 乘 | 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200 |
/ | 除 | x除以y b / a 输出结果 2 |
// | 取整除 | 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 |
% | 取余 | 返回除法的余数 b % a 输出结果 0 |
** | 幂 | 返回x的y次幂 a**b 为2的3次方, 输出结果8 |
2.7.2赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 赋值运算符 | 把=号右边的结果给左边的变量 num=1+2*3 结果num的值为7 |
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c **= a 等效于 c = c ** a |
//= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
2.7.3比较(即关系)运算符
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果是则条件变为真。 | 如a=3,b=3则(a == b) 为 true. |
!= | 检查两个操作数的值是否相等,如果值不相等,则条件变为真。 | 如a=1,b=3则(a != b) 为 true. |
<> | 检查两个操作数的值是否相等,如果值不相等,则条件变为真。 | 如a=1,b=3则(a <> b) 为 true。这个类似于 != 运算符 |
> | 检查左操作数的值是否大于右操作数的值,如果是,则条件成立。 | 如a=7,b=3则(a > b) 为 true. |
< | 检查左操作数的值是否小于右操作数的值,如果是,则条件成立。 | 如a=7,b=3则(a < b) 为 false. |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是,则条件成立。 | 如a=3,b=3则(a >= b) 为 true. |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是,则条件成立。 | 如a=3,b=3则(a <= b) 为 true. |
2.7.4逻辑运算符
运算符 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | x and y | 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 | (a and b) 返回 20。 |
or | x or y | 布尔"或" - 如果 x 是 True,它返回 True,否则它返回 y 的计算值。 | (a or b) 返回 10。 |
not | not x | 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 | not(a and b) 返回 False |
2.7.5 身份运算符
python中, 与None进行比较时, 建议用is进行判断
is用于判断两个变量引用是不是同一个对象
==用于判断引用变量的值是否相等
运算符 | 描述 | 实例 |
---|---|---|
is | is是判断两个标识符是否引用同一个对象 | x is y, 类似id(x) == id(y) |
is not | is not是判断两个标识符是否引用不同对象 | x is not y, 类似id(x) != id(y) |
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True
print(a is b) # False
2.8判断语句和循环语句
2.8.1if-elif-else
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import random
player = int(input('请输入:剪刀(0) 石头(1) 布(2):'))
computer = random.randint(0, 2)
print(computer)
if(((player == 0) and (computer == 2)) or ((player == 1) and (computer == 0)) or ((player == 2) and (computer == 1))):
print('玩家赢')
elif player == computer:
print('平局')
else:
print('电脑赢')
2.8.2while循环
# %-2d负号表示左对齐, 2表示当接收的整型数据长度少于2时就在右边补空格对齐
i = 1
while i < 10:
j = 1
while j <= i:
print('%d * %d = %-2d '%(i, j, i * j), end='')
j += 1
print('\n')
i += 1
2.8.3for循环(break, continue)
for x in name:
if x == 't':
continue
if x == 'm':
break
print(x)
- break的作用:用来结束整个循环
- continue的作用:用来结束本次循环,紧接着执行下一次的循环
- break/continue只能用在循环中,除此以外不能单独使用
- break/continue在嵌套循环中,只对最近的一层循环起作用
2.9函数
2.9.1局部变量和全局变量
局部变量,就是在函数内部定义的变量
全局变量,就是在函数外边定义的变量
总结1
全局变量能够在所有的函数中进行访问
如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的
# 定义全局变量
var_a = 120
def fn05():
var_a = 130 # 局部变量
print(var_a)
fn05()
def fn06():
global var_a
print('修改前', var_a)
var_a = 100
print('修改后', var_a)
fn06()
"""
在一个函数中, 对全局变量进行修改的时候, 关于是否需要加上global关键字的说明:
要看是否对全局变量的执行指向(即内存地址)进行了修改
如果修改了内存地址, 即让全局变量指向了另一个地方, 那么需要加上global关键字
如果仅仅是修改了空间中数据, 内存地址没变, 则不用加global关键字
例如:
数字, 字符串, 元组的加减乘除或者赋值, 列表的+=, 列表的赋值, 均需要加上global
列表的增删改等, 不需要加上global
"""
num = 100
nums = [1, 2, 3]
def fn01():
global num
num += 1 # 由于数字是不可变类型, 此时操作需要加上global
def fn02():
nums.append(4) # 由于列表是可变类型, 此处未对列表进行+, 赋值等操作, 未改变内存地址, 故不加global
nums.append(5)
fn02()
fn01()
print(num, nums)
总结2
在函数中不使用global声明全局变量时不能修改全局变量的本质是不能修改全局变量的指向,即不能将全局变量指向新的数据。
对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用global时无法修改全局变量。
对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用global时也可修改全局变量。
2.9.2函数定义
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 无参数,无返回值的函数
def fn01():
print('hello')
# 无参数,有返回值的函数
def fn02():
return 'world'
# 有参数,无返回值的函数
def fn03(name):
print(name)
# 有参数(参数有默认值,带有默认值的参数一定要位于参数列表的最后面), 有返回值(此处返回值有多个)
# 函数定义:此处会解析为文档, 与java不同的是, 可以与多个返回值
# 缺省参数:
# 带有默认值的参数一定要位于参数列表的最后面。
# 调用多个缺省参数时, 需要指定参数名
def fn04(a=1, b=1):
print(a - b, a, b)
return a + b, a - b # 多个返回值,本质是利用了元组
# 调用函数
# 当且仅当此处传的实参的名称指定与函数定义的形参名称a,b完全一样时, 才会调换位置传参
add, minus = fn04(b=2, a=30)
fn04(2, 30) # 此时按照实参位置传参
print(add, minus)
# 函数的文档说明
help(fn04)
函数注释
在函数定义名称的下方, 写三个双引号包裹的注释即可, 如:
def hello():
"""这是一个打招呼的函数"""
print('hello')
2.9.3可变参函数
# 加了星号(*)的变量tupleA会存放所有未命名的变量参数,tupleA为元组;
# 加**的变量dictA会存放命名参数,即形如key=value的参数, dictA为字典。
def fn07(a, b, *tupleA, **dictA):
print('a=', a)
print('b=', b)
print('tupleA=', tupleA)
for k, v in dictA.items():
print(k, '-->', v)
fn07(1, 2, 3, 4, 5, 6, p=7, q=8, r=9)
2.9.4递归函数
def fn08(num):
if type(num) != int or num < 1:
print('输入有误')
elif num == 1:
return 1
elif num == 2:
return 1
else:
return fn08(num - 1) + fn08(num - 2)
print(fn08(6))
2.9.5匿名函数
用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。
lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
# 匿名函数
sum1 = lambda arg1, arg2, arg3: arg1 + arg2 + arg3
print(sum1(10, 30, 50))
# 场景一: 函数作为参数传递
def fn10(a, b, sum2):
print('和为:', sum2(a, b))
fn10(1, 2, lambda x, y: x+y)
# 场景二: 作为内置函数的参数
stus = [
{"name": "zhangsan", "age": 18},
{"name": "lisi", "age": 19},
{"name": "wangwu", "age": 17}
]
stus.sort(key=lambda stu: stu["name"])
print(stus)
stus.sort(key=lambda stu: stu['age'])
print(stus)
2.9.6在函数内部, 针对函数赋值不会影响外部实参
def fn01(num, num_list):
# 赋值语句
num = 20
num_list = [4, 5, 6]
print(num, num_list)
gl_num = 1
gl_num_list = [1, 2, 3]
fn01(gl_num, gl_num_list) # 20 [4, 5, 6]
print(gl_num, gl_num_list) # 1 [1, 2, 3]
2.9.7在函数内部, 使用方法修改可变参数值会影响外部实参
def fn02(num_list):
num_list.extend([11, 22, 33])
print(num_list)
gl_num_list = [1, 2, 3]
fn02(gl_num_list) # [1, 2, 3, 11, 22, 33]
print(gl_num_list) # [1, 2, 3, 11, 22, 33]
2.9.8交换两个变量的值
a, b = 1, 100
# 1.1引入第三方变量
c = a
a = b
b = c
print(a, b)
# 1.2 不适用临时变量
a, b = 1, 100
a = a + b
b = a - b
a = a - b
print(a, b)
# 1.3 利用python元组
a, b = 1, 100
a, b = b, a
print(a, b)
2.10导入模块
2.10.1导入模块的几种方式
import xxx
import xxx,yyy
import xxx as zzz
from xxx import *
from xxx import mmm
from xxx import mmm,nnn
如:
import a
a.X=4
此时, 修改的a模块中的X的值
而from a import X
X=4
此时, 并未修改a模块中的X的值
总结:
多模块开发时, 若x,y模块均导入z模块的共享数据,
需要用Import方式导入, 不能用from z import m的方式导入
此外, 若是修改z模块的list, 需要用append方法, 不能用赋值(=)方式
2.10.2重新导入模块
假设一个启动中的项目, 已经通过下述方式导入了模块:
import xyz
此时需要修改xyz模块的代码, 并在不重启项目时令其生效,
方法如下:
from imp import reload
reload(xyz)
2.10.3import 搜索路径
import sys
print(sys.path)
[
'/usr/bin',
'/usr/lib/python35.zip',
'/usr/lib/python3.5',
'/usr/lib/python3.5/plat-x86_64-linux-gnu',
'/usr/lib/python3.5/lib-dynload',
'/usr/local/lib/python3.5/dist-packages',
'/usr/lib/python3/dist-packages',
'/usr/lib/python3/dist-packages/IPython/extensions',
'/home/python/.ipython'
]
程序执行时添加新的模块路径方法
sys.path.append('/home/hello/xxx')
sys.path.insert(0, '/home/hello/xxx') # 可以确保先搜索这个路径
3.文件操作
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件
open(文件名,访问模式)
示例如下:
f = open('test.txt', 'w')
访问模式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
w | 打开一个文件只用于写入。 如果该文件已存在则将其覆盖。 如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。 如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。 如果该文件不存在,创建新文件进行写入。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
wb | 以二进制格式打开一个文件只用于写入。 如果该文件已存在则将其覆盖。 如果该文件不存在,创建新文件。 |
ab | 以二进制格式打开一个文件用于追加。 如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。 如果该文件不存在,创建新文件进行写入。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
w+ | 打开一个文件用于读写。 如果该文件已存在则将其覆盖。 如果该文件不存在,创建新文件。 |
a+ | 打开一个文件用于读写。 如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。 如果该文件不存在,创建新文件用于读写。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
wb+ | 以二进制格式打开一个文件用于读写。 如果该文件已存在则将其覆盖。 如果该文件不存在,创建新文件。 |
ab+ | 以二进制格式打开一个文件用于追加。 如果该文件已存在,文件指针将会放在文件的结尾。 如果该文件不存在,创建新文件用于读写。 |
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# >>>>>>>>>>>>>>>>>>>>>> 文件操作 <<<<<<<<<<<<<<<<<<<<<<<<<<
# >>>>>>>>> 向文件中写数据
# 使用write()可以完成向文件写入数据
import os
from pathlib import Path
f = open('hello_python.txt', 'w')
f.write('hello world\ni am ok')
# 关闭这个文件
f.close()
# >>>>>>>>> 从文件中读数据
# 方法1:read(num)
# 使用read(num)可以从文件中读取数据,num表示要从文件中读取的数据的长度(单位是字节)
# 如果没有传入num,那么就表示读取文件中所有的数据
f = open('hello_python.txt', 'r')
content = f.read(10)
print(content) # hello worl
content = f.read()
print(content) # d, i am ok
f.close()
# 注意事项:
# 如果open是打开一个文件,那么可以不用写打开的模式,即只写open('test.txt')
# 如果使用读了多次,那么后面读取的数据是从上次读完后的位置开始的
# 方法2:readlines()
# readlines()可以按照行的方式把整个文件中的内容进行一次性读取,
# 并且返回的是一个列表,其中每一行的数据为一个元素
f = open('hello_python.txt', 'r')
content = f.readlines()
print(type(content))
lines = 1
for con in content:
print('lines %d : %s' % (lines, con))
lines += 1
f.close()
# 方法3:readline()
# readline()一次只返回一行数据
f = open('hello_python.txt', 'r')
content = f.readline()
print(content)
f.close()
# >>>>>>>>> 文件重命名
f = open('hello_test.txt', 'w')
f.write('hi')
f.close()
if f is False:
os.rename('hello_test.txt', 'hello_world.txt')
# >>>>>>>>> 文件删除
if f:
os.remove('hello_test.txt')
# >>>>>>>>> 创建一个目录
myFile = Path('dir0')
if myFile.exists() is False:
os.makedirs('dir0')
# >>>>>>>>> 获取当前目录
print(os.getcwd())
# >>>>>>>>> 删除文件夹
# os.remove('dir0')
# >>>>>>>>> 改变默认目录
# os.chdir('../')
print(os.getcwd())
# >>>>>>>>> 获取目录列表
print(os.listdir())
# ===================== 文件备份 ============================
oldFileName = 'hello_python.txt'
oldFile = open('hello_python.txt', 'r')
if oldFile: # 如果打开文件
fileFlagNum = oldFileName.rfind('.')
if fileFlagNum > 0:
fileFlag = oldFileName[fileFlagNum:]
# 组织新文件的名称
newFileName = oldFileName[:fileFlagNum] + 'bak' + fileFlag
# 创建新文件
newFile = open(newFileName, 'w')
# 把旧文件中的数据, 逐行放到新文件中
for con in oldFile.readlines():
newFile.write(con)
# 关闭文件
oldFile.close()
newFile.close()
# ===================== 文件的定位读写 ============================
# f.tell()获取当前读写的位置
f = open('hello_python.txt', 'r')
con = f.read(2)
print('读取的数据是: ', con)
position = f.tell()
print('当前文件光标位置是: ', position)
f.close()
# f.seek(offset, from)定位到某个位置
# offset: 偏移量
# from:方向
# 0: 表示文件开头
# 1: 表示当前位置
# 2: 表示文件末尾
# demo练习
# >>>> 由于python3对于非二进制的文本文件,不允许使用偏移定位, 所以此处文件打开方式应该是以二进制方式的
f = open('hello_python.txt', 'rb')
con = f.read(10)
print('当前文件光标位置是: ', f.tell())
# 把文件设置为:从文件开头,偏移2个字节
f.seek(2, 0)
print('把文件设置为:从文件开头,偏移2个字节: ', f.tell())
# 把文件设置为: 从当前位置, 偏移4个字节
f.seek(4, 1)
print('把文件设置为: 从当前位置, 偏移4个字节: ', f.tell())
# 把文件设置为: 离文件末尾, 偏移2个字节
f.seek(-2, 2)
print('把文件设置为: 离文件末尾, 偏移2个字节: ', f.tell())
f.close()
4.面向对象
4.1定义类
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 定义类时有2种:新式类和经典类,
# 经典类 class Car:
# 新式类 class Car(object)
# 类名的命名规则按照: "大驼峰"
import time
class Car:
# 定义一个类中的方法
def run(self):
print('>>>>>>>> car is running...')
# 魔法方法:
# 在python中方法名如果是__xxxx__()的,
# 那么就有特殊的功能,因此叫做“魔法”方法
# Python中没有像C++中public和private这些关键字来区别公有属性和私有属性
# 属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性
# 方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的
# __init__()方法,在创建一个对象时默认被调用,不需要手动调用---->类似于java中的构造器
# __init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)
# __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去
def __init__(self, color, brand):
self.color = color
self.__brand = brand
print('这是__init__方法')
# __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
# __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
# __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
# 我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节
def __new__(cls, *args, **kwargs):
print('这是__new__方法')
return object.__new__(cls)
def get_color(self):
return self.color
def set_color(self, color):
self.color = color
def get_brand(self):
return self.__brand
def set_brand(self, brand):
self.__brand = brand
# 定义了__str__(self)---->类似于java中的toString方法
# 当使用print输出对象的时候,
# 那么就会打印从在这个方法中return的数据
def __str__(self):
return '我是一辆' + self.color + '颜色的' + self.get_brand() + '车'
# 当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
def __del__(self):
print('删除了这辆车, 哈哈哈...')
car01 = Car('red', 'BMW')
car01.run()
car01.set_brand('Bentz')
print(car01.color, car01.get_brand(), car01)
car02 = car01
car03 = car01
# 当有1个变量保存了对象的引用时,此对象的引用计数就会加1
# 当使用del删除变量指向的对象时,如果对象的引用计数不为1,比如3,
# 那么此时只会让这个引用计数减1,即变为2,
# 当再次调用del时,变为1,
# 如果再调用1次del,此时会真的把对象进行删除
print("---马上 删除car01对象")
del car01
print("---马上 删除car02对象")
del car02
print("---马上 删除car03对象")
del car03
print("程序2秒钟后结束")
time.sleep(2)
4.2单继承
class Animal(object):
def __init__(self, name='动物', color='白色'):
self.__name = name
self.color = color
def __test(self):
print(self.__name)
print(self.color)
def test(self):
print(self.__name)
print(self.color)
class Dog(Animal): # Dog类继承于Animal
def dogTest1(self):
print(self.color, '///////') # 不能访问到父类的私有属性
def dogTest2(self):
print(self.test()) # 不能访问父类中的私有方法
A = Animal()
# print(A.__name) #程序出现异常,不能访问私有属性
print(A.color)
# A.__test() #程序出现异常,不能访问私有方法
A.test()
print('==============')
D = Dog('dog', 'black')
D.dogTest1()
D.dogTest2()
print(D.color, '==========')
# 总结:
# 子类在继承的时候,在定义类时,小括号()中为父类的名字
# 父类的属性、方法,会被继承给子类
# 私有的属性,不能通过对象直接访问,但是可以通过方法访问
# 私有的方法,不能通过对象直接访问
# 私有的属性、方法,不会被子类继承,也不能被访问
# 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
4.3多继承, 重写父类方法, 调用父类方法
class A:
def printA(self):
print('>>>>>>>>>..A..<<<<<<<<<<')
def printHello(self):
print('>>>>>>>>>..HelloA..<<<<<<<<<<')
class B:
def __init__(self, name):
self.name = name
def printB(self):
print('>>>>>>>>>..B..<<<<<<<<<<')
def printHello(self):
print('>>>>>>>>>..HelloB..<<<<<<<<<<')
class C(A, B):
# 调用父类的方法
def __init__(self, name):
super().__init__(name)
# 子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
def printA(self):
print('>>>>>>>>>..AC..<<<<<<<<<<')
def printC(self):
print('>>>>>>>>>..C..<<<<<<<<<<')
c1 = C('tom')
c1.printA()
c1.printB()
c1.printC()
c1.printHello()
# 说明
# python中是可以多继承的
# 父类中的方法、属性,子类会继承
# 如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?
# 子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
# 子类调用父类的方法: 如: super().__init__(name)
4.3.1Python中的MRO(方法搜索顺序)
python中有一个内置属性__mro__可以查看方法搜索顺序
method resolution order主要用于在多继承时判断方法,属性的调用路径/顺序, 按照顺序从左到右寻找, 找到就停止, 否则一直找, 找到最后仍未找到, 则报错...
print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
4.4多态
class F(object):
def show(self):
print('F.show')
class S1(F):
def show(self):
print('S1.show')
class S2(F):
def show(self):
print('S2.show')
def show(obj):
"""show函数需要接收一个F1类型或者F1子类的类型"""
print(obj.show())
show(S1())
show(S2())
4.5类属性及对象属性
stu01 = Stu(10, 'nj')
print(stu01.name)
# print(stu01.__id) ,不能在类外通过实例对象访问私有的类属性
# print(stu01.__addr) ,不能在类外通过实例对象访问私有的对象属性
print(stu01.age)
print(Stu.name)
# print(Stu.age) ,不能在类外通过类对象访问公有的对象属性
# print(Stu.__id) ,不能在类外通过类对象访问私有的类属性
# print(Stu.__addr) ,不能在类外通过类对象访问私有的对象属性
# 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改
# 如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,
# 并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,
# 除非删除了该实例属性。
stu01.name = 'tom'
print(stu01.name) # tom
print(Stu.name) # None
del stu01.name
print(stu01.name) # None
对象属性
一般定义在初始化方法中
类属性:
一般定义在类的成员属性中
4.5.1伪私有属性或私有方法
# python中没有真正意义上的私有属性或私有方法
# 可以通过下述方式访问私有方法和私有属性
# 开发中禁止使用!!!!!!!!!
class Person:
def __init__(self, name):
self.name = name
self.__age = 30
def __say_hello(self):
print("hello")
p1 = Person("tom")
print(p1._Person__age) # 访问私有属性
p1._Person__say_hello() # 访问私有方法
4.5.2@property属性
简介
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Pager:
def __init__(self, current_page):
self.current_page = current_page
self.per_items = 10
# property属性的功能是:
# property属性内部进行一系列的逻辑计算,最终将计算结果返回。
@property
def start(self):
return (self.current_page - 1) * self.per_items
@property
def end(self):
return self.current_page * self.per_items
page = Pager(2)
"""
定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
调用时,无需括号
"""
print("start: ", page.start)
print("end: ", page.end)
@property作为装饰器
class Money:
"""
@property作为装饰器
"""
def __init__(self):
self.__money = 0
@property
# 使用装饰器对money进行装饰,那么会自动添加一个叫money的属性,当调用获取money的值时,调用装饰的方法
def money(self):
return self.__money
@money.setter
# 使用装饰器对money进行装饰,当对money设置值时,调用装饰的方法
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print("输入有误")
@money.deleter
def money(self):
print("执行了对象的deleter方法")
m1 = Money()
del m1.money # 自动执行 @money.deleter 修饰的 price 方法
m1.money = 100 # 自动执行 @money.setter 修饰的 price 方法,并将 123 赋值给方法的参数
print(m1.money) # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
@property作为类属性
class Goods:
"""
@property作为类属性
"""
def __init__(self):
self.original_price = 100
self.discount = 0.8
def get_price(self):
return self.original_price * self.discount
def set_price(self, price):
print("======开始设置商品价格=======")
self.original_price = price
def del_price(self):
print("====删除了商品原始价格=======")
del self.original_price
PRICE = property(get_price, set_price, del_price, "价格")
g = Goods()
del g.PRICE # 删除商品原价
g.PRICE = 200 # 修改商品原价
print(g.PRICE) # 获取商品价格
4.5.3魔法方法(多为python解释器调用)
__doc__
表示类的描述信息
__module__
表示当前操作的对象在哪个模块
__class__
表示当前操作的对象的类是什么
__init__
初始化方法,通过类创建对象时,自动触发执行
__del__
当对象在内存中被释放时,自动触发执行
注:此方法一般无须定义,
因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,
因为此工作都是交给Python解释器来执行,
所以,__del__的调用是由解释器在进行垃圾回收时自动触发执行的。
__call__
对象后面加括号,触发执行
注:__init__方法的执行是由创建对象触发的,即:对象 = 类名() ;
而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
__dict__
类或对象中的所有属性
类的实例属性属于对象;类中的类属性和方法等属于类
__str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值
__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
__getslice__、__setslice__、__delslice__
该三个方法用于分片操作,如:列表
4.6类方法和静态方法
class Teacher(object):
name = 'jerry'
age = 20
# 类方法,用@classmethod来进行修饰, 参数中是cls,而非self
@classmethod
def getName(cls):
return cls.name
@classmethod
def setName(cls, name):
cls.name = name
# 静态方法,用@staticmethod来进行修饰, 参数中没有self或cls
@staticmethod
def getAge():
return Teacher.age
@staticmethod
def setAge(age):
Teacher.age = age
# 测试类方法
t1 = Teacher()
print(t1.getName())
print(Teacher.getName())
t1.setName('tom')
print(t1.getName())
print(Teacher.getName())
# 测试静态方法
print(Teacher.getAge())
Teacher.setAge(30)
print(Teacher.getAge())
# 从类方法和实例方法以及静态方法的定义形式就可以看出来,
# 类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;
# 而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),
# 不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。
# 静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用
静态方法:
主要用来存放逻辑性的代码,基本在静态方法中,不会涉及到类的方法和类的参数/属性, 也不涉及对象的方法和对象的参数/属性。
类方法:
是在传递参数的时候,传递的是类的参数/属性,参数是必须在cls中进行隐身传入, 而非实例属性
在继承的时候,静态方法和类方法都会被子类继承。在进行重载类中的普通方法的时候,只要 写上相同的名字即可进行重载。
总结
实例方法:
方法内部需要访问实例属性
实例方法内部可以使用"类名.类属性",访问类属性
类方法:
方法内部只需要访问类属性
静态方法:
方法内部, 既不需要访问类属性, 也不需要访问实例属性
###如果方法内部既需要访问类属性, 也需要访问实例属性,
###那么就定义成实例方法!!!!!!!!!!
4.7设计模式
4.7.1工厂模式
4.7.1.1简单工厂模式
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class BMW(object):
def run(self):
print('BMW is running...')
class Bentz(object):
def run(self):
print('Bentz is running...')
class CarFactory(object):
def createCar(self, carName):
if carName == 'BMW':
car = BMW()
elif carName == 'Bentz':
car = Bentz()
return car
class CarStore(object):
def __init__(self):
self.carFactory = CarFactory()
def createCar(self, carName):
car = self.carFactory.createCar(carName)
return car
carStore = CarFactory()
carStore.createCar('BMW').run()
4.7.2单例模式
# >>>>>>>>>>>>> 单例模式
class Singleton(object):
__instance = None
__first_init = False
# 创建单例 - 保证只有1个对象
def __new__(cls, name, age):
# 如果类数字能够__instance没有或者没有赋值
# 那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
# 能够知道之前已经创建过对象了,这样就保证了只有1个对象
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
# 创建单例时,只执行1次__init__方法
def __init__(self, name, age):
if not self.__first_init:
self.name = name
self.age = age
Singleton.__first_init = True
a = Singleton('tom1', 21)
b = Singleton('tom2', 22)
print(id(a), id(b))
4.8异常处理
# <<<<<<<<<< 捕获异常 >>>>>>>>>>>>>
# 捕获单个异常并获取异常的信息描述 try...except...
try:
open('aaa.txt', 'r')
except IOError as e: # Exception指捕获所有异常
print(e)
pass # pass 表示实现了相应的实现,但什么也不做
# 捕获多个异常 try...except...
try:
open('aaa.txt', 'r')
print(hello)
except (IOError, NameError) as e:
print('文件或变量找不到', e)
# 捕获异常 try...except...else...finally...
try:
open('hello_python.txt', 'r')
except IOError as e:
print(e)
else:
print('>>>>>>>>>文件读取正常<<<<<<<<')
finally:
print('>>>>>>>> 这段代码无论是否异常都会执行 <<<<<<<<<<')
4.9模块
4.9.1引入其他模块
不仅可以引入函数,还可以引入一些全局变量、类等
引入其他模块
import math # 模块名
引入其他模块中的函数
import math.sqrt # 模块名.函数名
from 模块名 import 函数名1,函数名2....
把一个模块的所有内容全都导入到当前的命名空间也是可行的
from modname import *
as 别名
import time as tt
tt.sleep(1) # 使用别名调用
4.9.2模块中的all函数
test0001.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__all__ = ['Test', 'test01'] # 这里定义可以被导入的类及函数
class Test(object):
def test(self):
print('test0001.py--->Test类--->test函数')
def test01():
print('test0001.py--->test01函数')
def test02():
print('test0001.py--->test02函数')
用于测试的py文件
# >>>>>>>>>>>>>> 模块
# 模块中的__all__
from test0001 import *
eee = Test()
eee.test()
test01()
test02() # 执行到这里会报错
4.9.3定位模块
当你导入一个模块,Python解析器对模块位置的搜索顺序是:
1.当前目录
2.如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。
3.如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/
4.模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。
4.10python中的内置函数
dir() # 查看内置函数
print(dir(fn02)) # fn02是函数名, 函数也是一个对象
print(fn02.__doc__, '======')
[
'__annotations__',
'__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__get__',
'__getattribute__',
'__globals__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__kwdefaults__',
'__le__',
'__lt__',
'__module__',
'__name__',
'__ne__',
'__new__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__'
]
网友评论