目录
一、逻辑控制语句
条件控制语句 if-else
for 循环语句
while 循环
break 语句
continue 语句
Pass 语句
二、函数
函数的定义与调用
参数传递
函数的参数类型
Return 语句
三、类
类的定义
self 参数
实例化
Python 中类定义与 Java、C++ 的差别
继承
函数的重写
私有属性与私有方法
Python 条件控制语句的形式为:
if Condition1:
Action1
elif Condition2:
Action2
else:
Action3
注意要点
:
。条件控制语句实例
实例1:从控制台输入两个数字 A、B,判断大小后输出较大数字,如果相等则输出提示和数值。
#从控制台输入数据默认为字符串类型,需要强制转换为int类型
A = int(input("Please enter the number A:"))
B = int(input("Please enter the number B:"))
if A > B:
print('The larger number is:',A)
elif A == B:
print('A and B are equal to ',A)
else:
print('The larger number is:',B)
执行结果:
Please enter the number A:123
Please enter the number B:456
The larger number is: 456
一般,我们通过 for 循环来遍历序列中的项目,这里序列包括但不限于字符串、列表、元组、字典。
for循环的一般形式如下:
for - in
:
实例1:求一组数据的平均值。
#测试数据集
num_set = [98,94,82,67,58,90,86]
sumOfNum = 0
#遍历列表中的元素,求和
for element in num_set:
sumOfNum += element
#求平均值并打印结果
average = sumOfNum/len(num_set)
print("The average is:%f"%(average))
执行结果:
The average is:82.142857
实例2:通过 range() 函数遍历数据序列,range() 函数可以生成数列,将生成的数列作为索引,我们可以遍历数字序列。range() 函数的参数是可变的:
for index in range(4):
print("index:",index)
执行结果:
index: 0
index: 1
index: 2
index: 3
实例3:for 循环结合 range() 遍历数据序列。
#测试数据集
city_set = ['BeiJin','TianJin','ShangHai','HangZhou','SuZhou']
#索引从0开始,以步长2遍历
for index in range(0,len(city_set),2):
print("city_set[%d]:%s"%(index,city_set[index]))
执行结果:
city_set[0]:BeiJin
city_set[2]:ShangHai
city_set[4]:SuZhou
与 for 循环不同,while 循环不是采用遍历数据序列的方式来进行循环操作的,其循环的依据是条件判断。
while 循环的一般形式如下,即当 condition 为 True,则执行 Action,否则退出。
while Conditon:
Action
实例1:求一组数据的平均值。
#初始化测试数据
num_set = [98,94,82,67,58,90,86]
sumOfNum = 0
index = 0
while index < len(num_set):
sumOfNum += num_set[index]
index += 1
#求平均值并打印结果
average = sumOfNum/len(num_set)
print("The average is:%f"%(average))
执行结果:
The average is:82.142857
break 语句用于跳出 for 和 while 循环体,也就意味着循环结束。
如下例子:检测数据集中是否存在小于60的数字,存在则打印提示信息并终止。
#初始化测试数据
num_set = [98,94,82,67,58,90,86]
for i in range(len(num_set)):
if num_set[i] < 60:
print("Someone failed!")
break
else:
print(num_set[i])
执行结果:
98
94
82
67
Someone failed!
在实际应用中,break 语句经常和 while 语句结合使用,当条件满足的时候跳出循环。
与 break 不同,continue 不会退出循环体,而是跳过当前循环块的剩余语句,继续下一轮循环。
如下例子:遍历数据集,遇到小于60的数据打印提示。
#初始化测试数据
num_set = [98,94,82,67,58,90,86]
for i in range(len(num_set)):
if num_set[i] < 60:
print("Someone failed!")
continue
print(num_set[i])
执行结果:
98
94
82
67
Someone failed!
90
86
Python pass 是空语句,一般用做占位,不执行任何实际的操作,只是为了保持程序结构的完整性。
如下例子,else 语句本来可以不写,但写上更为完整,这时候 pass 占位的意义就体现出来了。
#初始化测试数据
num_set = [98,94,82,67,58,90,86]
for i in range(len(num_set)):
if num_set[i] < 60:
print("Someone failed!")
else:
pass
在实际应用中,通常以函数作为一个基本的代码单元,对一组需求进行抽象,用于完成一项具体的任务。函数能提高应用的模块性,和代码的重复利用率。Python 会提供一些内建函数,比如 print()、sqrt()、append()、pop()。我们也可以自己创建函数,这种函数被称为用户自定义函数。
在 C/C++、Java 中,函数(方法)的定义形式如下:
修饰符1,修饰符2,…,返回值类型,函数名(参数列表)
public static String getPath(String basePath, String fileName)
Python 中函数的定义则“简洁”得多,Python 函数无需声明返回值类型,也无需修饰符,一般地,函数的定义形式如下:
函数定义符,函数名(参数列表)
def getPath(basePath, fileName):
def getName():
下面的代码中定义了一个比较函数,并执行了3次调用。
#定义函数
def compare(parameter1, parameter2):
if (parameter1 > parameter2):
print(1)
elif (parameter1 == parameter2):
print(0)
else:
print(-1)
#调用函数
compare(123,456)
compare(3.14,1.5)
compare(12,12.1)
执行结果:
-1
1
-1
变量与引用
在 Python 中,所有类型:函数、模块、数字、字符串、列表、元组、字典等等都是对象,而变量是没有类型的,怎么理解呢?请看如下实例:
a = 12
print("a=", a)
a = "ABCDE"
print("a=", a)
a = [1,2,3,4,5]
print("a=", a)
a = (1,2,3,4)
print("a=", a)
a = {'key':12,'key1':13}
print("a=", a)
执行结果:
a= 12
a= ABCDE
a= [1, 2, 3, 4, 5]
a= (1, 2, 3, 4)
a= {'key': 12, 'key1': 13}
从上面的例子可以看出,同一段代码中,同一个变量 a 先后被赋值整数、字符串、列表等多种类型,这是因为变量本身没有类型,它仅仅只是一个对象的引用(指针),它可以引用任何类型,上面例子中,变量 a 先后引用多种数据类型,本质上也仅仅是改变指向而已。
不可变类型
上文提及,变量没有类型,仅仅作为对象的引用,我们可以再深化一下,如下例子:
a = 12
a = 15
上述过程的实质就是:首先创建一个对象12,让 a 指向它,然后再创建一个对象 15,再让 a 指向后者,而前者12就被丢弃。这个过程是通过创建新的对象来实现的,并不是直接改变 a 的值。
这种只能通过创建新的对象才能改变对变量的赋值的数据类型,称为不可变类型,如整数、字符串、元组都是不可变类型。再来看一个例子:
def change(x):
x = 10
a = 5
change(a)
print("a=",a)
执行结果:
a= 5
调用 change() 函数并没有改变变量 a 的内容,这是因为,定义了一个变量 a,a 指向数字5,然后执行 change 函数,是复制 a 到 x,刚开始 x 也指向数字5,在函数体内执行 x=10,由于整数是不可变对象,所以将创建一个新的对象10,并将10赋值给 x 变量,此时 x 指向10,而 a 本身并没有发生改变,仍然指向5。
在 Python 中,对于不可变对象,调用自身的任意方法,并不会改变对象自身的内容,这些方法会创建新的对象并返回,保证了不可变对象本身是永远不可变的。
可变类型
与不可变类型相对就是可变类型,包括列表、字典、集合、队列等。如下例子:
def change(x):
x.append(2012)
a = [1,2,3,4]
change(a)
print("a=",a)
执行结果:
a= [1, 2, 3, 4, 2012]
很明显,a 发生了改变,原因分析:执行 change() 方法时,x 指向列表 [1,2,3,4]
,因为列表是可变对象,执行 x.append(5) 时,并不会产生新的对象,而是直接作用在原来列表对象 [1,2,3,4]
上,进而列表对象改变为 [1,2,3,4,5]
。
Python 中,函数的参数有四种类型:必须参数、关键字参数、默认参数和不定长参数。
必须参数
函数在定义的时候,已经声明了参数的数量,我们在调用函数的时候,参数的数量必须与声明时一致,且要注意顺序。
实例1:参数数量要对应。
#声明参数为一个
def update(arg):
arg = arg + 1
#正确
update(12)
#不正确,参数缺失
update()
#不正确,参数多余
update(1,2)
实例2:参数顺序要一致。
def printInfo(name, sex, age):
print("name:",name)
print("sex:",sex)
print("age:",age)
#正确
printInfo("Jack","female", 18)
#错误,参数顺序不对应
printInfo(18,"Jack","female")
关键字参数
上面已经提到,调用函数时,不仅参数数量要相等,还要顺序匹配。在 Python 中,还有一种方式可以更灵活的匹配参数:函数调用使用关键字参数来确定传入的参数值。
如下实例:
def printInfo(name, sex, age):
print("name:",name)
print("sex:",sex)
print("age:",age)
#都是正确的
printInfo(name="Jack",sex="female",age=18)
printInfo(sex="female",name="Jack",age=18)
printInfo(sex="female",age=18,name="Jack")
默认参数
有些场景下,如果调用函数时,参数错误可能会导致不可预期的严重后果,因此,为了增强函数的适应性和容错性,可以采取一种策略:调用函数时,如果没有传递参数,则会使用默认参数。如下实例:
#声明参数为一个
def printInfo(name, sex, age=0):
print("name:",name)
print("sex:",sex)
print("age:",age)
#正确
printInfo(name="Jack",sex="female")
不定长参数
有些场景下,我们希望设计一个参数数量不确定的函数,如任意个整数求和,调用形式可以是:sum(a)、sum(a,b,c)、sum(a,b,c,d)……,这时候我们需要使用一种不定长参数,一般定义形式如下:
def functionname([formal_args,] *var_args_tuple ):
functionbody
加了(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。如下实例:
#定义一个求和函数
def sum(num, *num_list):
sum = num
for element in num_list:
sum += element
print("sum=",sum)
sum(1)
sum(1,2,3,4)
执行结果:
sum= 1
sum= 10
return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的 return 语句返回 None,表示没有任何值。如果函数没有显式的使用 return 语句,Python 函数也会默认返回 None 对象。
#定义比较函数
def compare(parameter1, parameter2):
if (parameter1 > parameter2):
return 1
elif (parameter1 == parameter2):
return 0
else:
return -1
result = compare(123,456)
print("result=",result)
执行结果:
result= -1
变量作用域
变量的使用非常多,有些地方甚至同名,那么,它们会不会冲突呢?实例如下:
#这里的a是全局变量
a = 123
def function():
a = 10 #这里的a是局部变量
print("I a=",a)
function()
print("II a=",a)
执行结果:
I a= 10
II a= 123
上述实例可见,同名的变量并没有发生冲突,这是因为它们的“作用域”不同,变量只在自己的作用域内有效,a=123 处属于全局变量,function() 函数内部 a=10 属于局部变量,作用域不同,因此并不会冲突。
作用域分类
按作用域不同,变量可分为四种类型:L(Local),局部作用域;E(Enclosing),闭包函数外的函数中;G(Global),全局作用域;B(Built-in),内建作用域;
使用变量时,会根据作用域进行查找,优先级顺序为:L –> E –> G –>B,即在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
Python 是一门完全面向对象的编程语言,在 Python 中,数字、字符串、列表、元组、字典等都是对象。
相较于函数,类则是更高级别的抽象结构,类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础。类是一种用户定义类型,也称类类型。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象,类的实质是一种数据类型。
与其它面向对象编程语言类似,在 Python 中,类具有多态、封装、继承。不过,Python 中没有重载,类的定义细节也具有明显差异。定义类的一般形式如下:
class ClassName:
.
.
.
上面提到,类的本质是一种数据结构,一个类通常包含数据成员和函数成员。数据成员用于刻画类所描述的一类事物的属性,如描述人,一般用姓名、年龄、性别、学历等属性进行刻画,这就是数据成员;函数成员用于完成具体的任务,如查询、设置人名、打印基本信息等。如下实例:
#定义一个简单的类,描述一个人的基本信息
class Person:
#定义类的数据成员:姓名,年龄
name=''
age=0
#定义一个函数:打印类实例的基本信息
def printPersonInfo(self):
print('person-info:{name:%s, age:%d}'%(self.name,self.age))
#定义一个简单的函数
def hello(self):
print("hello world!")
#实例化,创建一个对象
p1 = Person()
#访问类的属性:数据成员,访问语法obj.X
print("name:",p1.name)
print("age:",p1.age)
#访问类的函数
p1.printPersonInfo()
p1.hello()
执行结果:
name:
age: 0
person-info:{name:, age:0}
hello world!
上述实例中,Person 类定义了两个函数,其定义形式与函数存在明显区别:类中的函数必须有一个额外的参数 self,并且 self 参数必须放在第一个参数的位置。那么,对于一个实例化的对象,self 参数代表什么呢?来看一个例子。
#定义一个简单的类,描述一个人的基本信息
class Person:
#定义类的数据成员:姓名,年龄
name=''
age=0
#定义一个函数:打印类实例的基本信息
def printPersonInfo(self):
print('name:',self.name)
print('self:',self)
print('self class:',self.__class__)
#实例化,创建一个对象
p1 = Person()
#访问类的函数
p1.printPersonInfo()
执行结果:
name:
self: <__main__.Person object at 0x00000000067B5F98>
self class:
从执行结果可以看出,self 的内容是一个地址,它代表当前实例,也就是当前对象的地址。需要说明的是,self 参数并不是 Python 的保留关键字,而是为了便于理解,按照惯例命名而来。事实上,换做其它名字也可以(须遵循规则:必须是类函数的第一个参数)。
上面,我们创建了一个 Person 类的对象:p1=Person(),通过对象可以访问类的属性和调用类的函数,语法形式为:obj.name,其中 name 代表类的属性名或函数名。
上述例子中存在一个疑点,例子中实例化对象的操作并不是显式调用构造函数完成的,如下代码:
p1 = Person()
类中并没有定义名为 Person() 的函数,Person 是类名,在进行实例化创建对象的时候,会自动调用__init()__
函数。该函数用于创建对象,并赋予所创建对象初始状态。
上述例子中,做了很多简化,创建的对象的所有属性都是默认值,在实际应用中,通常会采取更有效的方式来赋予对象初始状态。如下实例:
#定义一个简单的类,描述一个人的基本信息
class Person:
#定义类的数据成员:姓名,年龄
name=''
age=0
#定义构造函数,用于创建一个类实例,也就是类的具体对象
#通过参数传递,可以赋予对象初始状态
def __init__(self,name,age):
self.name = name
self.age = age
#定义一个函数:打印类实例的基本信息
def printPersonInfo(self):
print('person-info:{name:%s, age:%d}'%(self.name,self.age))
#实例化,创建两个对象,默认调用构造函数:__init__()
p1 = Person("Zhang San",12)
p2 = Person("Li Si",13)
#访问类的属性:数据成员,访问语法obj.X
print("name:",p1.name)
print("age:",p1.age)
#调用函数
p1.printPersonInfo()
p2.printPersonInfo()
运行结果:
name: Zhang San
age: 12
person-info:{name:Zhang San, age:12}
person-info:{name:Li Si, age:13}
从上面的例子中可以发现,Python 中类的定义与 Java 和 C++ 的区别:
__init__
,若不定义构造函数,则默认为 __init__(self)
,Java、C++ 则具有重载特性,可定义多个构造函数,且构造函数名必须与类名一致;#定义一个简单的类,描述一个人的基本信息
class Person:
#定义构造函数,用于创建一个类实例,也就是类的具体对象
def __init__(self,name,age):
self.name = name
self.age = age
#定义一个函数:打印类实例的基本信息
def printPersonInfo(self):
print('person-info:{name:%s, age:%d}'%(self.name,self.age))
继承可谓一种带有褒义的懒惰行为,一个最直观的好处就是减少编写重复代码,通过继承,子类可以重用父类中的函数和数据成员。当然,继承的意义远不止于此,这里就不展开了。
关于继承,通常将实施继承行为的类称为子类(Child Class)或者派生类(Derived Class),被继承的类称为父类(Parent Class)或者基类(Base Class)。与 Java、C++ 相比,Python 中继承的一般形式颇为简洁:
class childClassName(parentClassName):
.
.
.
下面结合实例来看一下,定义一个类 Occupation 和一个继承 Occupation 的类 Person,继承的定义形式为:Person(Occupation),无需关键词声明。
#定义一个类Occupation,描述职业
class Occupation:
#定义构造函数
def __init__(self,salary,industry):
self.salary = salary
self.industry = industry
def printOccupationInfo(self):
print('Occupation-info:{salary:%d, industry:%s}'%(self.salary,self.industry))
#定义一个简单的类Person,继承自类Occupation
class Person(Occupation):
def __init__(self,name,age):
self.name = name
self.age = age
#定义一个函数:打印类实例的基本信息
def printPersonInfo(self):
print('person-info:{name:%s, age:%d}'%(self.name,self.age))
#创建一个子类对象
temp = Person('Wu-Jing',38)
#访问父类的数据成员
temp.salary = 21000
temp.industry = "IT"
#分别调用本身和父类的函数
temp.printOccupationInfo()
temp.printPersonInfo()
执行结果:
Occupation-info:{salary:21000, industry:IT}
person-info:{name:Wu-Jing, age:38}
多继承
一些场景下,一个子类可能需要继承多个父类,举个例子:有三个类分别描述职业信息,购物信息,银行账户信息,现在定义一个类Person来描述一个人,显然,Person涉及上述三个类的信息,为了重复利用代码,降低开发难度,可以直接继承上述三个类,这便是多继承的应用。如上所述,多继承定义形式如下:
class childClassName(parentClassName1,parentClassName2,…):
.
.
.
关于多继承,实例如下:
#定义一个类BankAccount,描述银行账户
class BankAccount:
def __init__(self,number, balance):
self.number = number
self.balance = balance
#计算并返回年利息
def getAnnualInterest (self):
return self.balance*0.042
#定义一个类Occupation,描述职业
class Occupation:
def __init__(self,salary,industry):
self.salary = salary
self.industry = industry
def printOccupationInfo(self):
print('Occupation-info:{salary:%d, industry:%s}'%(self.salary,self.industry))
#定义一个类Person,继承自类BankAccount和BankAccount
class Person(Occupation,BankAccount):
def __init__(self,name,age):
self.name = name
self.age = age
#定义一个函数:打印类实例的基本信息
def printPersonInfo(self):
print('person-info:{name:%s, age:%d}'%(self.name,self.age))
#创建一个子类对象
temp = Person('Wu-Jing',38)
#访问父类数据成员
temp.number = 622202050201
temp.balance = 1000000.99
temp.salary = 21000
temp.industry = "IT"
#分别调用本身和父类的函数
temp.printOccupationInfo()
temp.printPersonInfo()
print('Annual interest:',temp.getAnnualInterest())
执行结果:
Occupation-info:{salary:21000, industry:IT}
person-info:{name:Wu-Jing, age:38}
Annual interest: 42000.041580000005
需要注意的是,多继承中,子类继承了不同父类中的属性和函数,这些属性和函数可能存在同名的情况,在子类使用这些同名的函数或属性时,在没有指定的情况下,Python 将根据一定顺序进行搜索:首先搜索子类,如果未找到则根据多继承定义的顺序,从左至右在父类中查找。
如下实例:
#定义一个类 BankAccount,描述银行账户
class BankAccount:
def printInfo(self):
print('BankAccount-info')
#定义一个类 Occupation,描述职业
class Occupation:
def printInfo(self):
print('Occupation-info')
#定义一个类 Person,继承自类 BankAccount 和 BankAccount
class Person(Occupation,BankAccount):
def __init__(self,name,age):
self.name = name
self.age = age
def printPersonInfo(self):
print('person-info')
#创建一个子类对象
temp = Person('Wu-Jing',38)
#调用父类中的函数
temp.printInfo()
执行结果:
Occupation-info
很明显,根据定义顺序,优先调用父类 Occupation 中的 printInfo()。
一些场景下,从父类继承来的函数并不能完全满足需求,需要在子类中对其进行修改,这就是重写的概念:在子类中重写父类中的函数,当子类对象调用该名称的函数时,会调用子类中重写的函数,父类中的同名函数将被覆盖。
实例如下:
#定义一个类Occupation,描述职业
class Occupation:
#定义构造函数
def __init__(self,salary,industry):
self.salary = salary
self.industry = industry
def printInfo(self):
print('salary:%d, industry:%s}'%(self.salary,self.industry))
#定义一个简单的类Person,继承自类Occupation
class Person(Occupation):
def __init__(self,name,age):
self.name = name
self.age = age
#定义一个函数:打印类实例的基本信息
def printInfo(self):
print('name:%s, age:%d'%(self.name,self.age))
print('salary:%d, industry:%s'%(self.salary,self.industry))
#创建一个子类对象
temp = Person('Wu-Jing',38)
#访问父类的数据成员
temp.salary = 21000
temp.industry = "IT"
#分别调用函数printInfo()
temp.printInfo()
执行结果:
name:Wu-Jing, age:38
salary:21000, industry:IT
前面的实例中,类的属性和函数都是“公有”的,可以通过类对象直接访问。但是,在某些场景下,我们并不希望对外暴露类的内部细节,为了限制外部访问,我们可以将对应的属性和函数设置为私有。将类的属性和函数设置为私有的一般形式为以下两种。
1.定义私有属性
__attribute
:属性名前面加两个下划线,即声明该属性为私有,不能在类的外部直接访问,在类内部访问时用 self.__attribute
。
2.定义私有函数
__function
:函数名前面加两个下划线,即声明该函数为私有,不能在类的外部直接访问,在类内部访问时用 self.__ function
。
实例如下:
#定义一个简单的类,描述一个人的基本信息
class Person:
#定义两个私有属性name,age
def __init__(self,name,age):
self.__name = name
self.__age = age
#定义公有函数,在类外部可以访问
def getName(self):
self.__fun()
return self.__name
def getAge(self):
return self.__age
#定义一个私有函数,只能在类内部使用
def __fun(self):
print('hello')
#实例化
p1 = Person("Zhang San",12)
#访问类的私有属性和私有函数,将会报错
print("name:",p1.__age)
print("age:",p1.__name)
p1.__fun()
对于私有属性和私有函数,如果需要在类外访问,可以通过公有函数实现,这与 Java 和 C++ 是一致的。
如下实例:
#定义一个简单的类,描述一个人的基本信息
class Person:
#定义两个私有属性name,age
def __init__(self,name,age):
self.__name = name
self.__age = age
#定义公有函数,在类外部可以访问
def getName(self):
self.__fun()
return self.__name
def getAge(self):
return self.__age
#定义一个私有函数,只能在类内部使用
def __fun(self):
print('hello')
#实例化
p1 = Person("Zhang San",12)
#访问类的公有函数
print("name:",p1.getName())
执行结果:
hello
name: Zhang San