1. 函数
我们在编程过程中,总是会遇到一些相似的,重复的代码段,而重复的代码段是一个程序员在编程的时候尽量避免的,所以我们可以将重复的代码定义为一个函数来精简你的代码,从而函提高应用的模块性和代码的重复利用率。
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
def f(a,b)
f()
#a和b都是默认值
f(1)
#a为0,b为默认值
def f(*args):
total =0
for val in args:
total += val
return total
mylist = [1,3,,4,10]
print(f(*mylist)#如果不加*,就会将mylist当做一个元素传入函数,会是数值和字符串的运算。
注意代码块后面的函数将会覆盖前面的与其相同名字的函数
作用域 - LEGB:
局部作用域–>嵌套作用域(下级可以使用上级的值)–>全局作用域–>内置作用域,值的搜索范围是从内而外的,这个优先顺序同样也适用于变量的使用。
a = 100#全局a
def f()
global a#读取去全局的a
a = 200#若果全局没有a,则定义全局a
b = 'hello'
def g():
nonlocal(b)#读取上级嵌套非全局a
b = 'good'
迪米特法则:最少知道原则,尽量减少全局变量的使用。
在调用内存时,之前的代码会保存现场在栈再去调用函数,调用函数之后才会恢复现场
函数也可以直接或间接调用自己,称为递归调用
#函数的递归调用
def gcd(x,y):
if x > y:
return gcd(y,x)
elif y % x == 0:
return x
else:
return gcd( y % x,x)
if __name__ == '__main__':
print(gcd(21,49))
收敛条件:让递归在有限的次数完成或者进行回溯
2.模块
- 常见内置模块主要有random、math、time、os等等
- 调用模块主要通过from、import和as
- 一个模块尽量放与其相关的函数
- 一个模块中的函数可以被另一个模块调用,需要在模块后面加
- if _ name _ == ‘main‘:否则另一个模块执行被调用模块中的变量
3.内存管理
- 内存简单分为:栈,堆,静态区
- 引用:对象包含字符串、数值、列表等等,保存在堆空间,并将地址映射到栈中,而变量就是引用栈中对象保存在堆空间的地址,从而调用对象。
值得注意的是如果使用list1 = [0]*10的形式,那么list1只是将栈中[0]的引用地址复制了十份,在对[o]进行添加元素时只会得到一个list1。
通过调用id()函数可以看到对象在内存中的位置,调用sys.getsizeof()函数可以查看对象占用了多少空间
list1 = [0]*10
list2 = list1
ilst1和list2保存在栈中而[0]*10保存在堆空间中
f = list(range(10))
#f申请一块内存
print(list{x for x in range(10)
#如果没有使用上面申请的空间,python将会将这个对象当做垃圾回收,如果不这样做内存空间将会泄漏,会导致程序闪退。
import sys
list1 = [0]*10
list2 = list1
list3 = list2
print(sys.getrefcount(list1))#显示对象的引用计数,实际值比显示值小1
4.对象类别
无论是在计算机环境还是显示生活中,我们可以把世界认为是由对象构成的,在现实生活中无论动物、植物、微生物或是其他的类别,其中每一个单体都可以认为是一个对象。在计算机环境中也是一样,对象组成了计算机环境。其中主要分为以下几类:
4.1字符串
字符串是Python实际应用中非常常见的一种对象类型,一般字符串是用‘’或者“”来创建,不过字符串的引号使用是不能混搭的。
如:
print("i want to learn 'Python',and you?")#单引号和双引号必须分别对应
字符串的运算方式如下表:
a = ‘hello’
b = ‘world’
header 1 | header 2 | header 1 |
---|---|---|
+ | 字符串连接 | print(a +b) ‘hellohello’ |
* | 重复输出字符串 | a *2 ‘hellohello’ |
[] | 通过索引获取字符串中字符 | a[1] e |
[:] | 获取字符串中的一部分 | a[1:4] ’ell’ |
in | 成员运算符-如果字符串中包含给定的字符串返回 True | ‘h’ in a True |
not in | 成员运算符 - 如果字符串中不包含给定的字符返回 True | “M” not in a True |
4.2列表
定义列表主要有以下两种方法:
1. 列表生成式
mylist = [x**2 for x in range(1,10)]
#用列表的生成表达式语法创建列表容器
#用这种语法创建列表之后元素已经准备就绪,所以需要耗费较多的内存空间
- 列表生成器
f = (x ** x for x in range(1,10))
print(f)
for val in f:
print(val)
列表生成器,这里得到的不是一个列表,通过生成器可以获取到数据,它不占用额外的空间存储数据,每次需要数据的时候就通过生成器获取数据,当然这需要额外花费时间。
#斐波拉切数列
def fib(n):
a,b = 0,1
for _ in range(n)
a,b = b,a+b
yield a
#yield表示将函数变成生成器
for val in fib(20):
print(val)
结果如下:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
- 添加和插入对象:
f.append(11)
f.insert(0,2)
mylist = mylist + [20,87]
- 删除列表中的对象:
del f()
f.index(50,2,5)#查找元素位置,括号是闭区间,如果这里的index值大于len(f),将在列表最后插入对象
f.pop()#找到列表中的值,并将它他列表中删除,默认是最后一个
f.remove()#表示移除一个元素
f.clear()#表示清理所有元素
- 访问列表:
miylist[0]、mylist()
- 切片:
[a:b:c]#a代表从多少位开始,b代表从多少位结束,c代表步长
- 排序:
mylist.sort()
f1 = f[::-1]#对列表反转
f.reverse#反转f,将会改变f
f1 = reversed(f)#不会改变f的反转将会改变mylist列表
mylist1 = mylist.sorted(reserve = True)
#按首字母排序,默认是升序,降序可以通过reverse,新建一个容器来装纳新的数值顺序
4.3元组
- Python的元组与列表类似,不同之处在于元组的元素不能修改。
- 元组使用小括号,列表使用方括号。
- 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。
#选出一串数字的最大值和第二大的值
def second_max(x):
(m1,m2) = (x[0],x[1]) if x[0] > x[1] else (x[1],x[0])
for index in range(2,len(x)):
if x[index] > m1:
m2 = m1
m1 = x[index]
elif x[index] > m2:
m2 = x[index]
return m1,m2
#元组
if __name__ == '__main__':
print(second_max([92,32,21,100,22]))
元组与列表最大的区别在于:元组中的对象不能被更改,但我们可以使用del语句来删除整个元组。另外,元组的创建时间比列表要短,
4.4集合
- 相较于列表和元组是一种无顺序的的容器,形如:set1 = {1,2,4,5,6,2,3}
- 集合不允许出现相同的值,会自动删除多余的相同值
- 集合不支持下标运算
set1 = {1,2,4,5,6,2,3}
set1.add(9)
print(set1)
set2 = {2,4,6,7,8}
print(f2)
set3 = set1 & set2求交集
print(set3)
set3 = set1 - set2
print(set3)
set3 = set1 | set2#求并集
print(set3)
运行结果:
{1, 2, 3, 4, 5, 6, 9}
{2, 4, 6, 7, 8}
{2, 4, 6}
{1, 3, 5, 9}
{1, 2, 3, 4, 5, 6, 7, 8, 9}
4.5字典
- 字典是另一种可变容器模型,且可存储任意类型对象(列表,元组,集合)。
- 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:
dic = {key1 : value1, key2 : value2 }
字典有以下特征:
- 键必须是唯一的,但值则不必。
- 值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。
在访问字典中的值时:
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'};
print "dict['Name']: ", dict['Name'];
print "dict['Age']: ", dict['Age'];
也可以对字典中的对象进行删除和修改操作:
dict = {'name':'xiangxianzhang','age':22,'class':'Python'}
dict['age'] = 23#将age键的值修改为23
del dict['age']#删除键是age的对象
print(dict)
结果显示:
{'name': 'xiangxianzhang', 'age': 23, 'class': 'Python'}
{'name': 'xiangxianzhang', 'class': 'Python'}
字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的,但键不行。
两个重要的点需要记住:
- 不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住。
- 键必须不可变,所以可以用数字,字符串或元组充当,所以不能用列表来充当键。
最后举一个列子:
dictionary = {}
flag = 'a'
pape = 'a'
off = 'a'
while flag == 'a' or 'c':
flag = input("添加或查找单词 ?(a/c)")
if flag == "a" : # 选择添加单词
word = input("输入单词(key):")
defintion = input("输入定义值(value):")
dictionary[str(word)] = str(defintion) # 添加到字典
print("添加成功!")
pape = input("您是否要查找字典?(a/0)")
if pape == 'a': #选择查找字典
print(dictionary)
else :
continue
elif flag == 'c':
check_word = input("要查找的单词:") # 检索
for key in sorted(dictionary.keys()): # yes
if str(check_word) == key:
print("该单词存在! " ,key, dictionary[key])
break
else: # no
off = 'b'
print("抱歉,该值不存在!")
else: # 停止
print("error type")
break
结果将显示为:
输入单词(key):my_name
输入定义值(value):xiangxianzhang
添加成功!
您是否要查找字典?(a/0)0
添加或查找单词 ?(a/c)c
要查找的单词:my_name
该单词存在! my_name xiangxianzhang
添加或查找单词 ?(a/c)
5.面向对象
在实际开发应用中,我们不可能把每个代码指令都发给对象来执行,因为那样做非常浪费时间和内存,在以前的软件行业中这都是一个无法避免的问题,直到面向对象这个编程思想的出现。
通常来说面向对象的实际操作流程主要分为三步;
定义一个类,给对象绑定属性。类是对象的蓝图和模板,有了类就可以创建对象,定义类需要做两件事:分析其数据抽象和行为抽象
- 数据抽象————抽象数据共同的静态特征(找名词)——属性
- 行为抽象————抽取对象共同的动态特征(找动词)——方法
定义类的关键字——class——类名(每个单词首字母大写)。
class Student(object):
#构造方法 --construtor
#调用该方法的时候,不是直接使用方法的名字而是使用类的名字
def __init__(self, name , age):
#给对象绑定属性,第一步
self.name = name
self.age = age
#我们定义一个方法就代表了对象可以接受这个消息
#对象方法的第一个参数同意写成self
#它代表了接收消息的对象
def study(self,course):
print('%s正在学习%s' % (self.name,course))
def watch_av(self):
if self.age >= 18:
print('%s正在观看爱情动作片' % self.name)
else:
print('%s,我们推荐你看喜洋洋' % self.name)
#调用构造方法创建学生对象,第二步
#实际上调用的是构造方法
def main():
stu1 = Student('xxz',22)
stu1.study('python')
#第三步,给对象发消息
#通过给对象发消息,让对象完成某些工作就可以实现某些工作
#解决任何问题都是通过让对象去做事情
stu2 = Student('sjy',15)
stu2.age = 22
stu2.watch_av()
if __name__ == '__main__':
main()
运行结果:
xxz正在学习python
sjy正在观看爱情动作片
#用面向对象的方法来编写一个计时器
import time
class Clock(object):
def __init__(self,hour=0,min=0,sec=0):
self._hour = hour
self._min = min
self._sec = sec
def min(self):
self._sec -= 1
if self._sec == 60:
self._sec = 0
self._min += 1
if self._min == 60:
self._min = 0
self._hour += 1
if self._hour == 24:
self._hour = 0
#下面的方法可以获得对象的字符串表达式
#当我们用print打印对象时会自动调用该方法
def __str__(self):
return '%02d:%02d:%02d' % (self._hour,self._min,self._sec)
def main():
localtime = time.localtime(time.time())#获取系统时间
clock = Clock(localtime[3],localtime[4],localtime[5])
while True:
print(clock)
sleep(1)
clock.run()
if __name__ == '__main__':
main()
运行结果如下:
我们定义一个类实际上是吧数据和操作数据的函数绑定到一起,形成一个逻辑上的整体,这个整体就叫对象,而且将来任何时候想使用这个对象时直接复用这个类就可以了。
实践出真知,理论知识需要与实际情况相结合,接下来我举几个例子来加深对面向对象这种思想的理解。
6.练习
1.有十步台阶,一个小孩一次最多走三步台阶,问他有多少种走法?
def sum_1_to_100(n):
if n == 1:
return 1
else:
return n + sum_1_to_100(n-1)
def walk(n):
'''
:param n: 走几步台阶
:return: 有多少种走法
'''
if n < 0:
return 0
elif n == 0:
return 1
return walk(n-1) + walk(n-2) +walk(n-3)
if __name__ == '__main__':
print(walk(10))
2.机选双色球,人选注数
from random import randint
def seletcd_ball():
sum_balls = []
red_balls = [x for x in range(1,34)]
for _ in range(6):
seletcd_red_ball = red_balls[randint(0,len(red_balls)-1)]
sum_balls.append(seletcd_red_ball)
red_balls.remove(seletcd_red_ball)
sum_balls.sort()
blue_ball = randint(1,16)
sum_balls.append(blue_ball)
return sum_balls
def foo(balls):
for ball in balls:
print('%02d' % ball,end=' ')
print()
def mains():
n = int(input('下多少注:'))
for _ in range(n):
foo(seletcd_ball())
if __name__ == '__main__':
mains()
3.设计一个显示炸弹倒计时的表
import time
from time import sleep
class Clock(object):
def __init__(self,hour = 0,min = 0,sec = 0):#类下面的函数上下隔一行
self._hour = hour
self._min = min
self._sec = sec
def run(self):
self._sec -= 1
if self._sec < 0:
self._min -= 1
self._sec = 59
if self._min < 0:
self._hour -= 1
self._min = 59
if self._hour < 0:
pass
def __str__(self):
return '%02d:%02d:%02d' % (self._hour, self._min, self._sec)
def main():
clock = Clock(0, 1, 1)
while True:
print(clock)
sleep(0.00001)
clock.run()
if 0==clock._hour == clock._min == clock._sec:
print('BOOM SHAKALAKA ')
break
if __name__ == '__main__':
main()
4.在坐标轴上标出两个点,有面向对象的方法求出两点的距离,表达a点移动到b点,表达a点移动多少距离后的点?
from math import sqrt
class Point(object):
def __init__(self,x = 0,y = 0):
self._x = x
self._y = y
def distance(self,x1,y1):
return sqrt(((x1 - self._x)**2 + (y1 - self._y)**2))
def to_second_point(self,x ,y ):
self._x = x
self._y = y
def move_distance(self,dx,dy):
self._x += dx
self._y += dy
def __str__(self):
return '(%s, %s)' % (str(self._x), str(self._y))
def main():
p1 = Point(3,2)
p2 = Point()
print(p1.distance(9,6))
p1.to_second_point(9,6)
print(p1)
p1.move_distance(1,2)
print(p1)
if __name__ == '__main__':
main()