---------2018.1.24------------
round是向上取整,引用方式为round(number[,ndigits])
而floor是向下取整,floor函数通过import math导入,引用方式为math.floor(number)
str函数,它会把值转换成合理形式的字符串,函数原型为str(object)//字符串要用双引 号引起来,数字不需要
repr函数,它会创建一个字符串.以合法的Python表达式的形式来表示值,函数原型为repr (object)
如果你希望打印一个包含数字的句子,加上``(反引号)可以很方便的输出
input()与raw_input()区别
input()会假设用户输入的是合法的python表达式,例如字符串一定要用引号引起来
而raw_input()会把所有的输入当作原始数据将其放入字符串中
如果你需要写一个非常长的字符串,需要跨越多行,可以使用三个引号(单引号和双引号均 可)代替.
如果一行中最后一个字符是反斜杠\,那么换行符本身就"转义"了,也就是被忽略了.
原始字符串r'x'或者r"x",几乎可以输出任何字符,唯一不行的就是原始字符串最后的一个 字符不能是反斜杠,要输出反斜杠\,只有对原反斜杠\进行转义,形式为'\\'
pow(x,y[,z]) 返回x的y次幂(所得结果对z取模)
---------2018.2.6------------
利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()
方法
1 # -*- coding: utf-8 -*-
2 def trim(s):
3 if s[:1] != ' ' and s[-1:] != ' ':
4 return s
5 elif s[:1] == ' ':
6 return trim(s[1:])
7 else:
8 return trim(s[:-1])
9 # 测试:
10 if trim('hello ') != 'hello':
11 print('测试失败!')
12 elif trim(' hello') != 'hello':
13 print('测试失败!')
14 elif trim(' hello ') != 'hello':
15 print('测试失败!')
16 elif trim(' hello world ') != 'hello world':
17 print('测试失败!')
18 elif trim('') != '':
19 print('测试失败!')
20 elif trim(' ') != '':
21 print('测试失败!')
22 else:
23 print('测试成功!')
汉诺塔的移动可以用递归函数非常简单地实现。
请编写move(n, a, b, c)
函数,它接收参数n
,表示3个柱子A、B、C中第1个柱子A的盘子数量,然后打印出把所有盘子从A借助B移动到C的方法,例如:
1 def move(n,a,b,c):
2 if(n==1):
3 print(a,'-->',c)
4 else:
5 move(n-1, a, c, b)
6 move(1, a, b, c)
7 move(n-1, b, a, c)
8 move(3, 'A' , 'B', 'C')
请使用迭代查找一个list中最小和最大值,并返回一个tuple:
1 # -*- coding: utf-8 -*-
2 def findMinAndMax(L):
3 length=len(L)
4 if(length==0):
5 return (None,None)
6 elif(length==1):
7 return (L[0],L[0])
8 else:
9 minn=L[0]
10 maxn=L[0]
11 for x in L:
12 if(x>=maxn):
13 maxn=x
14 if(x<=minn):
15 minn=x
16 return (minn,maxn)
17 # 测试
18 if findMinAndMax([]) != (None, None):
19 print('测试失败!')
20 elif findMinAndMax([7]) != (7, 7):
21 print('测试失败!')
22 elif findMinAndMax([7, 1]) != (1, 7):
23 print('测试失败!')
24 elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):
25 print('测试失败!')
26 else:
27 print('测试成功!')
杨辉三角定义如下:
1
/ \
1 1
/ \ / \
1 2 1
/ \ / \ / \
1 3 3 1
/ \ / \ / \ / \
1 4 6 4 1
/ \ / \ / \ / \ / \
1 5 10 10 5 1
把每一行看做一个list,试写一个generator,不断输出下一行的list:
1 # -*- coding: utf-8 -*-
2 def triangles():
3 a = [1]
4 while True:
5 yield a
6 a = [sum(i) for i in zip([0] + a, a + [0])]
7
8 # 期待输出:
9 # [1]
10 # [1, 1]
11 # [1, 2, 1]
12 # [1, 3, 3, 1]
13 # [1, 4, 6, 4, 1]
14 # [1, 5, 10, 10, 5, 1]
15 # [1, 6, 15, 20, 15, 6, 1]
16 # [1, 7, 21, 35, 35, 21, 7, 1]
17 # [1, 8, 28, 56, 70, 56, 28, 8, 1]
18 # [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
19 n = 0
20 results = []
21 for t in triangles():
22 print(t)
23 results.append(t)
24 n = n + 1
25 if n == 10:
26 break
27 if results == [
28 [1],
29 [1, 1],
30 [1, 2, 1],
31 [1, 3, 3, 1],
32 [1, 4, 6, 4, 1],
33 [1, 5, 10, 10, 5, 1],
34 [1, 6, 15, 20, 15, 6, 1],
35 [1, 7, 21, 35, 35, 21, 7, 1],
36 [1, 8, 28, 56, 70, 56, 28, 8, 1],
37 [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
38 ]:
39 print('测试通过!')
40 else:
41 print('测试失败!')
1 # -*- coding: utf-8 -*-
2 L1 = ['Hello', 'World', 18, 'Apple', None]
3 L2 = [s.lower() for s in L1 if isinstance(s,str)==True]
4 # 测试:
5 print(L2)
6 if L2 == ['hello', 'world', 'apple']:
7 print('测试通过!')
8 else:
9 print('测试失败!')
split翻译为分裂。 split()就是将一个字符串分裂成多个字符串组成的列表。
split()当不带参数时以空格进行分割,当代参数时,以该参数进行分割。
//---当不带参数时
example:
st0= ' song huan gong '
print(st0.split())
结果为:
['song', 'huan', 'gong']
结论:当不带参数时,默认是以空格作为参数,不管空格在哪,或者有几个 全部被镐掉了!
//---当带参数时 这种情况就不能按照上面的方式去理解了
example:
st0= 'iisongiiihuaniiiigongi'
print(st0.split('i'))
结果为:
['', '', 'song', '', '', 'huan', '', '', '', 'gong', '']
分析:
这个结果可能就有点出乎意料了并不是想象中的['song', 'huan', 'gong'] 而是多了很多空字符串元素'',这个怎么理解呢? 我的理解方式是,当带参数时,我们得把字符串想象成一块五花肉,我们要做 一件奇葩的事情,就是将肥肉丢到垃圾桶,把瘦肉留下。 比如'iisongiiihuaniiiigongi'这串五花肉,'i'就是要丢掉的肥肉,每次还只能切 'i'这么多。 切的时候是从左到右,一刀下去肥肉'i'丢掉,刀刃左边的部分拿走作为list的一个元素, 刀刃右边的就是剩下的,那么继续切剩下的部分,直到切完。
'iisongiiihuaniiiigongi'这块肉比较特殊:
其一、他的开始和结尾都有i,而且i还不止一个!这样按照上述的方法就会切出 空气,就是列表中我们看到的'', 空字符串元素。 如'iisongiiihuaniiiigongi',当第一刀下去的时候,第一个i被丢到了垃圾桶, 而刀刃的左边什么都没有,所以列表的第一个元素就是'',空字符串元素。 一刀下去之后,就剩下'isongiiihuaniiiigongi'。 所以第二刀下去之后,又得到一个空字符串元素,目前“肉”就剩下'songiiihuaniiiigongi'。 第三刀又切掉一个i,那么刀刃左边的就是song,所以第三个元素就是'song'。 直到切到最后,整坨肉就只剩下一个i了,使用最后一刀下去i被切掉了,刀刃的左边此时也 什么都没有了,所以最后一个元素任然是空字符串。
一个超级好的例子:
1 >>> str="hello boy<[www.doiido.com]>byebye"
2 >>> str.split("[")[1].split("]")[0]
3 'www.doiido.com'
4 >>> str.split("[")[1].split("]")[0].split(".")
5 ['www', 'doiido', 'com']
利用map
和reduce
编写一个str2float
函数,把字符串'123.456'
转换成浮点数123.456
:
1 # -*- coding: utf-8 -*-
2 from functools import reduce
3 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
4 def char2num(s):
5 return DIGITS[s]
6 def str2float(s):
7 s=s.split('.')
8 if len(s[0])==0:
9 s[0]='0'
10 return reduce(lambda x,y:x*10+y,map(char2num,s[0]))+reduce(lambda x,y:x*10+y,map(char2num,s[1]))*pow(0.1,len(s[1]))
11 print('str2float(\'123.456\') =', str2float('123.456'))
12 if abs(str2float('123.456') - 123.456) < 0.00001:
13 print('测试成功!')
14 else:
15 print('测试失败!')
Python提供的sum()
函数可以接受一个list并求和,请编写一个prod()
函数,可以接受一个list并利用reduce()
求积:
1 # -*- coding: utf-8 -*-
2 from functools import reduce
3 def prod(L):
4 return reduce(lambda x,y:x*y,L)
5 print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))
6 if prod([3, 5, 7, 9]) == 945:
7 print('测试成功!')
8 else:
9 print('测试失败!')
利用map()
函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:['adam', 'LISA', 'barT']
,输出:['Adam', 'Lisa', 'Bart']
:
1 # -*- coding: utf-8 -*-
2 def normalize(name):
3 name=name[0].upper()+name[1:].lower()
4 return name
5 # 测试:
6 L1 = ['adam', 'LISA', 'barT']
7 L2 = list(map(normalize, L1))
8 print(L2)
回数是指从左向右读和从右向左读都是一样的数,例如12321
,909
。请利用filter()
筛选出回数:
1 # -*- coding: utf-8 -*-
2 def is_palindrome(n):
3 nn = str(n) #转成字符串
4 return nn == nn[::-1] #反转字符串并对比原字符串返回true/false
5 # 测试:
6 output = filter(is_palindrome, range(1, 1000))
7 print('1~1000:', list(output))
8 if list(filter(is_palindrome, range(1, 200))) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]:
9 print('测试成功!')
10 else:
11 print('测试失败!')
---------2018.2.7------------
请把下面的Student
对象的gender
字段对外隐藏起来,用get_gender()
和set_gender()
代替,并检查参数有效性:
1 # -*- coding: utf-8 -*-
2 class Student(object):
3 def __init__(self, name, gender):
4 self.name = name
5 self.gender = gender
6 def get_gender(self):
7 return self.gender
8 def set_gender(self,gender):
9 if gender=='male' or gender=='female':
10 self.gender=gender
11 else:
12 raise ValueError('gender error')
13 # 测试:
14 bart = Student('Bart', 'male')
15 if bart.get_gender() != 'male':
16 print('测试失败!')
17 else:
18 bart.set_gender('female')
19 if bart.get_gender() != 'female':
20 print('测试失败!')
21 else:
22 print('测试成功!')
2018/3/5
ubuntu16.04自带python的环境,不用进行python环境安装, 在安装好环境的虚拟机中,提供了py2,py3,django_py2,tornado_py2,spider_py2,django_py3的虚拟环境
mysql安装 sudo apt-get install mysql-server sudo apt-get install libmysqlclient-dev 注意安装server端的时候会提示输入密码,记住这个密码。然后通过命令登入数据库
redis安装 sudo apt-get install redis-server 通过redis-cli登入 mongoDB安装 详情请参考 http://blog.csdn.net/zgf19930504/article/details/52045600 postgresql安装 sudo apt-get install postgresql sudo apt-get install libpq-dev elasticsearch安装(django项目使用) sudo apt-get install elasticsearch 其它依赖包 sudo apt-get install python-dev
3.django环境安装 我们将虚拟环境所需的包全部放在install.txt,以下是django_py3项目所需环境: django==1.7.4 jsonfield Pillow==2.8.2 celery amqp==1.4.9 anyjson==0.3.3 billiard==3.3.0.23 celery==3.1.23 decorator==4.0.10 Django==1.7.8 django-haystack==2.5.0 django-redis-sessions==0.5.6 ipdb==0.8.1 ipython-genutils==0.1.0 jsonfield==1.0.3 kombu==3.0.35 psycopg2==2.6.2 pytz==2016.6.1 redis==2.10.5 setuptools==25.1.0 wheel==0.29.0 执行pip3 install -r instal.txt命令即可
4.tornado环境安装 在tornado_py2虚拟环境中安装: ipython==4.2.0 ipython-genutils==0.1.0 pingpp==2.0.11 pycrypto==2.6.1 qiniu==7.0.7 redis==2.10.5 requests==2.10.0 tornado==4.3 MySQL-python==1.2.5 SQLAlchemy==1.0.14
5.spider环境安装 在spider_py2虚拟环境中安装: attrs==16.0.0 backports-abc==0.4 backports.ssl-match-hostname==3.5.0.1 BeautifulSoup==3.2.1 beautifulsoup4==4.4.1 boto==2.38.0 certifi==2016.2.28 cffi==1.7.0 chardet==2.3.0 CherryPy==3.5.0 click==6.6 cryptography==1.4 cssselect==0.9.2 cssutils==1.0 Cython==0.24 decorator==4.0.6 Django==1.8.7 dnspython==1.12.0 easydict==1.6 enum34==1.1.6 feedparser==5.1.3 greenlet==0.4.10 html5lib==0.999 idna==2.1 ipaddress==1.0.16 ipython==2.4.1 jieba==0.38 jsonpath==0.54 lxml==3.5.0 Markdown==2.6.6 mechanize==0.2.5 motor==0.2 motorengine==0.9.0 mysqlclient==1.3.7 ndg-httpsclient==0.4.0 netifaces==0.10.4 nltk==3.2.1 parsel==1.0.2 pbr==1.9.1 pexpect==4.0.1 Pillow==3.3.0 pip==8.1.2 pkg-resources==0.0.0 poster==0.8.1 ptyprocess==0.5 pyasn1==0.1.9 pyasn1-modules==0.0.8 pybloomfilter==1.0 pybloomfiltermmap==0.3.12 pycparser==2.14 pycrypto==2.6.1 PyDispatcher==2.0.5 Pygments==2.1 pymongo==2.7 pyOpenSSL==16.0.0 python-dateutil==2.4.2 pytz==2014.10 PyYAML==3.11 queuelib==1.4.2 redis==2.10.5 repoze.lru==0.6 requests==2.10.0 Routes==2.2 rq==0.6.0 Scrapy==1.1.0 scrapy-redis==0.6.3 scrapyd==1.1.0 scrapyd-client==1.0.1 selenium==2.53.6 service-identity==16.0.0 setuptools==25.1.0 simplegeneric==0.8.1 singledispatch==3.4.0.3 six==1.10.0 sqlparse==0.1.18 stevedore==1.13.0 tornado==4.3 Twisted==16.2.0 urllib3==1.13.1 w3lib==1.14.2 WebOb==1.5.1 wheel==0.29.0 zope.interface==4.2.0
编译C语言代码(基于Vim编辑器)
vi 1.c i插入代码 上下左右还是可以使用HJKL或者up down left right(建议使用HJKL) 写完保存退出ESC+:x gcc 1.c编译 会生成a.out文件 运行a.out文件命令:./a.out
python3支持中文编码,python2不支持中文编码 要解决python2不支持中文编码的操作为: # -*- coding=utf-8 -*-
特别注意: python2中input的意思是把交互式输入的东西当成代码去执行,而python3中默认当作字符串去输入 而如果要让python2中输入的东西当作字符串,我们需要用到raw_input()
比如a=input("请输入你的名字:") 请输入你的名字:laowang python2中会报错,python3则不会 请输入你的名字:1+2 print(a) python2中打印结果为3 python3中打印结果为'1+2' 而python2中要实现打印字符串,用raw_input函数 a=raw_input("请输入你的名字:") 请输入你的名字:1+2 print(a) '1+2'
由于在python3中默认input类型为字符串类型,如果我们需要获取int类型,我们需要设置一个变量去存储字符串类型 例如age_num=int(age)
变量名不能使用关键字
import keyword keyword.kwlist 显示当前版本的所有关键字
print("%d%s%f"%(a,b,c))
不等于在python2和python3中通用写法是!= 但是在python2中还有一种写法是<>,这个意思也是表示不等于
vi编辑代码的时候,如果之前有定义的变量,敲完该变量的一部分,再敲上Ctrl+n自动补全
if not (条件): print(xxx) 意思是不在条件范围内 if not (x>0 and x<50): print("hello")
逻辑运算符: and 且 or 或 not 非
if 条件1: print(a) elif 条件2: print(aa) ...... else: print(aaa)
while 条件: a=b+c print(c) 打印不换行:print("xxx(打印信息)",end="") 打印换行:print("")
复合赋值运算符: += -= *= /= %= **= //= 而不能使用j++之类的,这是错误的语法,只能写成j+=1
在进行复合赋值运算时,=后面的数字不管进行什么运算,切记加上小括号
举个例子: a=2 a*=3+2 答案是10,计算方式是a=a*(3+2)=2*5=10,而并不是a=2*3+2=8
import random random.randint(0,2) 意思是导入一个random的库,random.randint(0,2)意思是随机生成0-2中的整数
切片: name[2:6] 取的是从第二个位置开始(下标从0开始),到小于第六个位置为止(第五个位置)
name[2:] 取的是从第二个位置开始(下标从0开始),取到最后一个
name[2:-1:2] 取的是从第二个位置开始(下标从0开始),取到最后一个的前面一个,步长为2,就是每两个位置取一个
切片:[起始位置:终止位置:步长](针对字符串而言)
起始位置取大于等于号,终止位置取小于号
步长可以为负数
步长为负数时是倒着取值,反向,相当于取逆序数
find函数,意思是找到我们需要的字符串的首字符的下标,找不到输出-1
str="hello world" str.find("world") >>6 str.find("Hello") >>-1
index函数 和find查找函数一样 找到了返回 只不过find没找到返回-1 index没有找到直接返回异常
rindex 返回子字符串 str 在字符串中最后出现的位置 如果没有匹配的字符串会报异常
rfind 返回字符串最后一次出现的位置,如果没有匹配项则返回-1
count 用于统计字符串里某个字符出现的次数。可选参数为在字符串搜索的开始与结束位置。
replace 把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次。
split 通过指定分隔符对字符串进行切片,如果参数num 有指定值,则仅分隔 num 个子字符串 str.split(str="", num=string.count(str)). str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等 num -- 分割次数
str = "Line1-abcdef \nLine2-abc \nLine4-abcd"; print str.split( ); >>['Line1-abcdef', 'Line2-abc', 'Line4-abcd']
capitalize 将字符串的第一个字母变成大写,其他字母变小写。对于 8 位字节编码需要根据本地环境。
s = ' a, B' # a 前面有空格 s.capitalize() >>' a, b'
title 所有单词都是以大写开始,其余字母均为小写 str.title()
startswith 用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False。如果参数 beg 和 end 指定值,则在指定范围内检查。
endswith 用于判断字符串是否以指定后缀结尾,如果以指定后缀结尾返回True,否则返回False。可选参数"start"与"end"为检索字符串的开始与结束位置。
lower 转换字符串中所有大写字符为小写 str.lower()
upper 将字符串中的小写字母转为大写字母 str.upper()
rjust 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串。如果指定的长度小于字符串的长度则返回原字符串。
ljust 返回一个原字符串左对齐,并使用空格填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串。
center 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串。默认填充字符为空格。
lstrip 用于截掉字符串左边的空格或指定字符
rstrip 删除 string 字符串末尾的指定字符(默认为空格)
strip 用于移除字符串头尾指定的字符(默认为空格)
partition 用来根据指定的分隔符将字符串进行分割。
rpartition 从后往前查找,返回包含字符串中分隔符之前、分隔符、分隔符之后的子字符串的tuple;如果没找到分隔符,返回字符串和两个空字符串
splitlines 字符串以换行符为分隔符拆分,去掉换行符;如果keepends为True,保留换行符
isalpha 检测字符串是否只由字母组成
isdigit 检测字符串是否只由数字组成
join 用于将序列中的元素以指定的字符连接生成一个新的字符串
str = "-"; seq = ("a", "b", "c"); # 字符串序列 print str.join( seq ); >>a-b-c
append 用于在列表末尾添加新的对象 如果添加的对象是列表 则会整体添加 list.append(obj)
ps: a=[1,2] b=[3,4] a.extend(b) >>[1,2,3,4] a.append(b) >>[1,2,[3,4]]
insert 用于将指定对象插入列表的指定位置
list.insert(index, obj)
extend 用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list.extend(seq)
pop 用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 删除最后一个 list.pop(obj=list[-1])
remove 用于移除列表中某个值的第一个匹配项 根据内容来删除
list.remove(obj)
del xxx[下标] 根据下标来删除
in 操作符用于判断键是否存在于列表/字典中,如果键在列表/字典里返回true,否则返回false
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。
字典通过键来查找
info={键1:值1,键2:值2,......}
添加
xxx[新的key] = value
删除
del xxx[key]
修改
xxx[已存在的key] = new_value
查询
xxxx.get(key)
for...else结构:
如果for循环里面有break,不触发else 如果for循环里面没有break 一定会触发else
append 注意点: a=[1,2] b=[3,4]
a=a.append(b) 进行这一步操作后,a的值为None了
原因是进行a.append(b)操作后,b的值已经添加到a里面去了 结果已经发生变化了 但是我们单独敲a.append(b)这句话时, 并没有任何输出 这就说明a.append(b)这步操作的值为空 a.append(b)整体结果为没有 没有输出就没有结果 反而你把这个传入a a的值只能保存为空 即为None
在python2中
keys 以列表返回一个字典所有的键
ps:dict.keys()
values 以列表返回字典中的所有值
ps:dict.values()
items 以列表返回可遍历的(键, 值) 元组数组
ps:dict.items()
而python3中
会返回一个生成器 一个对象 内容是列表的形式
example:
在python2中: info={"name":"laowang","age":18} info.keys() >>['name','age']
而在python3中 info={"name":"laowang","age":18} info.keys() >>dict_keys(['name','age'])
拆包
举个例子就知道了: 下面是元组拆包 a=(11,22) c,d=a c >>11 d >>22
在items中取值时,两种取值方式 一种是用数组下标 一种是元组拆包
举个例子: info={"name":"laowang","age":18} for temp in info.items(): print("key=%s,value=%s"%(temp[0],temp[1]))
info={"name":"laowang","age":18} for A,B in info.items(): print("key=%s,value=%s"%(A,B))
以上两种方式得出的结果相同
元组:(小括号)
字典:很多信息描述一个物体(大括号) 列表:存储不同物体的相同信息(中括号)
元组类型的数据不能修改里面的值,相当于一个只读文件 而列表可以修改值
函数: def 函数名: ...
一个函数想要返回多个数值,可以将其打包成元组或者列表
return a,b,c 相当于封装成元组返回
写代码规范: 写函数时,先写结构,再去考虑里面内容
代码能够重复使用
全局变量与局部变量注意点:
1.如果全局变量中定义了某个量 如果还想在函数中对这个变量进行修改的话 在函数中使用global对全局变量进行一个声明 那么这个函数中的变量就不是定义一个局部变量 而是对全局变量进行修改
2.全局变量定义得放在函数调用之前
#注释会被忽略 文档字符串(doctoring)"""XXX"""可以被调用(不影响程序的执行)
def main 完成对整个程序的控制 main函数需要定义
main()调用主函数
python代码一般格式: # -*-coding=utf-8-*- import xxx def xxx(aa): ... xxx(aa)
列表 字典的注意事项:
如果列表 字典当作全局变量 可以不需要在函数中定义global,加了也没事 但是单纯的变量在函数中一定需要加上global
缺省参数:在函数中传入默认值 在调用函数时可以不传入那个变量值 那个参数称为缺省参数
example: def test(a,b=22): result = a+b print("result=%d"%result) test(11) test(22,33) test(44)
>>33 >>55 >>66
而像test(11,b=22) b=22为命名参数
不定长参数
如果我们需要调用一个传入任意个参数的函数 怎么办呢 我们这时候采用传入*args 函数的形参 告诉python解释器 传入的实参个数如果大于形参真正的个数 剩下的统统扔给args 比如我们有10个苹果要分给三个人 有个人是你的亲属 需要你照顾他 每个人发完一个后 剩余的都给需要照顾的人
输出的结果为元组
example: def sum(a,b,*args): print(a) print(b) print(args)
sum(1,2,3,4,5,6,7,8) >>1 >>2 >>(3,4,5,6,7,8)
对于上面这个例子 如果传入的实参只有2个 也不会错 args的值为空 输出的时候会输出一个()(空的元组)
**kwargs 以字典的形式保存 输出结果为字典形式
多余参数不带变量名的 统统给args 多余参数带变量名的 统统给kwargs
def sum(a,b,*args,**kwargs): print(a) print(b) print(args) print(kwargs)
sum(1,2,3,4,5,6,task=88,done=78)
1 2 (3, 4, 5, 6) {'task': 88, 'done': 78}
拆包:
就是在实参上加上*/** 把一个列表/字典拆成一个一个值 元组/列表拆成一个一个元素 字典拆成 key value 这个过程就是拆包
用法:如下例子
def sum(a,b,*args,**kwargs): print(a) print(b) print(args) print(kwargs)
A=(44,55,66)/[44,55,66]
B={"name":"laowang","age":18}
sum(11,22,*A,**B) 在实参上写了*/** 意思是拆包
>> 11 22 (44, 55, 66) {'name': 'laowang', 'age': 18}
id 用于获取对象的内存地址 id([object])
a=1 意思并不是说定义了一个变量 而是贴了个标签,这个标签是内存地址
b=a 这个意思也是把a的内存地址给b 所以id查看会发现a,b的内存地址相同
而C语言不是 C语言是定义变量 只是值相等 地址不同
只要a的值改变了 b的值也会改变
python有自动回收垃圾机制
数字是不可变类型 字符串也是不可变类型 元组也是个不可变类型
举个例子 a="hello" a[0] >>'h' a[0]='H' 报错。。。
说明字符串不允许修改
列表和字典属于可变类型 在定义时不允许当key用
infors.sort(key=lambda x:x['name'])
匿名函数 lambda
eval 用来执行一个字符串表达式,并返回表达式的值
eval(expression[, globals[, locals]])
交换两个数
a=a+b b=a-b a=a-b
任何语言都适用
a,b=b,a python独特写法 两数交换
列表加上列表 等于 列表的合并
误区:
python里面不是值赋值,而是引用赋值
例子:
num+=num与num=num+num的区别
由于python里面时引用赋值 假设num=100传入一个求解两个数的和的函数
num+=num 传入的实参num指向100这个值
所以做修改时直接修改的是num本身的值
修改的是全局变量
而num = num + num 传入参数时 num定义的是临时变量
此时num指向的是100+100=200
文件的读入
f = oepn("test.py","r") 意味着通过open打开文件 用f进行操作文件的读写
r 文件必须存在 w 文件如果不存在 就创建新文件 a 打开一个文件 从文件的末尾写
rb wb ab 有b结尾说明是二进制文件
文本文件与二进制文件区别
r+ w+ a+ +表示你可以读写文件
rb+ wb+ ab+
open默认以读入的方式打开 所以可以不写"r"
seek 用于移动文件读取指针到指定位置
fileObject.seek(offset[, whence])
f.seek(2,0) 0表示文件的开头 2表示跳过开头两个位置开始读
如果我已经读完了一个文件 想要重新读取该文件
我们应该用f.seek(0,0)拉回来 让该文件还能调用f.read()重新读取
f.tell() 返回文件的当前位置,即文件指针当前位置
fileObject.tell(offset[, whence])
open 支持相对路径和绝对路径
面向过程 考虑要面面俱到 强调的是过程 而面向对象则不需要 找个有这样能力的人去做 强调的是对象
形象的解释 对象 看的见摸得着 实实在在的东西
类是模型 一个概念
类由三部分组成
类的名称:类名
类的属性:一组数据
类的方法:允许对进行操作的方法(行为)
比如:
类名:Tank 属性:重量 速度 材料 方法:开炮 移动 转弯
在类中定义方法的时候参数位置要写上self
执行 Cat() 在内存中申请了空间 返回对象的引用
而执行 tom = Cat() tom是创建的对象的引用
指向那个对象
添加属性
tom.name="xxx" 给tom添加属性name
tom.age=xx 给tom添加属性age
例子:
类Cat
tom=Cat()
tom.调用方法
tom.添加属性
class Cat: #属性
#方法 def eat(self): print("猫在吃鱼....")
def drink(self): print("猫正在喝kele.....")
def introduce(self): #print("%s的年龄是:%d"%(tom.name, tom.age)) print("%s的年龄是:%d"%(self.name, self.age))
#创建一个对象 tom = Cat()
#调用tom指向的对象中的 方法 tom.eat() tom.drink()
#给tom指向的对象添加2个属性 tom.name = "汤姆" tom.age = 40
#获取属性的第1种方式 #print("%s的年龄是:%d"%(tom.name, tom.age))
tom.introduce()#相当于 tom.introduce(tom)
lanmao = Cat() lanmao.name = "蓝猫" lanmao.age = 10 lanmao.introduce()
self的作用: 你通过哪个对象去调用方法 self就指向哪个对象
tom.introduce() 相当于tom.introduce(tom)
而如果class中函数的形参不写入self 直接调用tom.introduce()
结果会显示多传入了一个参数 这个就是原因所在
还有 不一定要传入形参的时候传self a b c等任何数都行 只是我们约定俗成 用self
魔法方法1:__init__
方法:初始化对象 def __init__(self): pass 初始化对象
创建对象的过程: 1.创建一个对象 2.python会自动的调用__init__方法 3.返回创建的对象的引用给tom
__init__也称为魔法方法
class Cat: """定义了一个Cat类"""
#初始化对象 def __init__(self, new_name, new_age): self.name = new_name self.age = new_age
#方法 def eat(self): print("猫在吃鱼....")
def drink(self): print("猫正在喝kele.....")
def introduce(self): print("%s的年龄是:%d"%(self.name, self.age))
#创建一个对象 tom = Cat("汤姆", 40) tom.eat() tom.drink() #tom.name = "汤姆" #tom.age = 40 tom.introduce()
lanmao = Cat("蓝猫", 10) #lanmao.name = "蓝猫" #lanmao.age = 10 lanmao.introduce()
1.创建对象 name = "汤姆" age = 40
2.调用__init__方法 3.返回这个对象的引用
1.创建对象 name = "蓝猫" age = 10 2.调用__init__方法 3.返回这个对象的引用
魔法方法2:__str__
用来获取对象描述信息
def __self__(self): return xxx
print(tom)
打印出xxx(调用tom的信息)
class Cat: """定义了一个Cat类"""
#初始化对象 def __init__(self, new_name, new_age): self.name = new_name self.age = new_age
def __str__(self): return "%s的年龄是:%d"%(self.name, self.age)
#方法 def eat(self): print("猫在吃鱼....")
def drink(self): print("猫正在喝kele.....")
def introduce(self): print("%s的年龄是:%d"%(self.name, self.age))
#创建一个对象 tom = Cat("汤姆", 40)
lanmao = Cat("蓝猫", 10)
print(tom) print(lanmao)
打印结果为: 汤姆的年龄是40 蓝猫的年龄是10
通过全局变量 通过属性 来进行数据的共享
把函数的功能封装起来
def __test(self): pass
这种方式是方法私有化
del不是真正删除了 而是删除了引用
def __del__(self): pass
python解释器调用
class Dog: def __del__(self): print("-----英雄over------")
dog1 = Dog() dog2 = dog1
del dog1#不会调用 __del__方法,因为这个对象 还有其他的变量指向它,即 引用计算不是0 del dog2#此时会调用__del__方法,因为没有变量指向它了 print("====================")
#如果在程序结束时,有些对象还存在,那么python解释器会自动调用它们的__del__方法来完成清理工作
测量一个对象引用的计数方式:
使用sys模块中的getrefcount函数
import sys class T: pass
t = T()
sys.getrefcount(t) >>2
tt = t sys.getrefcount(tt) >>3
del tt sys.getrefcount(t) >>2
父类/基类
继承
子类/派生类
我们定义了一个Animal类 父类/基类
下面有个Dog Cat的子类
Dog下面定义了一个wangcai的方法 tom的方法
wangcai只能使用Dog Animal类中的方法 tom只能使用Cat Animal类中的方法
不允许出现tom使用Dog中的方法 或者是wangcai使用Cat中的方法
重写 在子类中重写父类的方法
调用的时候只会调用子类的方法
super().bark()
super调用被重写的父类的方法
私有方法 私有的属性并不会被继承
如果调用的是继承的父类中的共有方法 可以在这个公有方法中访问父类中的私有属性和私有方法
但是如果在子类中实现了一个公有方法 那么这个方法是不能够调用继承的父类中的私有方法
class Base(object): pass
class Base(object): def test(self): print("----Base")
class A(Base): def test(self): print("-----A")
class B(Base): def test(self): print("-----B")
class C(A,B): pass #def test(self): # print("-----C")
c = C() c.test()
print(C.__mro__)
类名.__mro__ 决定调用一个方法的时候 搜索的顺序 如果在某个类中找到了方法 那么就停止搜索
定义的时候对象不确定 调用的时候确定对象 这个方法叫多态
python既支持面向过程 也支持面向对象
python面向对象的三个基本要素是 封装 继承 多态
一个特殊的属性 能够知道这个对象的class
类在程序里面也是一个对象 称为类对象
由类创建出的对象为实例对象
实例对象的属性为实例属性 实例属性和对象有关系
类对象中的属性为类属性 类属性和类有关系
类属性是共享的
实例属性:和具体的某个实例对象有关系 并且 一个实例对象和另外一个实例对象是不共享属性的
类属性:类属性所属于类对象 并且多个实例对象之间共享同一个 类属性
class Tool(object):
#类属性 num = 0
#方法 def __init__(self, new_name): #实例属性 self.name = new_name #对类属性+=1 Tool.num += 1
tool1 = Tool("铁锹") tool2 = Tool("工兵铲") tool3 = Tool("水桶")
print(Tool.num)
实例方法 类方法 静态方法
class Game(object):
#类属性 num = 0
#实例方法 def __init__(self): #实例属性 self.name = "laowang"
#类方法 @classmethod def add_num(cls): cls.num = 100
#静态方法 @staticmethod def print_menu(): print("----------------------") print(" 穿越火线V11.1") print(" 1. 开始游戏") print(" 2. 结束游戏") print("----------------------")
game = Game() #Game.add_num()#可以通过类的名字调用类方法 game.add_num()#还可以通过这个类创建出来的对象 去调用这个类方法 print(Game.num)
#Game.print_menu()#通过类 去调用静态方法 game.print_menu()#通过实例对象 去调用静态方法
@classmethod 装饰器 固定写法
通过一个类进行分离解耦
在父类中不去实现 在子类中实现
这就是工厂方法模式
def __new__(cls): pass
当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径
class Dog(object): def __init__(self): print("----init方法-----")
def __del__(self): print("----del方法-----")
def __str__(self): print("----str方法-----") return "对象的描述信息"
def __new__(cls):#cls此时是Dog指向的那个类对象
#print(id(cls))
print("----new方法-----") return object.__new__(cls)
#print(id(Dog))
xtq = Dog()
1.创建一个对象 2.调用__init__方法 3.返回对象的引用
而__new__方法就是重写父类的new方法
1.调用__new__方法来创建对象,然后找了个变量来接受__new__返回值,这个返回值表示 创建出来的对象的引用
2.__init__(刚刚创建出来的对象的引用) 初始化
3.返回对象的引用
而构造方法是既创建对象 又初始化 和__init__方法不等价
__new__只负责创建对象 __init__只负责初始化
class Dog(object):
__instance = None
def __new__(cls): if cls.__instance == None: cls.__instance = object.__new__(cls) return cls.__instance else: #return 上一次创建的对象的引用 return cls.__instance
a = Dog() print(id(a)) b = Dog() print(id(b))
class Dog(object):
__instance = None __init_flag = False
def __new__(cls, name): if cls.__instance == None: cls.__instance = object.__new__(cls) return cls.__instance else: #return 上一次创建的对象的引用 return cls.__instance
def __init__(self, name): if Dog.__init_flag == False: self.name = name Dog.__init_flag = True
a = Dog("旺财") print(id(a)) print(a.name)
b = Dog("哮天犬") print(id(b)) print(b.name)
异常处理:
try:
except 出现异常的名字:
try: print(num) except NameError: print(111)
Exception
如果用了Exception,那么意味着只要上面的except没有捕获到异常 这个except一定会捕获到
Exception 不管产生什么异常 都会捕获到 就不需要去写许多异常了 异常方面很多
as 预处理方案 会给出产生该异常的原因
#coding=utf-8
try: num = input("xxx:") int(num) #11/0 #open("xxx.txt") #print(num) print("-----1----")
except (NameError,FileNotFoundError): print("如果捕获到异常后做的 处理....") except Exception as ret: print("如果用了Exception,那么意味着只要上面的except没有捕获到异常,这个except一定会捕获到") print(ret) else: print("没有异常才会执行的功能") finally: print("------finally-----")
print("-----2----")
Ctrl + C也是一个异常
自定义异常类
raise引发一个自定义的异常
log日志 会记录发生的异常
*.py文件就是模块
.pyc 字节码的后缀 翻译后的python代码
from 模块名 import 功能名1,功能名2,.....从模块中导入功能1,功能2,等等
from 模块名 import * 从模块中导入所有功能
这种方式缺陷:如果导入的模块的功能名相同 后面导入的会覆盖前面导入的
import msg msg.text1()
通过模块名.功能名调用
import time as tt 导入time模块 给它取个名字 叫tt tt.sleep(3)
不取和模块名相同的名字
import xxx
class ClassName(object): def __init__(self,arg): pass
def xxx(): pass
def main(): pass
if __name == '__main__': main()
__all__ = ["功能名1","功能名2",...../或者类名也行]
定义的作用:放上将来你想要用的功能/类名,如果没放进去 调用import仍不能用
把模块有关联的放在一个文件夹中
在python2中调用文件夹名会直接失败 在python3中调用会成功,但是调用不能成功
解决办法是:
在该文件夹下加入空文件__init__.py python2会把该文件夹整体当成一个包
然后编辑__init__.py
加入__all__ = ["功能名1","功能名2",...../或者类名也行]
再通过from 模块名 import * 通用写法是:from . import 模块名
这样就可以调用包中那些模块功能了
#如果导入这个模块的方式是 from 模块名 import * ,那么仅仅会导入__all__的列表中包含的名字
setup.py
from distutils.core import setup
setup(name="dongGe", version="1.0", description="dongGe's module", author="dongGe", py_modules=['TestMsg.sendmsg', 'TestMsg.recvmsg'])
模块的发布过程: 1.创建文件setup.py 传入模块.功能 2.python3 setup.py build 3.python3 setup.py dist 4.生成压缩包,然后可以发布到github.com上
系统安装包 sudo python3 setup.py install
python2中range(10)返回值是一个列表[0,...,9] 而在python3中返回值是range(0,10)
range(0,10)在python2中返回是一个列表[0,...,9] 而在python3中返回值是range(0,10)
range有风险 如果将来你需要一个很大的值 因为需要占用很大的空间 所以不给你
如果python3中想要返回值是一个列表
使用a = [i for i in range(1,18)] 这样可以返回一个列表
在python2中这种写法也适合
(参数1,参数2,参数3,.....) for 参数1 in range(第1个数) for 参数2 in range(第2个数) 。。。。。。。
set 字典
list 列表
while True: 1.检测事件,如果有时间就控制相应的图片移动 2.把所有的图片重新画一遍
1/60s --> 动画效果
列表循环删除的时候不能删除循环的那个列表 我们可以申请一个新的列表去存