Python从入门到进阶(四)——语法基础(一)

Python语法

1 缩进规则

1 缩进对程序的影响

1. 缩进不符合规则,解析器会报缩进错误,程序无法运行
# 例1:
pi=0
	print(pi)  #缩进不符合规则 程序报错,抛出异常:IndentationError:unexpected indent
2. 符合规则,但缩进位置不同,程序执行逻辑会有差异
# 例1
isPrint=False
if isPrint:
	print("A")
	Print("B")
# 程序运行后没有输出

# 例2
isPrint=False
if isPrint:
	print("A")
print("B")
# 程序运行后会输出一个字符"B"

2 代码缩进规则

缩进是针对逻辑行的,因此要首先区分代码中的物理行和逻辑行

1. 什么是物理行:源码中换行符分割的每一行代码,是一个物理行

通常就是代码编辑工具中显示的每一行
如果编辑器有自动换行,例如(windows的记事本),需要将其关闭,否则代码会被编辑器重新换行,影响到源码的阅读

a=1
b=2
c=3

print(a,b,c)  # 这里一共5行代码,也是5个物理行

obj={
"a":1,
"b":2
}  # 这里一共4行代码,也是4个物理行
2.什么是逻辑行:Python解释器对代码进行解释,一个语句是一个逻辑行
obj={
"a":1,
"b":2
}  # 这里Python解释器,作为一个赋值语句解释,是一个逻辑行

print("1\
2\
3")  # 这里python解释器,作为一个函数调用语句解释,是一个逻辑行
3.相关的代码书写规则
  1. 可以使用“;”号将多个逻辑行合并成一个物理行
i=1;j=2;k=3;print(i,j,k)
# 等效于
i=1
j=2
k=3
print(i,j,k)

# 需要注意,多个逻辑行使用";"连接时,它们属于同一个缩进.那么
if True:a=1;else a=2
//等效于
if True:
	a=1
	else:
		a=2
//所以else位置缩进出错了
  1. 可以使用""对于一个逻辑行进行换行,书写为多个物理行
print("1\
2\
3")  # 这一个逻辑行书写为3个物理行
  1. 字典,列表等变量赋值语句,是可以直接换行,书写为多个物理行的
obj={"a":1,
	"b":2,
"c":3}
# 这段代码只是一个赋值语句,即一个逻辑行,缩进是针对逻辑行的
# 所以2,3,4行无论怎么缩进,都不影响程序运行

3 缩进规则

  1. 逻辑行的"首行"需要顶格,无缩进(也就是一份源码的第一个逻辑行)
import sys //例如这一行是代码第一行,那它需要顶格
print(sys.argv)
  1. 相同逻辑层(同一个代码块)保持相同的缩进量
a=1
	b=2
# 这是两个赋值语句,即两个逻辑行,需要保持相同的缩进
# 因此改代码运行会报缩进异常
  1. ":"标记一个新的逻辑层
    如:while循环,if分支,函数声明,类定义等等.
    增加缩进表示进入下一个代码层
    减少缩进表示返回上一个代码层
a=1
if a==1print(a)  # 相对于第二行if语句,增加了一个缩进代表进入if条件为真执行的逻辑层
a+=1  # 相对于第三行,减少了一个缩进返回上一个代码层,即if分支执行结束

2 函数

2.1.1 函数概述

在程序设计中,函数的使用可以提升代码的复用率和可维护性。

提升代码的复用率: 程序设计中,一些代码的功能是相同的,操作是一样的,只不过针对的数据不一样。此种情况下,可以将这种功能写成一个函数模块,要使用此功能时只需调用这个函数模块就可以了。
提升代码的可维护性: 使用函数后,实现了代码的复用,某个功能需要核查或修改时,只需要核查或修改此功能相对应的函数就可以了。对功能的修改可以使调用该函数的所有模块同时生效,极大提升了代码的可维护性。

内建函数:内建函数也叫内置函数,即系统已经定义好的函数,开发者可以直接调用。为了使开发者对内函数和自定义函数有一个直观的认识,下面给出一个简单示例。
调用系统内建函数pow():

pow(2,4)

自定义函数func():

def func(a,b):
return a**b


func(2,4)

上述代码中,首先调用了Python语言的内建函数pow()进行幂运算;
然后,自定义了一个函数func(),功能是输出a的b次幂;最后调用了自定义函数func(),输出相应的结果。可以看出,Python语言中函数的定义和使用都是非常便捷的。

2.1.2 函数的定义

在Python语言中,函数通常是由函数名,参数列表以及一系列语句组成的函数体构成的.函数定义的一般格式如下:

