目录
-
函数
-
面向对象编程(类/子类)
-
文件读写
-
迭代器/迭代对象
-
生成器yield
函数可以简单理解成 '打包' 好的一段代码。
函数的作用主要是为了使代码可以重用。
对于一些通用的代码,放到函数里,每次使用直接调就好了。节省时间,提高效率。
Python 里的函数是什么样子的?
1
def fib(n):
2
a, b = 0, 1
3
for i in range(n):
4
print(a, end=" ")
5
a, b = b, a+b
从例子中可以看到:
- 函数是以 'def ' 开头,我们称为 关键字;后面的 'fib' 是函数的名字;紧接着的小括号,里面是函数的参数,可以通过参数从外面传一些值到函数的内部。这里的参数只有一个,我们给函数的参数也起了一个名字'n' 。
- 函数的参数可以是一个入上面的例子。也可以一个都没有,只有小括号。也可以是多个,参数之间用逗号隔开。
- 接下来的 : (冒号) 表示 函数的代码写在后面。Python的代码要求以统一的缩进开始。所以上面的函数 换行并缩进了。
- 上面的函数并没有 返回值 ,Python默认返回了None。 如果要返回确定的值要用return。
- 调用函数,直接函数名加小括号。有参数写到括号里。如:fib(10)
1
fib(10)
0 1 1 2 3 5 8 13 21 34
函数的参数可以设置 默认值/缺省参数
1
def my_sum_2(a, b=5):
2
return a+b
3
4
my_sum_2(3,10) #输出 13
5
my_sum_2(3,) # 第二个参数没有给,所以函数取默认值5。 3+8=8 输出8
python 函数的参数传递:
- 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。
比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
- 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
python 传不可变对象实例
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
def ChangeInt( a ):
5
a = 10
6
7
b = 2
8
ChangeInt(b)
9
print b # 结果是 2
实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。
传可变对象实例
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
# 可写函数说明
5
def changeme( mylist ):
6
"修改传入的列表"
7
mylist.append([1,2,3,4]);
8
print "函数内取值: ", mylist
9
return
10
11
# 调用changeme函数
12
mylist = [10,20,30];
13
changeme( mylist );
14
print "函数外取值: ", mylist
实例中传入函数的和在末尾添加新内容的对象用的是同一个引用,故输出结果如下:
1
函数内取值: [10, 20, 30, [1, 2, 3, 4]]
2
函数外取值: [10, 20, 30, [1, 2, 3, 4]]
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数。
加了星号(*)的变量名会存放所有未命名的变量参数。选择不多传参数也可。如下实例:
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
# 可写函数说明
5
def printinfo( arg1, *vartuple ):
6
print "输出: "
7
print arg1
8
for var in vartuple:
9
print var
10
return;
11
12
# 调用printinfo 函数
13
printinfo( 10 );
14
printinfo( 70, 60, 50 );
以上实例输出结果:
1
输出:
2
10
3
输出:
4
70
5
60
6
50
一个星号和两个星号:
1
def my_func(**x):
2
if len(x)==0:
3
print('None')
4
else:
5
print(x)
6
7
my_fun(b=1,c=2,d=3)
8
#输出 {'d': 3, 'c': 2, 'b': 1}
1
#两个 '*' 号
2
def my_func(x, y=1, *a, **b):
3
print(x,y,a,b)
4
my_func(1) # 输出 : 1 1 () {}
5
my_func(1,3) # 输出 : 1 3 () {}
6
my_func(1,2,3,4,5) #输出 : 1 2 (3, 4, 5) {}
7
my_func(1,2,3,4,5,tmp=6) #输出 :1 2 (3, 4, 5) {'tmp': 6}
8
9
# 可以看出来 一个星号 表示参数是一个tuple,两个星号表示参数为一个字典。
10
# 可以用type()函数来实验一下
11
12
def my_func(x, y=1, *a, **b):
13
print(type(a))
14
print(type(b))
15
print(x,y,a,b)
16
my_func(1,2,3,4,5,tmp=6)
17
# 输出 :
18
# <class 'tuple'>
19
# <class 'dict'>
20
# 1 2 (3, 4, 5) {'tmp': 6}
匿名函数/lambda
匿名函数,是一个表达式,函数体比def定义的函数简单的多。
语法:
1
lambda [arg1 [,arg2,.....argn]]:expression
如下实例:
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
# 可写函数说明
5
sum = lambda arg1, arg2: arg1 + arg2;
6
7
# 调用sum函数
8
print "相加后的值为 : ", sum( 10, 20 )
9
print "相加后的值为 : ", sum( 20, 20 )
以上实例输出结果:
1
相加后的值为 : 30
2
相加后的值为 : 40
面向对象的编程/class入门
Python通过class来定义类。类可以看做是我们自定义的一种数据结构。
Python语言自带了一些数据结构(int,float,str,list)。我们可以通过class来定义一下我们自己的类。
说起面向对象,首先一定要明白 类和实例的的概念。
类可以看做是 实例 的 '图纸'(模板)。
比如:我们盖房子的时候需要'图纸',盖房子的图纸可以就几张,但是房子却可以盖很多。
也可以看做是写文章时,脑子里想好的大纲。虽然脑子想写什么都想到了。但是终究是还没有'实现'。
这里的 实际存在的房子,动笔写好的稿子,都可以看做是类的'实例'。
等房子盖好了,稿子写好了,我们就可以说我们的 '类' 已经 '实现' 了(创建了'实例')。
关键字: 类、实例、实现
- 我们可以把int当做一个类, a = 5,a是就是一个int类型的对象(instance 实例)。int->类,=号->实现,a->一个实例,名字叫做'a'。
- Python 中的实例被统称为'对象'(object), class就是某一种对象的模板。
创建类
1
class Employee(object):
2
# python中的__init__表示初始化类。函数中的第一个参数self 是指类的实例自己(即Employee的实例),Python默认会把自己传给初始化的函数的第一个参数,定义初始化函数时一定不要忘了写self参数。
3
def __init__(self,name,ID,title,salary,manager=None):
4
self.name = name
5
self.title = title
6
self.salary = salary
7
self.manager = manager
8
def get_info(self):
9
return "Employee name:{},title:{},salary:{},manager:{}"\
10
.format(self.name, self.title, self.salary,"" if self.manager==None else self.manager)
11
12
def __eq__(self, other):
13
return self.ID == other.ID
1
# 初始化对象/实例
2
ceo = Employee('user1', 1, 'CEO', 10000000)
3
user2 = Employee('user2', 10, 'employee', 100, ceo)
1
ceo.get_info()
2
# 输出: '(Employee name:user1, title:CEO, salary:10000000, manager:)'
1
user2.get_info()
2
# 输出: 'Employee name:user2, title:CTO, salary:100, manager:<__main__.Employee object at 0x7fd7affaa940>'
1
# 定义一个类
2
class Company(object):
3
def __init__(self, name, employees=[]):
4
self.name = name
5
self.employees = employees
6
7
def hire(self, employee):
8
if not employee in self.employees:
9
self.employees.append(employee)
10
11
def fire(self, employee):
12
if employee in self.employees:
13
self.employees.remove(employee)
14
15
def get_info(self):
16
res = "Company:{}, employees:".format(self.name)
17
for employee in self.employees:
18
res += ", {}".format(employee.get_info())
19
return res
1
com = Company("com")
2
com.hire(ceo)
3
com.hire(user2)
4
com.get_info()
子类/继承
子类可以继承基类的的field、method,复用代码,也可以再基类的基础上扩展自己特有的field、method。
在python中继承中的一些特点:
- 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
- 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
- 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
语法:
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:
1
class SubClassName (ParentClass1[, ParentClass2, ...]):
2
'Optional class documentation string'
3
class_suite
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
class Parent: # 定义父类
5
parentAttr = 100
6
def __init__(self):
7
print "调用父类构造函数"
8
9
def parentMethod(self):
10
print '调用父类方法'
11
12
def setAttr(self, attr):
13
Parent.parentAttr = attr
14
15
def getAttr(self):
16
print "父类属性 :", Parent.parentAttr
17
18
class Child(Parent): # 定义子类
19
def __init__(self):
20
print "调用子类构造方法"
21
22
def childMethod(self):
23
print '调用子类方法'
24
25
c = Child() # 实例化子类
26
c.childMethod() # 调用子类的方法
27
c.parentMethod() # 调用父类方法
28
c.setAttr(200) # 再次调用父类的方法 - 设置属性值
29
c.getAttr() # 再次调用父类的方法 - 获取属性值
以上代码执行结果如下:
1
调用子类构造方法
2
调用子类方法
3
调用父类方法
4
父类属性 : 200
你可以继承多个类
1
class A: # 定义类 A
2
.....
3
4
class B: # 定义类 B
5
.....
6
7
class C(A, B): # 继承类 A 和 B
8
.....
你可以使用issubclass()或者isinstance()方法来检测。
- issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
- isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法:
实例:
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
class Parent: # 定义父类
5
def myMethod(self):
6
print '调用父类方法'
7
8
class Child(Parent): # 定义子类
9
def myMethod(self):
10
print '调用子类方法'
11
12
c = Child() # 子类实例
13
c.myMethod() # 子类调用重写方法
执行以上代码输出结果如下:
1
调用子类方法
Abstract Base class
- 抽象类不能实例化
- 抽象类中定义的抽象方法,子类必须重写。
1
from abc import ABC, abstractmethod
2
3
class Person(ABC):
4
@abstractmethod
5
def __init__(self, name, ID):
6
self.name = name
7
self.ID = ID
8
9
@abstractmethod
10
def get_info(self):
11
return "name:{}".format(self.name)
上面的Person继承了ABC。定义了两个抽象方法__init__和get_info
1
class Student(Person):
2
def __init__(self, name, ID, level=0):
3
super().__init__(name, ID) # 通过super()方法调用基类的方法
4
self.level = level
5
6
def get_info(self):
7
return "{}, level:{}".format(super().get_info(), self.level)# 通过super()方法调用基类的方法
8
9
def take_exam(self, grade):
10
if grade.upper() in ['A', 'B', 'C']:
11
self.level += 1
12
return self.level
13
14
def graduate(self):
15
self.get_info()
16
if self.level >= 5:
17
print('congratulations, you have graduated from school')
18
return True
19
else:
20
print('Sorry, you need more practice')
21
return False
1
stud_1 = Student('xiaoming', 10, 2)
2
stud_1.get_info()
3
# 输出 : 'name:xiaoming, level:2'
文件读写
1
#读到一个字符串里
2
f = open('./ShangHai.txt', 'r', encoding='utf-8') # 使用open读取文件
3
content = f.read()
4
f.close() #关闭文件流
5
6
#读取到一个数组里,每一行作为数组的一个元素
7
f = open('./ShangHai.txt', 'r', encoding='utf-8')
8
contents = f.readlines()
9
10
# 可以再for中直接循环输出
11
for line in open('./ShangHai.txt', 'r', encoding='utf-8'):
12
print(line.strip())
13
print("\n\n")
下面做一个小例子:统计词频
1
# 定义一个统计词频函数
2
def my_count(in_file, out_file):
3
#读取文件并统计词频
4
word_count = {}
5
for line in open(in_file, encoding='utf-8'):
6
words = line.strip().split(" ")
7
for word in words:
8
if word.lower() in word_count:
9
word_count[word.lower()] += 1
10
else:
11
word_count[word.lower()] = 1
12
# 写文件
13
out = open(out_file, 'w', encoding='utf-8')
14
for word in word_count:
15
#print(word, word_count[word])
16
out.write(word+" : "+str(word_count[word])+"\n")
17
print("count successfully!")
18
out.close()
1
in_file = 'ShangHai.txt'
2
out_file = 'WordCount.txt'
3
my_count(in_file, out_file)
迭代器/可迭代对象
迭代器,简单的可以理解每次只取一个元素。类似 sql中的游标
迭代是Python最强大的功能之一,是访问集合元素的一种方式。。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:
1
list=[1,2,3,4]
2
it = iter(list) # 创建迭代器对象
3
print (next(it)) # 输出迭代器的下一个元素
4
# 输出 1
5
print (next(it))
6
# 输出 2
迭代器对象可以使用常规for语句进行遍历:
1
#!/usr/bin/python3
2
3
list=[1,2,3,4]
4
it = iter(list) # 创建迭代器对象
5
for x in it:
6
print (x, end=" ")
7
8
# 输出 : 1 2 3 4
实用next()函数,每次取一个元素:
1
#!/usr/bin/python3
2
3
import sys # 引入 sys 模块
4
5
list=[1,2,3,4]
6
it = iter(list) # 创建迭代器对象
7
8
while True:
9
try:
10
print (next(it))
11
except StopIteration:
12
sys.exit()
13
14
# 输出
15
1
16
2
17
3
18
4
生成器yield
- yield关键字的作用和return相似,都是返回一个值。
不同的是,yield返回值之后,yield后面的代码还会继续执行,return则会直接结束代码。
- 生成器就是指实用了yield的函数。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
- 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行 next()方法时从当前位置继续运行。
以下实例使用 yield 实现斐波那契数列:
1
#!/usr/bin/python3
2
3
import sys
4
5
def fibonacci(n): # 生成器函数 - 斐波那契
6
a, b, counter = 0, 1, 0
7
while True:
8
if (counter > n):
9
return
10
yield a
11
a, b = b, a + b
12
counter += 1
13
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
14
15
while True:
16
try:
17
print (next(f), end=" ")
18
except StopIteration:
19
sys.exit()
20
21
# 输出: 0 1 1 2 3 5 8 13 21 34 55