Python支持大多数面向对象编程技术。在Python中所有东西都是对象,包括类、函数、数和模块。它允许多态性,不只是在类层级之内而且通过采用鸭子类型的方式。任何对象可以用于任何类型,只要它有适当的方法和特性就能工作。
Python的函数支持递归和闭包及其他头等函数特征,但不支持函数重载。Python的函数作为第一类对象,具有和普通对象平等的地位。
本文继续总结Python基础中的重要部分--函数与类。
函数用于完成一项特定的工作。函数允许您只编写一次代码,然后在需要完成相同任务时运行这些代码。函数可以接收它们需要的信息,并返回它们生成的信息。有效地使用函数可以使程序更容易编写、读取、测试和修复。
函数的第一行是它的定义,用关键字def
标记。函数名后面跟着一组圆括号和冒号。用三引号括起来的文档字符串描述函数的功能。函数体缩进一层。要调用一个函数,请在函数名之后加上一组圆括号。
我们可以自己定义一个函数,但是需要遵循以下的规则:
()
。return
相当于返回 None。def greet_user():
"""Display a simple greeting."""
print("Hello!")
greet_user()
def greet_user(username):
"""Display a personalized greeting."""
print("Hello, " + username + "!")
greet_user('jesse')
greet_user('diana')
greet_user('brandon')
两种主要的参数是位置参数和关键字参数。
使用位置参数时,Python将函数调用中的第一个参数与函数定义中的第一个形参进行匹配,依此类推。
使用关键字参数,您可以指定每个参数应该在函数调用中赋值给哪个形参。当您使用关键字参数时,参数的顺序并不重要。
def describe_pet(animal, name):
"""Display information about a pet."""
print("\nI have a " + animal + ".")
print("Its name is " + name + ".")
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')
def describe_pet(animal, name):
"""Display information about a pet."""
print("\nI have a " + animal + ".")
print("Its name is " + name + ".")
describe_pet(animal='hamster', name='harry')
describe_pet(name='willie', animal='dog')
可以为参数提供默认值。当函数调用忽略此实参时,将使用默认值。在函数定义中,带有默认值的形参必须列在没有默认值的形参之后,这样位置实参仍然可以正常起作用。
def describe_pet(name, animal='dog'):
"""Display information about a pet."""
print("\nI have a " + animal + ".")
print("Its name is " + name + ".")
describe_pet('harry', 'hamster')
describe_pet('willie')
None
语使参数可选def describe_pet(animal, name=None):
"""Display information about a pet."""
print("\nI have a " + animal + ".")
if name:
print("Its name is " + name + ".")
describe_pet('hamster', 'harry')
describe_pet('snake')
函数可以返回一个值或一组值。当函数返回值时,调用行必须提供一个用于存储返回值的变量。函数在到达return
语句时停止运行。
def get_full_name(first, last):
"""Return a neatly formatted full name."""
full_name = first + ' ' + last
return full_name.title()
musician = get_full_name('jimi', 'hendrix')
print(musician)
def build_person(first, last):
"""Return a dictionary of information
about a person.
"""
person = {'first': first, 'last': last}
return person
musician = build_person('jimi', 'hendrix')
print(musician)
def build_person(first, last, age=None):
"""Return a dictionary of information
about a person.
"""
person = {'first': first, 'last': last}
if age:
person['age'] = age
return person
musician = build_person('jimi', 'hendrix', 27)
print(musician)
musician = build_person('janis', 'joplin')
print(musician)
您可以将列表作为参数传递给函数,函数可以使用列表中的值。该函数对列表所做的任何更改都将影响原始列表。你可以通过传递列表的副本作为参数来阻止函数修改列表。
def greet_users(names):
"""Print a simple greeting to everyone."""
for name in names:
msg = "Hello, " + name + "!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
下面的示例将模型列表发送到一个函数以进行打印。原始列表被清空,第二个列表被填充。
def print_models(unprinted, printed):
"""3d print a set of models."""
while unprinted:
current_model = unprinted.pop()
print("Printing " + current_model)
printed.append(current_model)
# 存储一些未打印的设计,并打印每一个。
unprinted = ['phone case', 'pendant', 'ring']
printed = []
print_models(unprinted, printed)
print("\nUnprinted:", unprinted)
print("Printed:", printed)
下面的示例与前面的示例相同,只是在调用print_models()
之后原始列表没有改变。
def print_models(unprinted, printed):
"""3d print a set of models."""
while unprinted:
current_model = unprinted.pop()
print("Printing " + current_model)
printed.append(current_model)
# 存储一些未打印的设计,并打印每一个。
original = ['phone case', 'pendant', 'ring']
printed = []
print_models(original[:], printed)
print("\nOriginal:", original)
print("Printed:", printed)
有时你不知道一个函数需要接受多少参数。
Python允许您使用*
操作符将任意数量的参数收集到一个形参中。接受任意数目实参的形参必须出现在函数定义的最后。
**
操作符允许参数收集任意数量的关键字参数。
def make_pizza(size, *toppings):
"""Make a pizza."""
print("\nMaking a " + size + " pizza.")
print("Toppings:")
for topping in toppings:
print("- " + topping)
# 用不同的配料做三个披萨。
make_pizza('small', 'pepperoni')
make_pizza('large', 'bacon bits', 'pineapple')
make_pizza('medium', 'mushrooms', 'peppers',
'onions', 'extra cheese')
def build_profile(first, last, **user_info):
"""Build a user's profile dictionary."""
# 使用所需的键构建字典。
profile = {'first': first, 'last': last}
# 添加任何其他键和值。
for key, value in user_info.items():
profile[key] = value
return profile
# 创建两个具有不同类型信息的用户。
user_0 = build_profile('albert', 'einstein',
location='princeton')
user_1 = build_profile('marie', 'curie',
location='paris',
field='chemistry')
print(user_0)
print(user_1)
可以将函数存储在名为模块的单独文件中,然后将所需的函数导入包含主程序的文件中。这允许更纯粹的程序文件。(确保模块与主程序存储在同一个目录中。)
pizza.py
def make_pizza(size, *toppings):
"""Make a pizza."""
print("\nMaking a " + size + " pizza.")
print("Toppings:")
for topping in toppings:
print("- " + topping)
making_pizzas.py
模块中的每个函数都可以在程序文件中找到。import pizza
pizza.make_pizza('medium', 'pepperoni')
pizza.make_pizza('small', 'bacon', 'pineapple')
from pizza import make_pizza
make_pizza('medium', 'pepperoni')
make_pizza('small', 'bacon', 'pineapple')
import pizza as p
p.make_pizza('medium', 'pepperoni')
p.make_pizza('small', 'bacon', 'pineapple')
from pizza import make_pizza as mp
mp('medium', 'pepperoni')
mp('small', 'bacon', 'pineapple')
最好不要这样做,但当你在别人的代码中看到它时要认出它。它可能会导致命名冲突,从而导致错误。
from pizza import *
make_pizza('medium', 'pepperoni')
make_pizza('small', 'bacon', 'pineapple')
类定义对象的行为和对象可以存储的信息类型。类中的信息存储在属性中,属于类的函数称为方法。子类继承其父类的属性和方法。
类是面向对象编程的基础。类表示希望在程序中建模的真实世界的事物:例如,狗、汽车和机器人。可以使用一个类来创建对象,这些对象是狗、汽车和机器人的特定实例。类定义了整个对象类别可以拥有的一般行为,以及可以与这些对象关联的信息。
类可以相互继承——可以编写一个扩展现有类功能的类。这允许有效地编写各种情况下的代码。
命名约定: 在Python中,类名用驼峰大小写写,对象名用小写下划线写。包含类的模块仍然应该用小写下划线命名。
考虑一下我们如何建模一辆汽车。我们会把什么信息和汽车联系起来,它会有什么行为?信息存储在称为属性的变量中,行为由函数表示。属于类的函数称为方法。
class Dog():
"""Represent a dog."""
def __init__(self, name):
"""Initialize dog object."""
self.name = name
def sit(self):
"""Simulate sitting."""
print(self.name + " is sitting.")
my_dog = Dog('Peso')
print(my_dog.name + " is a great dog!")
my_dog.sit()
class Car():
"""A simple attempt to model a car."""
def __init__(self, make, model, year):
"""Initialize car attributes."""
self.make = make
self.model = model
self.year = year
# 燃料容量和液位(加仑)。
self.fuel_capacity = 15
self.fuel_level = 0
def fill_tank(self):
"""Fill gas tank to capacity."""
self.fuel_level = self.fuel_capacity
print("Fuel tank is full.")
def drive(self):
"""Simulate driving."""
print("The car is moving.")
my_car = Car('audi', 'a4', 2016)
print(my_car.make)
print(my_car.model)
print(my_car.year)
my_car.fill_tank()
my_car.drive()
my_car = Car('audi', 'a4', 2016)
my_old_car = Car('subaru', 'outback', 2013)
my_truck = Car('toyota', 'tacoma', 2010)
可以直接修改属性的值,也可以编写更仔细地管理值更新的方法。
my_new_car = Car('audi', 'a4', 2016)
my_new_car.fuel_level = 5
def update_fuel_level(self, new_level):
"""Update the fuel level."""
if new_level <= self.fuel_capacity:
self.fuel_level = new_level
else:
print("The tank can't hold that much!")
def add_fuel(self, amount):
"""Add fuel to the tank."""
if (self.fuel_level + amount
<= self.fuel_capacity):
self.fuel_level += amount
print("Added fuel.")
else:
print("The tank won't hold that much!")
如果正在编写的类是另一个类的专门化版本,则可以使用继承。
当一个类从另一个类继承时,它会自动继承父类的所有属性和方法。子类可以自由地引入新的属性和方法,并覆盖父类的属性和方法。
要从另一个类继承,在定义新类时将父类的名称包含在括号中。
# 小狗类的继承
class SARDog(Dog):
"""Represent a search dog."""
def __init__(self, name):
"""Initialize the sardog."""
super().__init__(name)
def search(self):
"""Simulate searching."""
print(self.name + " is searching.")
my_dog = SARDog('Willie')
print(my_dog.name + " is a search dog.")
my_dog.sit()
my_dog.search()
# 汽车类的继承
class ElectricCar(Car):
"""A simple model of an electric car."""
def __init__(self, make, model, year):
"""Initialize an electric car."""
super().__init__(make, model, year)
# Attributes specific to electric cars.
# Battery capacity in kWh.
self.battery_size = 70
# Charge level in %.
self.charge_level = 0
class ElectricCar(Car):
--snip--
def charge(self):
"""Fully charge the vehicle."""
self.charge_level = 100
print("The vehicle is fully charged.")
my_ecar = ElectricCar('tesla', 'model s', 2016)
my_ecar.charge()
my_ecar.drive()
class ElectricCar(Car):
--snip--
def fill_tank(self):
"""Display an error message."""
print("This car has no fuel tank!")
一个类可以以对象作为属性。这允许类一起工作来建立复杂的情况。
class Battery():
"""A battery for an electric car."""
def __init__(self, size=70):
"""Initialize battery attributes."""
# 容量以千瓦时计,充电水平以%计。
self.size = size
self.charge_level = 0
def get_range(self):
"""Return the battery's range."""
if self.size == 70:
return 240
elif self.size == 85:
return 270
class ElectricCar(Car):
--snip--
def __init__(self, make, model, year):
"""Initialize an electric car."""
super().__init__(make, model, year)
# 属性是电动汽车。
self.battery = Battery()
def charge(self):
"""Fully charge the vehicle."""
self.battery.charge_level = 100
print("The vehicle is fully charged.")
my_ecar = ElectricCar('tesla', 'model x', 2016)
my_ecar.charge()
print(my_ecar.battery.get_range())
my_ecar.drive()
只要添加了详细的信息和功能,类文件就会变得很长。为了帮助保持程序文件整洁,可以将类存储在模块中,并将所需的类导入到主程序中。
car.py
"""Represent gas and electric cars."""
class Car():
"""A simple attempt to model a car."""
--snip--
class Battery():
"""A battery for an electric car."""
--snip--
class ElectricCar(Car):
"""A simple model of an electric car."""
--snip--
my_cars.py
from car import Car, ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
my_beetle.fill_tank()
my_beetle.drive()
my_tesla = ElectricCar('tesla', 'model s', 2016)
my_tesla.charge()
my_tesla.drive()
import car
my_beetle = car.Car(
'volkswagen', 'beetle', 2016)
my_beetle.fill_tank()
my_beetle.drive()
my_tesla = car.ElectricCar(
'tesla', 'model s', 2016)
my_tesla.charge()
my_tesla.drive()
from car import *
my_beetle = Car('volkswagen', 'beetle', 2016)
一个列表可以包含任意多的项,因此可以从一个类中创建大量对象并将它们存储在一个列表中。
下面是一个示例,演示如何创建一个出租车队,并确保所有的汽车都已准备就绪。
from car import Car, ElectricCar
# 列出一个车队的名单。
gas_fleet = []
electric_fleet = []
# 生产500辆汽油车和250辆电动汽车。
for _ in range(500):
car = Car('ford', 'focus', 2016)
gas_fleet.append(car)
for _ in range(250):
ecar = ElectricCar('nissan', 'leaf', 2016)
electric_fleet.append(ecar)
# 给汽车加油,给电动汽车充电。
for car in gas_fleet:
car.fill_tank()
for ecar in electric_fleet:
ecar.charge()
print("Gas cars:", len(gas_fleet))
print("Electric cars:", len(electric_fleet))