def 函数名(参数列表):
	函数体

例如:

def hello():
	print("hello")
	print("world!")

以上实例定义的hello()函数虽然不包含任何参数,但是函数名后的一对括号是不能省略的。在实际应用中,稍复杂的函数通常都会包含一个或多个参数。

下列代码定义了一个计算矩形面积的函数area()和一个欢迎信息打印函数welcome()。

# 计算矩形面积的函数area()
def area(width, height):
    return width * height


# 输出汉英信息的函数
def welcome(name):
    print("Welcome ", name)


# 调用welcome函数
welcome('张三')
# 调用area函数
w = 4
h = 9
print("width=", w, "height=", h, "area=", area(w, h))

上述代码中,首先定义了area()和welcome()两个函数,其中area()提供了width(宽)和height(高)两个参数,函数welcome()函数只提供了一个参数name.然后,分别调用了area()和welcome()函数,在控制台输出了相应的结果.结果如下:

Welcome 张三
width=4 height=9 area=36

以下代码定义了无任何操作的空函数nop()

def nop()pass

在Python代码中,pass语句通常可以用来作为占位符,表示什么操作都不执行.比如在项目起始阶段,如果还没想好函数具体实现时,可以先放置一个pass语句,让代码先成功运行起来,待项目框架搭建完毕后,在进行相应的具体实现.
通常情况下,在Python语言中定义一个具有特定功能的函数需要符合以下规则:

  • 函数代码块以def关键字开头,后接函数标识符名称和形参列表;
  • 任何传入的参数和自变量必须放在圆括号内;
  • 函数的第一行语句可以选择性地使用文档字符串(即函数说明);
  • 函数内容以冒号起始,并且严格统一缩进;
  • 函数都有返回值,默认返回None。

2.1.3 函数的返回值

  • 函数的返回值是函数执行完成后,系统根据函数的具体定义返回给外部调用者的值
  • 在Python语言中,当函数运行到return语句时即执行完毕,同时将结果返回,如果没有return语句,函数体内所有语句执行完毕后返回None
# 函数定义
def add(x,y):
print('x+y=',x+y)
return x+y


# 函数调用
result=add(y=1,x=2)
print(result)

上述代码中,定义的add()函数返回“x+y”的运算结果,可以看到,调用该函数后,把该函数的返回值赋值给了变量result,最后输出了变量result的值
另外需要注意的是,在Python语言中,函数也可以有多个返回值.

# 函数定义
def add(x,y):
	print('x+y=',x=y)
	print('x*y=',x*y)
	return x+y,x*y

# 函数调用
a,b=add(y=1,x=2)
print(a,b)

2.2 函数分类

2.2.1 内置函数

Python语言中自带的函数叫做内建函数,这些内建函数对大部分常用操作进行有效封装,可以直接调用,为开发提供了极大便利。由于内建函数是Python语言内置的函数,因此不需要导入任何函数库即可直接调用

在Python语言中,除内建函数外的其他类型函数通常被称为第三方函数。

  • 第三方函数一般是由其它开发者或组织针对某些特定需求编写的函数库,并共享给大家使用。Python语言的强大功能,也正是得益于其丰富的第三方函数库。不管是内建函数,还是第三方函数,在Python语言中都可以非常方便的使用。
  • 要成功调用一个内建函数或第三方函数,首先需要知道的是该函数的准确名称和参数列表信息。如求绝对值的内建函数abs()有一个数值类型参数。

Python语言常用的内建函数还包括数据类型转换函数,以下代码演示了常用类型转换函数的方法

print("int('12'):",int('12'))
print("int('12.3'):",int('12.3'))
print("float('12.3'):", float('12.3'))
print("str(1.23):", str(1.23))
print("str(10):", str(10))
print("bool(1):", bool(1))
print("bool(''):", bool(''))

输出结果

int('12'): 12
int(12.3): 12
float('12.3'): 12.3
str(1.23): 1.23
str(10): 10
bool(1): True
bool(''): False

上述代码中,分别演示了内建函数int()、float()、str()和bool()的使用方法。其中,int()函数是把传入的参数转换为整数类型,float ()函数是把传入的参数转换为浮点类型,str()函数是把传入的参数转换为字符串类型,bool()函数是把传入的参数转换为布尔类型。

在Python语言中,还可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”,如下代码所示。

a=abs
print(a(-1))
2.2.2 自定义函数

当内建函数不能满足要求时,开发者可以根据实际需要自定义函数。函数自定义完成后,开发者可以在其他代码处通过函数名调用。如下代码演示了自定义函数printme()的定义和调用过程。

