- 学完了基础中的基础后,我们准备深入基础中的函数、类和对象。
function函数:
正如英文单词描述的,函数就是“功能”的意思,把完成一个功能所需要的代码打包起来放在一个函数下可以方便以后程序的重复调用,也能使整体代码条理清晰。正如前面用到的print(), input()之类的内置函数,这里讨论的函数为自定义涵数。
定义函数的格式:
def 函数名 (参数1,参数2,参数3…):
代码行
return - [可选项,如果不加,返回None]
函数的调用格式:
函数名(参数1,参数2,参数3)
函数名一般要小写字母,当调用函数时,如果在后面的括号中加了参数,表明需要将这几个参数传到定义好的函数中去用。
定长传参:
在定义的函数名后面的括号内必须要留有相对应数量的参数名(变量名)进行参数的接收,如果没有特别指名参数赋值的变量,那么参数将按照对应的位置进行参数传递,也叫位置传参。如果在调用时使用接收参数的变量名进行了参数赋值,那么参数将按指定的变量名位置进行参数传递,也叫关键字(变量名)传参。当传递的参数多于收接收的参数量时就是报错。如下
>>> def function1(para1, para2):
... print(para1,para2)
...
>>> function1('Hello', 'World')
Hello World
>>> function1('World','Hello')
World Hello
>>> function1(para2='World',para1='Hello')
Hello World
>>> function1('How','are','you')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function1() takes 2 positional arguments but 3 were given
>>>
如果在定义函数时,参数的末尾有一个指定的参数值时,那么这个参数就是默认参数,即在传参时不写相对应的参数值时,默认将使用预先定义好的数值。如下
>>> def function2(para1, para2, para3='Cool'):
... print(para1, para2, para3)
...
>>> function2('Hello','World')
Hello World Cool
>>> function2('How','are','you')
How are you
>>>
不定长传参:
当不确定要传递的参数有多少时,通常有下面几种方法传
使用 *变量名,作为参数,参数将会以元祖形式接收多出来的参数,输出时如果使用*变量名,则将元祖内的元素以空格分隔的字符串形式输出,如果仅使用变量名,则以元祖方式输出参数。
>>> def function3(para1, *para2):
... print(para1)
... print(para2)
... print(*para2)
... print(para1,para2)
... print(para1, *para2)
...
>>> function3('how','do','you','do','?')
how
('do', 'you', 'do', '?')
do you do ?
how ('do', 'you', 'do', '?')
how do you do ?
>>>
使用 **变量名,作为参数,参数将会以字典形式接收多出来的参数,与元祖不同,字典变量不能直接输出成字符串。
>>> def function4(para1, **para2):
... print(para1)
... print(para2)
... print(**para2)
... print(para1, para2)
... print(para1, **para2)
...
>>> function4('one','two','three')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function4() takes 1 positional argument but 3 were given
>>> function4('one','two'='2','three'='3')
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
>>> function4('one',two='2',three='3')
one
{'two': '2', 'three': '3'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in function4
TypeError: 'two' is an invalid keyword argument for print()
>>> function4('one',two=2, three=3)
one
{'two': 2, 'three': 3}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in function4
TypeError: 'two' is an invalid keyword argument for print()
>>>
注意,如果参数中单独使用一个*,那么这个*后面的参数必须要使用关键字进行传参, *号不能直接输出,即它就像一个强制要求符,它后面的参数必须使用关键字传参,如下
>>> def function5(para1, *, para2):
... print(para1)
... print(*)
File "<stdin>", line 3
print(*)
^
SyntaxError: invalid syntax
>>> def function5(para1, *, para2):
... print(para1)
... print(para2)
... print(para1, para2)
...
>>> function5('Hello','World')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function5() takes 1 positional argument but 2 were given
>>> function5('Hello',para2='World')
Hello
World
Hello World
>>> function5(para1='Hello','World')
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>>
return: 在函数最后加上return 可以指定函数执行完后想要返回的一个值,可以是变量也可以是固定的值,就看你需要返回什么就根据需要写这个表达试。如果不加return,那么函数返回None比如:
>>> def test():
... print('Hello World')
... return 'what'
...
>>> a = test()
Hello World
>>> print(a)
what
>>> def test1():
... sum = 1 + 1
... return sum
...
>>> print(test1())
2
>>>
- 了解了函数,我们就可以升级到类的概念了。本质上有点类似函数,函数是打包小的程序语句,而类就是打包函数用的,通常把执行同一类任务的函数归为一类。类的定义如下, 用class开头,类名首字母通常用大写字母开头,后面加小括号。
class ClassName():
变量1
变量2
def 函数1():
xxxxx
def 函数2():
xxxxx
由于类是一个大壳子,在类中包含了变量和函数。类里面的变量叫做类的属性,而类里面的函数叫做类的方法。使用类,其实是在使用即调用类里面的方法即函数。一个类里面,在类函数外面层定义的变量可以被类内所有函数引用修改,也可以在类外面被引用修改。
在类内被函数引用类的变量时,需要在类方法上一层让类先用@classmathod呼唤一下类方法,而在方法中的括号中加上(cls)表示收到,于是就可以快乐的使用类中的变量了,注意:Python中一定要注意大小写,如:
>>> class Great():
... a = 'Hello'
... b = 'World'
... @classmethod
... def good(cls):
... print(cls.a)
... print(cls.b)
...
>>> great.good()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'great' is not defined
>>> Great.good()
Hello
World
>>>
不难发现,在类外面引用类中的变量、方法格式都是先点名我要使用哪个类,然后通过点'.'来指定要用的变量或者方法名,即 类名.变量名/方法名。能呼叫了,就可以进行变量的引用、修改和方法的调用了。如:
>>> class Great():
... a = 'Hello'
... b = 'World'
... @classmethod
... def good(cls):
... print(cls.a)
... print(cls.b)
...
>>> great.good()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'great' is not defined
>>> Great.good()
Hello
World
>>> Great.a = 'How are'
>>> Great.b = 'you?'
>>> Great.good()
How are
you?
>>>
那么问题来了,类中直接定义的变量可以和外部进行‘沟通’,那么类中的方法呢?因为方法就是函数,所以可以参考函数的参数传递,只是需要指名一下是给哪个类中的方法(函数)传递参数。如:
>>> class Great():
... def Get(para1, para2):
... print(para1, para2)
...
>>> Great.Get('Hello','World')
Hello World
>>> Great.Get(para1='World', para2='Hello')
World Hello
>>> Great.Get(para1='Hello', para2='World')
Hello World
>>>
- 说了半天的类,貌似类作用不是很大。其实不然,类的真正用途在于它的“实例化”,把类变成一样实例对象,这种编程方式才是我们真正想要的,也就是所谓的“面向对象”的编程方式。这样,别人造的轮子就能为我们所用了。
类的实例化其实就是把类“复制”到一个变量,此时我们就叫这个变量为“实例对象“”实例“”对象“,而类相当于这个实例的模板。当使用实例时,实例里的属性、方法改变不会影响类本身的属性、方法,反之,当类(模板)的属性、方法发生改变,会同步到实例里的属性和方法。谁让类是实例的根呢。
需要注意的是,当类需要实例化的时候,类中的方法不能再有@classmethod和(cls)了,需要在方法中使用(self)作为第一个位置参数进行传递,虽然self不是强制性的名字,但这是程序界约定俗成的命名法。当类支持实例化的时候,self是所有方法中第一个默认位置的一个特殊参数。这也解释了为什么不能有@classmethod 和(cls)了,因为要做成一个能用的类(能实例化),让类里面的方法能让大家使用就不能仅限于类里面的参数传递了。同理,由于没有了@classmethod (cls),类里的方法就不能直接被调用了,需要实例化后才能使用。还个举个例子吧,直接调用出错,实例化后才能使用。
>>> class Great():
... def good(self):
... self.a = 'Hello'
... self.b = 'World'
... print(self.a, self.b)
...
>>> Great.good()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: good() missing 1 required positional argument: 'self'
>>> OBJ = Great()
>>> OBJ.good()
Hello World
>>>
通过实例化后,向方法中传递参数的方法,本质上和传递参数给函数是一样的,只是方法在接收参数时,第一位self不能动,剩下的自定义变量就行,如下:
>>> class Great():
... def good(self,para1,para2,para3):
... self.a = para1
... self.b = para2
... self.c = para3
... print(self.a, self.b,self.c)
...
>>> Test = Great()
>>> Test.good('How','are','you?')
How are you?
>>> Test.good(para2='are',para3='you?',para1='How')
How are you?
>>>
有了(self),一个类中的不同方法之间的参数就可以通过这个self进行传递了。常用的情况是当我们设置了一个”初始化“函数的时候。通常在初始化函数中,我们常常用来初始化各种参数,而这些参数通常会用于同一类中的其它方法。
初始化函数的定义:使用一个固定的名字__init__(self),初始化函数还有个特点是,当类被实例化的时候,会被自动调用。如下
>>> class Great():
... def __init__(self,para1,para2,para3):
... self.a = para1
... self.b = para2
... self.c = para3
... def good(self):
... print(self.a, self.b,self.c)
...
>>> Test = Great('How','are','you?')
>>> Test.good()
How are you?
>>>
类方法的重写:当一个类中的方法不适合需求,需要更换时,可以通过在类的外部重新写一个方法,将新方法赋值给类中的旧方法,以此实现新的方法覆盖老的方法,达到替换的目的。
赋值语法:类.老方法 = 新方法 注意,因为不是调用,所以都不能有()。举例如下:
>>> class Great():
... def __init__(self,para1,para2,para3):
... self.a = para1
... self.b = para2
... self.c = para3
... def good(self):
... print(self.a, self.b,self.c)
...
>>> Test = Great('How','are','you?')
>>> Test.good()
How are you?
>>>
>>> def bad(self):
... print('Hello World')
...
>>> Great.good = bad
>>> Test.good()
Hello World
>>>
类的继承:当觉得老类中的方法有用但是功能还不够用的情况下,可以通过定义一个新类,同时把老类继承给新类来实现实例化后的新类能使用上老类中的方法(减少了新类中写重复的方法)。
继承语法:定义新类(老类):效果如下
>>> class Great():
... def __init__(self,para1,para2,para3):
... self.a = para1
... self.b = para2
... self.c = para3
... def good(self):
... print(self.a, self.b,self.c)
...
>>> class newGreat(Great):
... def newgood(self):
... print('New Hello World')
...
>>> Test = newGreat('How','are','you?')
>>> Test.good()
How are you?
>>> Test.newgood()
New Hello World
>>>