houmenghu 2019-05-07
在概述了Python数据类型以及if和loop语句之后,我们已经准备好了解任何编程语言的两个非常重要的概念函数和对象。
函数
函数以它们的数学对应物命名,因为原理是相同的:取一些输入,执行操作并输出新值。
“编程”函数采用一组参数(也可以没有参数),在其中执行语句,并可能返回某些内容(数据类型,对象甚至是其他函数)。
更重要的是,函数就像构建编程块一样,因为它们允许重用代码。因此,让我们首先看看如何在Python中定义函数,然后如何应用代码重用原则。
定义
使用def关键字定义Python函数。我们还需要指定一个函数名称和一些参数:
def function_name(parameter1, parameter2): # some code here pass
参数放在名称后面的括号内。与if,for或while语句一样,函数中的代码块必须适当缩进。
要运行一个函数,我们调用它的名称并提供必要的参数(如果有的话)。
def hello_world(): print("Hello World") hello_world() hello_world() >> Hello World Hello World
在上面的例子中我们:
一个更复杂的例子
假设我们有3个整数变量a,b,c,我们想检查它们是否是偶数。如果不使用函数,我们会这样写。
a = 7 b = 8 c = 9 if a % 2 == 0: print('{} is even'.format(a)) else: print('{} is odd'.format(a)) if b % 2 == 0: print('{} is even'.format(b)) else: print('{} is odd'.format(b)) if c % 2 == 0: print('{} is even'.format(c)) else: print('{} is odd'.format(c)) >> 7 is odd 8 is even 9 is odd
您可以看到它相对较长,并且每个变量都会重复大量代码。现在让我们使用函数来做。
a = 7 b = 8 c = 9 def is_even(nr): if nr % 2 == 0: print('{} is even'.format(nr)) else: print('{} is odd'.format(nr)) is_even(a) is_even(b) is_even(c) >> 7 is odd 8 is even 9 is odd
第二个代码块更短,我们可以通过再次调用它并发送参数来重用该函数用于许多其他变量。
命名参数
到目前为止,我们已经看到了带有直接发送参数的函数。当在函数中有多个参数时,它们的传输顺序很重要。
让我们考虑一个显示学生姓名和成绩的函数。
def display_info(name, grades): print("Name: {}; Grades: {}".format(name, grades)) display_info("Python", [10,6,7]) >> Name: Python; Grades: [10, 6, 7]
我们发送参数的顺序很重要。如果我们颠倒顺序,得到的结果就和预期不一样。
display_info([8,10,8], "Python") >> Name: [8, 10, 8]; Grades: Python
但是,我们可以在调用函数时使用参数的名称。在这种情况下,参数的顺序不再相关,因为它们现在由它们的名称而不是它们被输入进来的顺序来标识。
display_info(grades=[8,10,8], name="Python") >> Name: Python; Grades: [8, 10, 8]
默认值
在定义函数时,我们可以指定参数的默认值。如果这样做,那么该参数是可选的。可以在不使用该参数的情况下调用该函数,在这种情况下,它将使用默认值。
让我们考虑一个函数,它把一个数取幂。第一个参数是数字,第二个参数是应该取多少次方。它的默认值为2。
def raise_power(nr, pwr=2): return pow(nr, pwr)
如果我们调用带有单个参数(nr)的函数,它总是返回它的平方。
print(raise_power(5)) >> 25
如果我们添加第二个参数,该函数将使用其值来表示该数字的幂。
print(raise_power(5,4)) >> 625
希望这个例子能说明函数是多么有用和重要。函数一直都在使用,理解它们的工作原理以及如何正确地调用它们(使用已命名和/或可选参数)是非常重要的。
对象
对象和面向对象编程(OOP)是一个很大的主题,不可能在一篇文章中介绍。与其他概念一样,目的是解释它们如何工作的基本原理,以便我们可以放心地使用我们将来使用的库提供的对象。
在编程中可以更容易地考虑对象,比如现实对象的抽象。例如,一辆汽车,有许多属性,例如:
属性是包含描述对象的值的变量。
汽车可以执行一系列的操作,最基本的操作是:
对象可以执行的动作通过对象内部的函数进行编码。这样的函数就是一种方法。
值描述对象存储在变量在对象和它的属性。
动作的对象可以执行编码函数内部的对象的方法。
创建一个汽车对象
在Python中,对象是使用class关键字创建的。类名应该始终大写。
定义对象就像创建蓝图一样。通过这个蓝图,我们可以创建类的特定实例。从汽车蓝图中我们可以创建特定的汽车(特斯拉或本田思域)。
让我们定义我们的对象。
class Car(object): def __init__(self, brand_att, model_att, color_att): self.brand = brand_att self.model = model_att self.color = color_att
这看起来有点令人迷茫,所以让我们一步一步地解释......
让我们用这个“蓝图”创造一辆汽车。假设我们想要一个白色的特斯拉Model3。就像任何其他值一样,我们希望将它存储在一个变量中,以便我们以后可以访问它。
my_tesla = Car("Tesla", "Model 3", "white")
现在我们有了对象,我们可以使用点(“.”)访问它的属性
print(my_tesla.brand) print(my_tesla.model) print(my_tesla.color) >> Tesla Model 3 white
再试一个。
my_honda = Car("Honda", "Civic", "red") print(my_honda.brand) print(my_honda.model) print(my_honda.color) >> Honda Civic red
我们有两辆车,我们可以访问他们的品牌,型号和颜色属性,但他们做的不多......如果我们可以开动他们,那就更好了:)
创建第一个Car对象方法
方法是对象“动作”的实现。首先应该开启和关闭发动机。为此,我们首先需要一个代表引擎状态的新属性。必须调整类定义。
class Car(object): def __init__(self, brand_att, model_att, color_att): self.brand = brand_att self.model = model_att self.color = color_att self.engine_on = False
我们添加了一个新属性engine_on并将其设置为False。我们在__init__函数中不需要新参数。
如果是False,那么打开引擎方法应该将engine_on更改为True。关闭引擎的方法会适得其反。让我们将这两个函数编码到对象中。
class Car(object): def __init__(self, brand_att, model_att, color_att): self.brand = brand_att self.model = model_att self.color = color_att self.engine_on = False def turn_engine_on(self): if self.engine_on is False: self.engine_on = True def turn_engine_off(self): if self.engine_on is True: self.engine_on = False
我们可以使用self关键字访问方法定义中的对象属性(和其他方法)。所以在turn_engine_on方法中我们首先检查engine_on属性是否为False,如果是,我们将其设置为True。我们在turn_engine_off方法中反转该过程。
让我们测试新的方法。由于我们更改了Car对象,所以我们需要再次创建我们的Car,以便包含更改。
print(my_tesla.engine_on) >> False my_tesla.turn_engine_on() print(my_tesla.engine_on) >> True my_tesla.turn_engine_off() print(my_tesla.engine_on) >> False
我们成功地开启和关闭了我们的引擎!
加速和制动方法
我们可以打开和关闭引擎,所以下一步是移动一下。通过加速和制动方法,我们可以做一些赛车......
首先,我们需要一个新的属性speed。我们可以在__init__函数中默认将其设置为0。
class Car(object): def __init__(self, brand_att, model_att, color_att, acc_att = 10): self.brand = brand_att self.model = model_att self.color = color_att self.engine_on = False self.speed = 0 self.acc = acc_att
为了加速汽车,每次我们调用加速方法时,我们都会将速度提高到acc值。我们会做相反的制动并假装它有意义......
class Car(object): def __init__(self, brand_att, model_att, color_att, acc_att = 10): self.brand = brand_att self.model = model_att self.color = color_att self.engine_on = False self.speed = 0 self.acc = acc_att def turn_engine_on(self): if self.engine_on is False: self.engine_on = True def turn_engine_off(self): if self.engine_on is True: self.engine_on = False def accelerate(self): if self.engine_on is True: self.speed = self.speed + self.acc print("Speed increased to {}".format(self.speed)) def brake(self): if self.speed > 0: self.speed = self.speed - self.acc print("Speed decreased to {}".format(self.speed))
我们再次实例化特斯拉并测试我们的新方法
my_tesla = Car("Tesla", "Model 3", "white") my_tesla.turn_engine_on() my_tesla.accelerate() >> Speed increased to 10 my_tesla.accelerate() >> Speed increased to 20 my_tesla.accelerate() >> Speed increased to 30 my_tesla.brake() >> Speed decreased to 20 my_tesla.brake() >> Speed decreased to 10 my_tesla.brake() >> Speed decreased to 0 my_tesla.turn_engine_off()
现在,我们有了一个在my_tesla变量中实例化的运行良好的Car对象,并开始了解对象是如何工作的。
继承
继承允许使用旧类创建新类。新类具有旧类的所有属性和方法,以及添加到其中的任何新属性和方法。
让我们先创建一个简单的Animal类。
class Animal(object): def __init__(self): print("This is an Animal") def eat(self): print("I've eaten!")
我们已经确定所有的动物都吃。
现在我们可以创建一个Dog类并让它吠叫。
class Dog(Animal): def __init__(self): Animal.__init__(self) print("This is a Dog!") def bark(self): print("BARK!")
必须注意两件事。与常规类不同,在使用继承时,您需要在括号中指定原始类名。
class Dog(Animal)
其次,必须在继承的类__init__中调用原始类名__init__这个特殊函数。
Animal.__init__(self)
让我们实例化一条狗并测试它。
y_dog = Dog() >> This is an Animal This is a Dog! my_dog.bark() >> BARK!
我们现在已经确认了原始类必须首先在继承类__init__中实例化。
继承是一种允许代码重用的技术。
多态性
多态性是不同对象共享方法名称的一种方式。每个方法在每个对象中都有一个单独的实现,但名称是相同的。
这可以在特定上下文中用于创建易于观察的代码。让我们看一个Dog和Cat类的例子,它们都有一个名为eat的方法。因为狗和猫吃的东西不一样,所以这两种动物的区别是很自然的。
class Dog(object): def __init__(self): print("I am a dog") def eat(self): print("I eat dog food") class Cat(object): def __init__(self): print("I am a cat") def eat(self): print("I eat cat food") my_dog = Dog() my_cat = Cat() my_dog.eat() my_cat.eat() >> I am a dog I am a cat I eat dog food I eat cat food
每只宠物都会吃适当的食物。两个类都有eat方法,每个方法都有不同的表现。
多态性的一个优点是我们可以轻松地遍历不同的对象并调用共享名称的方法。
for pet in [my_dog, my_cat]: pet.eat() >> I eat dog food I eat cat food
我们可以同时喂它们:)
再举一个例子,想象一下不同几何形状的列表(正方形,圆形,球形,立方体,三角形等),迭代这个列表并调用area()方法来计算形状的面积。
由于每个形状都有不同的面积计算算法,所以每个实现都是不同的,而area()方法对所有几何形状都有相同的名称。