# 自定义函数
def printme(str):
    "函数功能:打印传入的字符串"
    print(str)


# 调用自定义函数
printme("调用用户自定义函数!")
printme("再次调用用户自定义函数!")

输出结果

调用用户自定义函数!
再次调用用户自定义函数!

在Python语言中,内建函数可以直接使用,第三方函数需要使用import命令导入相应的库才能使用。对于自定义函数,其定义和调用可以在同一个文件中,也可分离成不同的文件。

from test import hello

hello()

上述代码演示了函数的定义和调用不在一个文件的情形。首先,将hello()函数定义好并保存为test.py文件,然后使用Python语言的import指令“from test import hello”将该文件导入,可以调用hello()函数了。导入时需要注意test是文件名并且不含.py扩展名。

2.3 函数参数

2.3.1 参数种类

函数参数分为可变类型和不可变类型,其调用结果是不同的。
(1)可变类型:类似c++的引用传递,如列表、字典等。如果传递的参数是可变类型,则在函数内部对传入参数的修改会影响到外部变量。
(2)不可变类型:类似c++的值传递,如整数、字符串、元组等。如果传递的参数是不可变类型,则在函数内部对传入参数的修改不会影响到外部变量。
不可变类型参数实例:

def cahnge_int(a):
	a=10


b=2
change_int(b)
print(b)  # 结果是2

上述实例中,有int类型的对象2.指向它的变量是b
在传递给change_int()函数时,按传值方式复制了变量b,a和b都指向了同一个int对象.在a=10时,则新生成一个int值对象10,则新生成一个int值对象10,并让a指向它
可变类型参数实例:

def change_int(my_list):
    "修改传入的列表"
    my_list.append([1, 2, 3])
    print("函数内修改后的变量:", my_list)


my_list = [10, 20, 30]
change_int(my_list)
print("函数外变量的值:", my_list)

在调用函数时,如果传入的参数是可变类型,则外部变量也会被更改。在上述例子中,传入函数的list对象和在末尾添加新内容的mylist对象用的是同一个引用。

2.3.2 位置参数

调用函数时,Python语言必须将函数调用中的每个实参都关联到函数的相应形参。最简单的关联方式是基于实参的顺序,这种关联方式被称为位置实参。下面代码显示学生信息的函数,该函数输出学生的名字及年龄。

def describe_student(person_name, student_age):
    "函数功能:显示学生的信息"
    print("my name is ", person_name)
    print(person_name + "is" + student_age + "years old")


describe_student('Jack', '24')

输出:

my name is  Jack
Jackis24years old
2.3.3 默认参数

编写函数时,可给每个形参指定默认值。在调用函数时,如果给形参提供了实参,Python语言将使用指定的实参值;否则,将使用形参的默认值。给形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。
若大部分学生的年龄为18岁,开发者可以把第二个参数student_age的默认值设定为18,这样,当开发者调用describe_student(Jack)时,相当于调用describe_student(Jack,18) ,如下代码所示。

def describe_student(person_name,student_age='18'):
	print("my name is ",person_name)
	print(person_name+"is"+student_age+"years old")


describe_student('Jack')
describe_student('Jack','18')

结果:

my name is  Jack
Jackis18years old
my name is  Jack
Jackis18years old

默认参数很有用,但使用时要牢记一点,默认参数必须指向不可变对象,否则会出现错误,如下代码所示。

def test_add(a=[]):
    a.append('END')
    return a


print(test_add([1, 2, 3]))
print(test_add(['a', 'b', 'c']))
print(test_add())
print(test_add())
print(test_add())

结果:

[1, 2, 3, 'END']
['a', 'b', 'c', 'END']
['END']
['END', 'END']
['END', 'END', 'END']

从上述代码可以看出,默认参数是空列表[],但是函数test_add()似乎每次都“记住了”上次添加了’END’后的list。这是因为在Python语言中,函数在定义的时候,默认参数H的值就被计算出来了,即[]。因为默认参数H也是一个变量,它指向对象[]。每次调用该函数,如果改变了H的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
可以用None不可变对象来解决报错问题

def test_add(H=None):
	if H is None:
		H=[]
	H.append('END')
	return H


print(test_add())
print(test_add())

结果:

['END']
['END']

对于str、None等类似的不可变对象一旦创建,其内部数据就不能修改,这样就减少了由于修改数据导致的错误。
此外,由于对象不变,多线程环境下同时读取对象不需要加锁,同时读也没有问题。开发者在编写程序时,如果可以设计一个不可变对象,就尽量设计成不可变对象。

