https://www.jianshu.com/p/1e375fb40506
# -*- coding:utf-8 -*-
"""
@author:zhen.xiao
@file:index.py
@time:2018/5/1210:04
"""
'''
使用模块:
注意:file必须得是含由__init__函数的文件夹或者是包(含由__init__)
from file import demo #调用模块语句
demo.Print() #执行file包中的demo.py
print __file__ #输出文件路径
print __doc__ #输出文档注释
'''
'''
函数避免了做重复的事情,做一个模板:
def Print(name):
print name,'在学习'
Print('肖震')
Print('小震')
'''
'''
函数式编程--返回值的使用,调用函数
注意自己的编程的习惯
函数之间上下代码间隔为2行,逗号','后面一定加一个空格
def login(username):
if username == '肖震':
return '登录成功'
detail(username)
else:
return '登录失败'
def detail(username):
print username, 'ssssssss'
if __name__ == '__main__':
user = raw_input('请输入用户名:')
res = login(user)
if res == '登录成功':
detail(user)
else:
print '失败失败'
login(user)
'''
'''
函数的参数不定,就可以这么做 *arg:默认当个函数列表传进来, **arg:字典
def show(*arg):
for item in arg:
print item
show('xiaozhen','xiao','xiaozhen','xiao','xiaozhen','xiao')
#传参数的时候可以根据标准的key=value去传,
#但是传参数的话就要把字典前面加上两个**
def show(**karg):
for item in karg.items():
print item
user_dict = {'k1': 123, 'k2': 456}
show(name='alex', age='24')
show(**user_dict) #会遇到非常多的这种情况
'''
# 生成器
'''
print range(10)
print xrange(10)
# 创建xrange的时候,没有立马出来,说明现在还没有到内存中----迭代器类型
# 但是当你用for循环去迭代它的时候,就会得到0-9
# 每一次循环,创建一次,相当于延迟创建
for item in xrange(10):
print item
# 生成器 延迟 可以在多线程的时候作为一个线程池
# 调用这个函数的时候你得到的什么也不是,这是一个生成器对象
# 生成器只有在你遍历的时候函数里面的代码才会执行,并且每一次循环只执行一条
def foo(): # generator object foo
yield 1
yield 2
yield 3
yield 4
yield 5
yield 6
re = foo()
for item in re:
print item
# 实例来练习生成器
def XiaoReadrLines():
seek = 0
while True:
with open('D:/temp.txt', 'r') as f:
f.seek(seek) # seek()根据设置的字节,按照字节往下读,默认为0,从文件的开始往下读
data = f.readline()
if data:
seek = f.tell() # 获取上一次读取的位置,下次再接着上一次的位置执行
yield data
else:
return # return之后整个函数都不再执行了,注意与yield的区别
# print XiaoReadrLines() 这样执行的话就是一个生成器
# generator object XiaoReadrLines at 0x000000000383DB88
for item in XiaoReadrLines():
print item
'''
'''
三元运算和lambda表达式
三元运算:
result = 'gt' if 1 > 3 else 'it'
(匿名函数)lambda表达式:匿名就是没有名字,只能调用一次(你的程序比较简单,并且不是经常会被调用,就可以写成lambda的形式)
a = lambda x,y:x+y
print a(4, 10)
而且lambda函数经常和 map() 一起使用:
map(lambda x: x**x, range(10))
temp = lambda x, y: x+y #x,y是参数,冒号:后面的内容就是对于参数的操作
print temp(4, 10)
'''
'''
内置函数
help() # 帮助
a = []
help(a)
dir() key
vars() key-value{}
type()
import temp
reload(temp) #python中模块只会导入一次,下一次用的时候不需要再去导入,如果还想导入,就用reload(temp)
id()
-----------------
print cmp(2, 3) -1
print cmp(2, 2) 0
print cmp(2, 1) 1
print cmp(10, 1) 1
print abs(-10) 10
print bool(-1) False
print divmod(9,3) # 得到的结果是9除以3的商和余数 (3, 0)
print divmod(9, 2) (4, 1)
print max([11,22,33,333]) 333
print min([11,22,33,333]) 11
print sum([11,22,33,333]) 399
---------------------------------------------
print all([1, 2, 3, 0]) # 判断后面可迭代对象的布尔值,如果全部为真,就输出True bool(0) = False
print all([1, 2, 3, 1])
print any([0, 0, 0, 0]) # 判断后面可迭代对象的布尔值,如果有一个为真,就输出True 全部为假,输出False
print any([1, 0, 0, 0])
# 通过上面的方式(all,any)就能判断列表里面有没有空的字符串
# 因为 bool('') 和 bool(None) = False
print chr(55) # 数字对应的字符 动态生成数字,然后通过chr()就能动态生成字母,也就是动态验证码的原理
print chr(65)
print chr(66)
# 与chr相反的就是ord() # 字母对应的数字
print ord('A')
print ord('B')
print hex(2) # 十六进制
print oct(2) # 八进制
print bin(2) # 二进制
----------------------------------------------------
xiao = ['手表', '汽车', '房子']
for item in xiao:
print item
for item in enumerate(xiao, 1): # 表示序列是从下标1开始的,可以随意定义
print item[0], item[1]
print item
------------------------------------------------------
字符串的格式化:
format
s = 'i am {0},{1}' # {0}和{1}表示占位符,想用的时候就往里面加参数
print s.format('alex', 'zhen')
------------------------------------------------------
print apply(Function, ('aaaaa')) # 执行函数
--------------
map(Function, iterable)
map做了一件事,就是遍历了list,并且把list中的每一个数当做参数传入当Function中
比如:
xiao = [11, 22, 33]
temp = map(lambda x: x+100, xiao)
print temp
--------------
filter(Function, iterable) #True序列
filter()做了一件事,就是对于list中的每一个元素传入Function中,当Function返回True的时候就留下,返回False的时候就过滤掉
xiao = [11, 22, 33]
def foo(arg):
if arg <= 22:
return True
else:
return False
temp = filter(foo,xiao)
print temp # 结果[11, 22]
----------------
reduce() #可以做累加累乘:下面例子,第一次计算1+2,得到的返回值3再与3相加,于是得到3+3 = 6
同理做累乘,第一次计算1*2,计算结果为2,返回2的值再与3相乘,得到最后结果2*3 = 6
reduce区别于上面的map和filter是它必须有两个参数,一个参数的话就返回那一个数
print reduce(lambda x,y: x+y,[1, 2, 3]) >>>6
print reduce(lambda x,y: x*y,[1, 2, 3]) >>>6
print reduce(lambda x, y: x+y, [1]) >>>1
print reduce(lambda x, y: x*y, [1]) >>>1
上面四个内置函数的总结:
以上四个的表达形式都是相同的,就是函数的名称不同
0. apply是执行函数的
1. map是对所有的元素进行操作
2. filter是进行过滤的,只有function的返回值为True的时候才会有操作 过滤嘛
3. reduce做累加累乘累除什么的
----------------------------------------------------------------------
zip():其实就是把传入的list的行变列,就是将每一行对应元素组成新的列,然后输出
x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]
q = [10, 11, 12]
print zip(x, y, z, q) >>>[(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]
如果元素少了怎么办?
x = [1, 2]
y = [4]
z = [7, 8, 9]
q = [10, 11, 12]
print zip(x, y, z, q) >>>[(1, 4, 7, 10)]
缺了哪个列对应的元素,哪个列就不显示白
----------------------------------------------------------------------
***反射***装逼利器 以字符串的形式导入模块: __import__(model),并且以字符串的形式执行函数: getattr(model,func)
大型程序:设计模式:比如工厂模式,就必须用这个实现,就避免耦合
开胃小菜:
假如老板给了你一个excle表,里面的内容是这样的:
```````````````
hostname memory
主机A 8*8
主机B 16*8
````````````````
你从表中读出的数据是a = '8*8',string类型,老板想让你对里面的内容计算,怎么弄呢?
eval(a)
作用就是: 将你读入的string类型的文本当做对象去计算里面的内容
a = '8*8' 假设就是你在表格内读出的内容
print eval(a) >>>64 #eval()函数将其计算出来
---反射来喽---
需求:给了你字符串,通过字符串导入模块
temp = 'sys' # sys是一个模块,平时就是import os 就可以了,但是我想让你通过字符串的形式导入
也就是说给了你一个变量temp,不准用import sys,就把sys模块导入进来
temp = 'sys'
model = __import__(temp)
print model.path # path是sys模块里面的方法,用于显示路径
# >>>['C:\\Users\\Mr.xiao\\PycharmProjects\\18day03\\main', 'C:\\Users\\Mr.xiao\\PycharmProjects\\18day03']等等
继续反射:
需求:
两个数据库模块,sql和sqlserver,两个模块内都有两个计算同样用户某样数据个数的函数count(),一个含有1条,一个含有2条,
之前都是使用
import sqlserverhelper
print sqlserverhelper.count()
现在down机了,要改数据库,需要下面形式进行改
import mysqlhelper
print mysqlhelper.count()
但是太麻烦了,还只是在mian函数里面改的
可以用 -----------反射(可以读string类型,通过字符串的形式导入模块,并且以字符串的形式执行函数)
# temp = 'mysqlhelper'
temp = 'sqlserverhelper'
model = __import__(temp)
print model.count >>><function count at 0x0000000002A0C518>
下面就是以字符串的形式执行函数
temp = 'mysqlhelper' 模块(字符串形式)
func = 'count' 模块里面的函数(字符串形式)
model = __import__(temp)
Function = getattr(model, func) # getattr就是去model这个模块中获取model中的函数,并且这个函数名是以字符串形式的
print Function >>>function count at 0x0000000002E5C518> 这里怎么返回的是函数呐???版本?返回应该是1
------------------------------------------------
getattr() 获取模块中的某一个函数
hasattr() 判断某一个函数中有没有某一个函数
module = __import__('sqlserverhelper')
print dir(module) >>>['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'count']
val = hasattr(module, 'version')
print val >>>False
delattr() 删除模块中的某一个函数
---------------------------------------------------------
这些面向对象的时候才会用到,都是用于操作类的
isinstance()
issubclass()
super()
staticmethod()
--------------------------------------------------------------
-----------------------常用模块---------------------------------
---------------------------------------------------------------
import random #random模块
# print random.random() # 生成0-1之间任意的随机数 >>>0.876753108367 再执行一次:0.0521871726502 再执行一次:0.172469152628
print random.randint(1, 2) # 生成范围之内的数字,而且是int型的,也就是只有1和2
print random.randint(1, 10) # 生成范围之内的数字,而且是int型的,也就是只有1-10(包括1和10)之间的int数
# >>>6 7 3 5
# print random.randrange(1, 10) # 生成的int型整数的范围变成 1<= x <10,左闭右开
如何随机生成字母:
import random
temp = random.randint(65, 90)
print chr(temp)
如何生成六位验证码,既包含数字又包含字母(做判断即可)
import random
code = []
for i in range(6):
if i == random.randint(1, 5):
code.append(str(random.randint(1, 5))) # 注意,这里的数字和下面的字母类型不一样,转换成字符串的时候会有问题,str转一下
else:
temp = random.randint(65, 90)
code.append(chr(temp))
print code
# >>> ['H', 'F', 'T', 'J', 'B', 'Y']
# >>> ['U', 'J', 5, 'Z', 'R', 'N']
# 字符需要格式化为字符串
print ''.join(code)
# VLSAZH
# IQ4DTY
或者:
import random
checkcode = ''
for i in range(4):
current = random.randrange(0, 4)
if current != i:
temp = chr(random.randint(65, 90))
else:
temp = random.randint(0, 9)
checkcode += str(temp) +=是字符串的拼接,要使用''.join(),这样的效率要高,否则+=每一次都要在内存中开辟空间
print checkcode
# VIF3 EFD3
-------------------------------------------------------------------
md5加密:md5不能再反写,用户输入的值可以先加密,再和md5的值进行对比
import hashlib
hash = hashlib.md5()
hash.update('admin')
print hash.hexdigest()
# >>>21232f297a57a5a743894a0e4a801fc3,加密之后是16进制
print hash.digest() # 和上面就是长度的区别
--------------------------------------------------------------------
序列化和json 以前web前后端都是xml,现在都被json取代了,同样的存储量,xml要比json大很多
pickle是用在python程序之间,用的比较多
序列化pickle
json只能提供常规格式的序列化 可以直接看出来格式,pickle是不可读的
序列化之后python和pyhton代码之间进行文件传输,也可以说成内存共享
序列化就是用dumps()
反序列化就是用loads()进行
序列化list到文件:dump(list,open('')),就是将dumps的s去掉即可
import pickle
xiao = ['alex', 11, 22, 'ok', 'shuai']
dumpsed = pickle.dumps(xiao)
print dumpsed
print type(dumpsed)
>>>
(lp0
S'alex'
p1
aI11
aI22
aS'ok'
p2
aS'shuai'
p3
a. 序列化的结果,不过就是看不懂
<type 'str'>
# 反序列化
loadsed = pickle.loads(dumpsed) # 用loads()进行反序列化
print loadsed # >>>['alex', 11, 22, 'ok', 'shuai']
print type(loadsed) # 类型就是list型,和序列化之前是一样的
# 如何序列化到文件呢??
import pickle
xiao = ['alex', 11, 22, 'ok', 'shuai']
# pickle.dump(xiao, open('D:/temp.pk', 'w')) # 把dumps改成dump就可以了,别忘了格式
result = pickle.load(open('D:/temp.pk', 'r'))
print result # >>>['alex', 11, 22, 'ok', 'shuai']
pickle和json的对比:
import json
name = {'name': 'xiaozhen', 'age': 23}
result = json.dumps(name)
print result
print type(result)
# >>> {"age": 23, "name": "xiaozhen"} <type 'str'>
import pickle
res = pickle.dumps(name)
print res
print type(res)
>>>
(dp0
S'age'
p1
I23
sS'name'
p2
S'xiaozhen'
p3
s.
<type 'str'>
import json
name = {'name': 'xiaozhen', 'age': 23}
result = json.dumps(name)
res = json.loads(result)
print res
# >>>{u'age': 23, u'name': u'xiaozhen'} 注意内存中默认形式是Unicode编码,所以加上了u开头了
-----------------------------------------------------------------------
re模块(正则表达式)
re.match(parttern, string, flags)flags这个参数不用管,默认即可
6个函数可以解决问题
complie()
match() search() findall()
group() groups()
import re
# re.match(你写的表达式, 一大堆给你的字符串让你进行匹配)
# re.search()格式同上
res1 = re.match('\d+', '123asfroi21e413ij4u3') # 注意哈,match只从开头开始找,找到(成功)就输出对象,找不到(失败)就输出None
print res1 # >>> <_sre.SRE_Match object at 0x000000000390E6B0>
res2 = re.search('\d+', 'asfroi21e413ij4u3') # search是从整个字符串开始找,连续往下找,知道找到就返回objext
print res2 # >>> <_sre.SRE_Match object at 0x000000000390E718>
print res1.group() # >>> 123 使用group()
print res2.group() # >>> 21
# 上面这俩,找不到的话都会返回None,None不是对象,就无法调用group函数,找到了就会返回对象,对象有group函数,就可以使用了
import re
res3 = re.findall('\d+', '123asfroi21e413ij4u3')
print res3 # >>> ['123', '21', '413', '4', '3']
# 之前的match和search都只是拿出来一个,就是找到就返回第一个,但是findall将所有的都返回
compile()编译,编译之后再去找就快了很多
import re
com = re.compile('\d+') # 编译一次,再去找99次,省了98次编译pattern,效率很高
print com.findall('123asfroi21e413ij4u3') # >>>['123', '21', '413', '4', '3']
# 上面的match,search,findall都是按照上面的格式进行的,先进性编译pattern,再去字符串中找
import re
res4 = re.search('(\d+)', '123asf4321roi21e413ij4u3') # 注意,这里的\d+被括号()括起来了
print res4.groups() # >>> ('123',) 注意与下面的区别,groups只和正则表达式的分组有关,注意res4的正则表达式被()起来,说明分组了
print res4.group() # >>> 123
res5 = re.search('(\d+)\w*(\d+)', '123asfr4321oi21e413ij4u3')
print res5.group() # >>> 123asfr4321oi21e413ij4u3 group就是把所有满足正则表达式的东西全拿出来
print res5.groups() # >>> ('123', '3') groups就是只获取组里面的东西,注意(\d+),这就是一个正则表达式组
常用的正则表达式格式:
\d : 数字
\w : 数字,字母,下划线
\t : 制表符
. : 除了回车以外的所有字符
* : >= 0
+ : >= 1
? : 0 or 1
{m} : m次
{m, n}: 表示范围,出现m次和n次之间的次数,包括m和n
import re
res0 = re.search('a{3,5}', 'aaaaa')
print res0.group() # >>> aaaaa
'''
# 44mins21
# -*- coding:utf-8 -*-
"""
@author:Levy
@file:index.py
@time:2018/5/1315:23
"""
'''
-----------------------------反射----------------------------------------
# 需求:我们根据用户输入的url的不同,去返回给用户不同的界面
# 规范 xxx/xxx
# ************搬砖式:************
from backend import account
data = raw_input('请输入地址:')
# array = data.split('/')
if data == 'account/login':
account.login()
elif data == 'account/logout':
account.logout()
# 要是有1W个地址你写1W行????
# 我们需要改进,用比较好的方式来实现功能
# **************反射:*************所有的主流web框架在干的事
data = raw_input('请输入地址')
array = data.split('/')
userspance = __import__(array[0]) # 导入模块account,array得到的是xxx/xxx中的前一个xxx
func = getattr(userspance, array[1]) # 注意,这个func的返回值就相当于整个函数
func() # 执行函数
# 详细解析,getattr的第一个参数是我们导入的模块,第二个参数是模块的函数,都是str类型的
# 但是上述代码执行不了 >>> ImportError: No module named account
分析
data = raw_input('请输入地址')
array = data.split('/')
下面一句执行之后的是 array[0] = account
userspance = __import__(array[0])
注意 我们自己导入模块的时候:
from backend inport account
所以说上面的userspance是通过account.array[0],并没有加backend
还有一种自己导入模块的方式:
import backend.account
account.login()
所以我们这里的userspance = __import__(array[0])就相当于这一句:
import backend.account(这里的backend是需要加一个字符串的拼接):__import__('backend.'+array[0])
所以说我们想要调用里面的函数的话还得再导入一次,因为上面是account.login(),还需要account这个模块嘛
func = getattr(userspance, array[1])
func()
所以,总结一下:
1. 导入模块的时候加backend这个字符串链接 __import__('backend.'+array[0])
2. 如果有反射的话,需要再执行一次getattr()
data = raw_input('请输入地址:')
array = data.split('/')
userspance = __import__('backend.'+array[0])
model = getattr(userspance, array[0])
func = getattr(model,array[1])
func()
>>> 请输入地址:admin/index
欢迎登陆后台管理界面
'''
# -*- coding:utf-8 -*-
"""
@author:Levy
@file:sqlhelper.py
@time:2018/5/1321:51
"""
# 以下显示静态字段的作用
class MsSqlHelper:
def add(self,sql):
pass
def delete(self,sql):
pass
def update(self,sql):
pass
def select(self,sql):
pass
# 下面的方法针对每一个业务方,需要创建n多个对象,在内存中开辟n多个空间
ms = MsSqlHelper()
ms.update(sql)
# 下面静态字段发挥作用了
class MsSqlHelper:
@staticmethod
def add(sql): # 注意,不需要self了
pass
@staticmethod
def delete(sql):
pass
@staticmethod
def update(sql):
pass
@staticmethod
def select(sql):
pass
# 下面我们要使用相关的方法,就可以根据每一个业务就可以直接使用类.去调用方法,就不用创建那么多对象
'''
来一个吊的问题:
python中类的静态方法的作用
通过不实例化类就可以调用类中的方法
问题来了:
我们不实例化类就直接调用类中的方法 和 我直接调用模块.函数名 有什么区别呢?
1. 在内存里是没有区别的
在类中直接使用@staticmethod字段使得一个方法变成静态方法 在逻辑上是属于这个类的
但是其他的跟外面都是一样的,也就是说,类的静态方法和外面的方法是一样的,只是给了这个方法一个从属关系,它是属于这个类的
鸡肋?
官方解释来了
高手在设计语言的时候,不会做无用功,或者是很少做无用功
为什么模块有了这个方法之后 又要设计出来静态的这个方法,他们的价值是一样的
但是,
python在最初设计的时候,是模块化编程的思想,其实并不支持面向对象
只要我定义好模块,我想用哪一种方法,在我使用的时候调用这个模块就行了
所以说python最初是没有静态这个概念的
静态这个概念是怎么产生的呢? 我在进行面向对象编程的时候,面向对象编程是从java中提出的
在用java的时候你会发现,在用面向对象的时候必须要new出来东西,也就是要把对象构造出来,才能用里面的方法
但是一构造,就会在内存的堆里面开辟空间,内存里面有堆有栈什么的,堆里面就会有一块区域专门用来装这些东西
如果没有静态方法,100个对象在要用数据库的时候,我们就要构造100个方法,这是在面向对象编程中没法避免的问题
所以java设计出来叫做静态的东西,静态的东西在内存中只保存一份,当我们在调用静态方法的时候,就只会在那个专门的区域中找
不会给它单独开辟一块区域,所以,静态是专门应对面向对象编程产生的东西
python为什么有了模块化编程之后又有了这个静态呢?
是因为python想支持面向对象编程,于是乎python又把面向对象的所有的东西拿过来又做了一次
具体你选择用什么东西,这要看你的个人选择,为什么这个问题会产生?
因为这是一个历史遗留问题,这是两种编程思想的碰撞。。。
模块化编程和面向对象编程两种思想的区别?
面向对象是灵活性的考虑,能够避免重复的代码
多态 面向对象存在并且比模块化编程的最大优势所在
因为类这个东西嘛,和模块形式上差不多的,在编程的时候,你很难在开始的时候就知道要写什么什么类,都是在编程的过程中,
你觉得这几个方法应该放到一个类中,才会想着把他们变成一个类
python的模块式编程是非常强大的,也可以实现多态
java是强制性语言,在定义的时候你必须告诉我类型是什么
反射 + 模块化编程 == 面向对象编程 ?
但是用java的时候,就要选面向对象编程
面向对象更多考虑到可扩展性,在做一件事之前,就要考虑好整体的框架
面向函数式编程更像是一个莽夫,走一步写一步,高手来说,可能写的时候整体框架就有了,但是新手还是面向对象吧
'''
# -*- coding:utf-8 -*-
"""
@author:Levy
@file:index.py
@time:2018/5/1321:50
"""
'''
-----------------------------------类和对象-----------------------------------------
注意与之前学习的区别,在类中要有__init__()
class Province(object):
def __init__(self, name, captial, leader):
self.Name = name
self.Captial = captial
self.Leader = leader
hebei = Province('河北', '石家庄', 'XXX')
shanddong = Province('山东', '济南', '肖震')
三个问题:self是啥,name是啥,是否可以加默认参数 注意类的封装
先看哈,我们传hebei = Province()的三个参数给__init__(),但是self没传,其实pyhton帮你传了,传的是对象名heibei
我们想要看heibe的省会怎么看?
print hebei.Captial
那这里的hebei就相当于__init__()中的self
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
#动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
hebei = Province('河北', '石家庄', 'XXX')
shandong = Province('山东', '济南', '肖震')
print shandong.Captial 属于对象的就用对象.调用 属于对象的就叫做动态字段 类不能访问动态字段
print Province.memo memo属于类,就用类.调用 属于类的就叫做静态字段 对象能访问静态字段(避免)
>>>济南 hebei.memo可以访问
中国的23个省之一
在类里面定义方法,供给对象用的
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 动态方法,类不能访问,假如访问的话,返回谁?河北?山东? self都不知道是什么,Name也不知道啊------需要实例化
def sport_meet(self):
print self.Name + '正在开运动会'
hebei = Province('河北', '石家庄', 'XXX')
shandong = Province('山东', '济南', '肖震')
shandong.sport_meet() # >>> 山东正在开运动会
有了静态字段,动态字段,动态方法,还缺一个静态方法,如下两步
1. 在动态方法上面加上装饰器 @staticmethod,把原来的动态方法就变成了静态方法
2. 去掉self,因为静态方法属于类,所以不需要self,self是对象,类访问不了对象的东西
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 静态方法
@staticmethod
def anti_corruption(): # 去掉了self
print '每个省都要带头反腐'
hebei = Province('河北', '石家庄', 'XXX')
shandong = Province('山东', '济南', '肖震')
Province.anti_corruption() >>> 每个省都要带头反腐
特性
@property 方法的访问形式 变成 字段的访问形式
在绑定属性的时候,如果我们直接把属性暴露出去,虽然写起来简单,但是,没有办法检查参数,导致可以随便把属性的值进行修改
比如:
s = Student()
s.score = 9999
这显然不合理啊,为了限制score的范围,可以通过一个set_score()方法来设置成绩(主要进行范围限制),再通过get_score()方法获取成绩
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
这样,对于任意的Student实例进行操作,就不能随心所欲地设置score了:
>>> s = Student()
>>> s.set_score(60) # ok!
>>> s.get_score()
60
>>> s.set_score(9999)
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。
有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?
还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。
Python内置的@property装饰器就是负责把一个方法变成属性调用的:
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer')
if value < 0 or value > 100:
raise ValueError('score must be 0~100')
self._score = value
@property比较复杂,先考虑如何使用,把一个getter方法变成属性只要加上@property
此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
于是,就有了一个可以控制的属性控件
----------------方法变成了属性调用了----------
>>> s = Student()
>>> s.score = 60 # 实际转化为s.set_score(60)
>>> s.score # 实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
---------------------------------------------
注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
@property广泛应用在类的定义中,可以让调用者写出简短的代码-----少了get和set方法
同时保证对参数进行必要的检查----@birth.setter,这样,程序运行时就减少了出错的可能性
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 静态方法
@staticmethod
def anti_corruption():
print '每个省都要带头反腐'
@property # bar就是一个只读属性
def bar(self):
print self.Name
hebei = Province('河北', '石家庄', 'XXX')
shandong = Province('山东', '济南', '肖震')
hebei.bar >>> 河北 注意,这里不加括号,因为是特性@property
小结:类里面三种结构了:
字段(静态,动态字段),方法(静态,动态方法),特性(@property)
----------------------公有和私有-----------------------------
私有字段就是__变量名(两个下划线) 可以让你看,但是你不能改,毕竟python的安全机制要差一点
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader, flag):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 私有字段
self.__Thailand = flag
# 动态方法
def show(self):
print self.__Thailand
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
#私有方法
def __xiao(self):
print 'I am xiaozhen'
def zhen(self):
self.__xiao()
# 静态方法
@staticmethod
def anti_corruption():
print '每个省都要带头反腐'
japan = Province('日本', '东京', '小泽', True)
print japan.__Thailand # >>> 报错 直接用对象去访问__.Thailand(私有字段)访问不到 直接不行
japan.show() # >>> True 但是通过类自己的动态方法去访问私有字段就可以访问得到 间接行
japan.__xiao() # >>> 报错 对象不能直接访问类的私有方法 直接不行
japan.zhen() # >>> I am xiaozhen 通过类自己内部的方法可以访问私有方法 间接行
# 另外一种方式就是利用@property,然后外部通过property来访问类中的私有字段
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader, flag):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 私有字段
self.__Thailand = flag
# 动态方法
def show(self):
print self.__Thailand
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 私有方法
def __xiao(self):
print 'I am xiaozhen'
def zhen(self):
self.__xiao()
# 静态方法
@staticmethod
def anti_corruption():
print '每个省都要带头反腐'
@property
def Thailand(self):
return self.__Thailand
japan = Province('日本', '东京', '小泽', True)
print japan.Thailand # >>> True
私有字段可以给你看,不过不让你改 推荐使用下面的方式进行修改和查看私有字段
class Province(object): # 要先继承Object类,才能实现下面的可写@Thailand.setter
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader, flag):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 私有字段
self.__Thailand = flag
# 动态方法
def show(self):
print self.__Thailand
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 私有方法
def __xiao(self):
print 'I am xiaozhen'
def zhen(self):
self.__xiao()
# 静态方法
@staticmethod
def anti_corruption():
print '每个省都要带头反腐'
@property # 这里是可读 注意写法:@property
def Thailand(self):
return self.__Thailand
@Thailand.setter # 这里是可改 注意写法:@Thailand.setter 删了这一段就是可读的
def Thailand(self, value):
self.__Thailand = value
japan = Province('日本', '东京', '小泽', True)
print japan.Thailand
japan.Thailand = False
print japan.Thailand
# >>> True False
继承了object写的话得用@函数名.setter
不继承便可以可读可写
-----------------------------析构函数-----------------------------------
对象创建了得销毁掉吧
注意,析构函数不是自己销毁内存的,销毁内存是python自带的解释器干的,解释器会有一套算法,检查对象是否还有人用,没有人用的话就销毁了
析构函数是这样的,解释器不是有销毁动作嘛,如果你想让解释器销毁的时候做点什么,就写到析构函数里面
怎么写???
class Foo:
def __init__(self):
pass
def __del__(self): # 析构函数
print '解释器要销毁我了,我要做最后的挣扎!'
# 解释器通知一声(就是执行析构函数(__del__)),然后就真的把对象销毁了
----------------------------call—--------------------------------
__call__就是一个函数,就是调用方式不一样而已,自己想什么时候用就什么时候用
import time
class Foo:
def __init__(self):
pass
def __del__(self):
print '析构函数'
def Go(self):
print 'Go'
def __call__(self):
print 'Call'
f1 = Foo() # 创建类Foo的对象
f1.Go() # 对象.方法名调用方法
time.sleep(100) 程序在这里睡一会,但是下面还有对象的调用,所以就不能执行析构函数,析构函数一定是最后执行的,
因为一旦执行了析构函数,就把对象干掉了。
f1() # 就是对象加上括号就会执行__call__方法
--------------------------------类的继承------------------------------
class Father:
def __init__(self):
self.Fname = 'fffff'
def Func(self):
print 'father.Func'
def Bad(self):
print 'father.抽烟喝酒烫头'
class Son(Father):
def __int__(self):
self.Sname = 'sssss'
def Bar(self):
print 'son.bar'
def Bad(self):
Father.Bad(self)
print 'son.赌'
s1 = Son()
s1.Bar()
s1.Func()
s1.Bad()
>>>
son.bar
father.Func
father.抽烟喝酒烫头
son.赌
调用父类的构造函数
使用super必须继承object
继承了object 新式类(现在都使用,向面向对象发展)
没有继承Object 经典类
# 下面程序有点疑问,输出结果与视频中的解释不同,day04 24
class Father(object):
def __init__(self):
self.Fname = 'fffff'
# print 'Father.__init__'
def Func(self):
print 'father.Func'
def Bad(self):
print 'father.抽烟喝酒烫头'
class Son(Father):
def __int__(self):
self.Sname = 'sssss'
print 'Son.__init__'
Father.__int__(self)
super(Son, self).__init__() # 调用父类的构造方法,父类继承object,注意写法 super(Son, self).__init__()
def Bar(self):
print 'son.bar'
def Bad(self):
Father.Bad(self)
print 'son.赌'
s1 = Son()
s1.Bar()
s1.Func()
s1.Bad()
# 新式类和经典类的区别
python2.2产生了新式类,2.2之前都是经典类,新式类在经典类的基础上加了一些东西
比如加入了__slot__,只能限制你调用类里面的某一个方法,还有一些其他的,比如__name__,__doc__,__get__,__set__,__delete__
还有一点就是python修复了一个bug,就是经典类在面临多继承的时候可能会出现问题
------------------------------------抽象类--------------------------
自己去看
接口,不能具体实现,只能定义规则
架构师给你一个规范,你写的时候就要按照这个规范去做,不做就会报错
抽象类 + 抽象方法 = 接口(第二种接口,即规范)
from abc import ABCMeta,abstractmethod
class Alert:
__metaclass__ = ABCMeta
@abstractmethod
def Send(selfs):pass
class Wechat(Alert):
def __int__(self):
print '__int__'
def Send(self): 既然继承了接口Alert,就要按照规范去做,去复写里面的抽象方法
print 'send.Wechat'
f = Wechat()
f.Send()
>>> send.Wechat
'''
# -*- coding:utf-8 -*-
"""
@author:Levy
@file:Multiple_Inheritance_Problem.py
@time:2018/5/1420:00
"""
'''
# 经典类的多重继承问题
经典类是深度优先,而新式类是广度优先
如何理解呢?
先上图,再上代码:
class A: (def save(self):...)
· ·
· ·
classB classC:(def save(self):...)
· ·
· ·
classD
# 经典类的写法,不继承object
class A:
def __int__(self):
print 'This is A'
def save(self):
print 'save method from A'
class B(A):
def __int__(self):
print 'This is B'
class C(A):
def __int__(self):
print 'This is C'
def save(self):
print 'save method from C'
class D(B, C): # 看好 D继承了B和C,
def __int__(self):
print 'This is D'
c = D() # c是D的对象
c.save()
>>> save method from A 这就是bug
# c调用save方法,很遗憾D没有,只有去B中去找,很遗憾,B也没有,那么!!!!
# 问题出在这里,c并没有去找另一个继承的类C,而是去找A了,也就是深度优先,这不是我们想要的
来来来 看看新式类 只要A继承了object就可以,其他不用改,结果就是广度优先
也就是说,B没有了之后,c会去C类中去找save()方法,所以结果输出如下所示
class A(object):
def __int__(self):
print 'This is A'
def save(self):
print 'save method from A'
class B(A):
def __int__(self):
print 'This is B'
class C(A):
def __int__(self):
print 'This is C'
def save(self):
print 'save method from C'
class D(B, C): # 看好 D继承了B和C, B和C的摆放也是有讲究的,谁在前面优先执行谁
def __int__(self):
print 'This is D'
c = D() # c是D的对象
c.save()
>>> save method from C
'''
# -*- coding:utf-8 -*-
"""
@author:Levy
@file:exception.py
@time:2018/5/1420:46
"""
'''
data = raw_input('请输入网址:')
array = data.split('/')
try:
userspance = __import__('backend.'+array[0])
model = getattr(userspance, array[0])
func = getattr(model, array[1])
func()
except ImportError, e:
print 1, e
print '跳转到自定义的404'
except AttributeError, e:
print 2, e
print '跳转到自定义的404'
except Exception, e:
print 3, e
print '跳转到自定义的404'
else:
print 'No Error'
finally:
print '无论出错与否,都会执行这个语句,finally和else都可以没有'
请输入网址:a/b
1 No module named a
跳转到自定义的404
无论出错与否,都会执行这个语句,finally和else都可以没有
请输入网址:account/l
2 'module' object has no attribute 'l'
跳转到自定义的404
无论出错与否,都会执行这个语句,finally和else都可以没有
请输入网址:account/login
login
No Error
无论出错与否,都会执行这个语句,finally和else都可以没有
--------------------------自定义的错误-----------------------------
上面都是python自带的错误,我们想要自己的错误
class MyException(Exception):
def __int__(self, msg):
self.error = msg
def __str__(self, *args, **kwargs):
return self.error
# obj = MyException('自定义信息错误')
# obj
raise MyException('自定义错误') 这句话是主动触发错误
为什么要主动触发异常呢???主动触发异常有什么作用吗?
来来来 给你瞅一眼作用
下面是一个检验用户登录的函数
def Validate(name, pwd):
if name == 'xiaozhen' and pwd == '52105210':
return True
else:
return False
try:
res = Validate('xiaozhen', '123')
if res:
print '登录成功'
else:
# print '记录日志到数据库' # 假如else有很多,下面的语句要写很多,我们便可以主动触发异常
# print '登录失败'
raise Exception('登录失败') # 主动触发可以巧妙减少很多代码
except Exception, e:
print '记录日志到数据库'
print e
>>> 记录日志到数据库
登录失败
'''