2.3.4 不定长参数

在Python语言中,函数还可以定义不定长参数,也叫可变参数.给定一组数字a,b,c… …,请计算a+b+c+… …,要定义这个函数,必须确定输入的参数.开发者可以把a,b,c… …作为一个list或tuple传进来

def calc(numbers):
	sum=0
	for n in numbers:
		sum=sum+n
	return sum

print(calc([1,2,3]))  # 结果是6
print(calc([1,2,3,4]))  # 结果是10

对于以上定义的求和函数,调用的时候,需要先组装出一个list或tuple;在Python语言中,可以在函数参数前面添加“*”号把该参数定义为不定长参数;可以看出,不定长参数的使用使得calc()函数定义和调用都变得简洁,实例如下所示:

def calc(*numbers):
	sum=0
	for n in numbers:
		sum=sum+n
	return sum

print(calc(1,2,3,4))
print(calc())
num=[1,2,3]
print(calc(*num))

结果

10
0
6
2.3.5 关键字参数

关键字实参是传递参数时使用”名称-值“对的方式,在实参中将名称和值关联起来.
关键字实参让开发者无需考虑函数调用中的实参顺序,清楚地指出了函数调用中各个值地用途
关键字参数有扩展函数的功能

2.3.6 命名关键字参数

如果要限制关键字参数的名字,可以用命名关键字参数.和关键字参数**kw不同,如果没有可变参数,命名关键字参数就必须加一个"“号作为特殊分隔符.如果缺少”",Python语言解释器将无法识别位置参数和命名关键字参数.例如,若只接收age和city作为关键字参数,可以采用如下形式.

def enroll(name,gender,*,age,city):
	print(name,gender,age,city)

enroll('Jack','M',age='18',city='Beijing')

输出:

Jack M 18 Beijing
def enroll2(name,gender,*grade,age,city):
	print(name,gender,age,city)

enroll('Jack','M','18','Beijing')

结果报错:

enroll2() missing 2 required keyword-only arguments: 'age' and 'city'
def enroll3(name,gender,*,age='18',city):
	print(name,gender,age,city)

enroll3('Jack','M',city='Beijing')  # 结果是: Jack M 18 Beijing

注意:
*表示不定长参数
** 表示不定长参数的关键字参数

2.3.7 参数组合

在Python语言中定义函数,可以组合使用这些参数(必选参数,默认参数,可变参数,关键字参数和命名关键字参数).注意参数定义是有顺序的.
定义的顺序是:必选参数,默认参数,可变参数,命名关键字参数和关键字参数
比如要定义一个函数,包含上述若干种参数

def func(a,b,c=0,*args,**kw):
	print('a=',a,'b=',b,'c=',c,'args=',args,'kw=',kw)

print(func(1,2))
# 输出结果 a=1 b=2 c=0 args=() kw={}
print(func(1,2,c=3))
# 输出结果 a=1 b=2 c=3 args=() kw={}
print(func(1,2,3,'a','b'))
# 输出结果 a=1 b=2 c=3 args=('a','b') kw={}
print(func(1,2,3,'a','b',x=4))
# 输出结果 a=1 b=2 c=3 args=('a','b') kw={'x':4}

args=(1,2,3,4)
kw={'x':5}
print(func(*args,**kw))
# 输出结果:a=1 b=2 c=3 args=(4,) kw={'x':5}

2.4 函数式编程

2.4.1 高阶函数

接受函数为参数,或者把函数作为结果返回的函数称为高阶函数.例如,若要根据单词的长度排序,只需把len函数传给key参数

fruits=['strawberry','fig','apple','cherry','raspberry','banana']
print(sorted(fruits,key=len))
# 输出结果如下:
# ['fig', 'apple', 'cherry', 'banana', 'raspberry', 'strawberry']
def reverse(word):
    return word[:: -1]

print(reverse('testing'))  # 结果是:gnitset 反转
print(sorted(fruits,key=reverse))
# 输出结果如下:
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
2.4.2 匿名函数

所谓匿名函数,即不再使用def语句这样标准形式定义的函数,Python语言经常使用lamba来创建匿名函数.lamba只是一个表达式,函数体比def定义的函数体要简捷.lambda函数的语法如下所示

lamda [arg1[,arg2],....argn]]:expression

举例:

sum=lambda arg1,arg2:arg1+arg2
print(sum(1,2))  # 结果是:3

上述代码中,第一行定义了一个lambda函数,执行两个数的和运算,并且把该lambda函数命名为sum.会面的代码通过sum()函数即实现了调用lambda函数的功能.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值