Python自学笔记(2)

整理一下Python相关内容,方便查阅。

参考用书:《Python编程:从入门到实践》,作者:Eric Matthes

第5章 用户输入和while循环

5.1 用户输入input()

函数input(str)会在屏幕上打印字符串str,然后等待用户输入。用户输入的内容被看作字符串,作为其返回值。

prompt = "If you tell us who you are, we can personalize the messages you see."
prompt += "\nWhat is your first name? "

name = input(prompt)
print("Hello, " + name + "!")

运行结果(反引号``内为键盘输入内容):

If you tell us who you are, we can personalize the messages you see.
What is your first name? `Eric`
Hello, Eric!

注意,用户输入内容会被解读成字符串,想要作为其它数据类型使用则需要进行类型转换:

age = input ("How old are you? ")
age = int(age)
print(age >= 18)

运行结果:

How old are you? `12`
False

5.2 while循环

while循环和多数高级语言思想是一样的,我们来看一个使用while循环在列表之间移动元素的例子:

unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []

while unconfirmed_users:
    current_user = unconfirmed_users.pop()
    print("Verifying user: " + current_user.title())
    confirmed_users.append(current_user)

print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
    print(confirmed_user.title())

运行结果:

Verifying user: Candace
Verifying user: Brian
Verifying user: Alice

The following users have been confirmed:
Candace
Brian
Alice

Python中也有break语句和continue语句,其用法与C语言是一致的。

第6章 函数

6.1 函数的定义

def greet_user(username):
    """显示简单的问候语"""
    print("Hello, " + username.title() + "!")

greet_user('jesse')

运行结果:

Hello, Jesse!

这里三引号中的内容被称为文档字符串,描述了函数是做什么的。Python使用它们来生成有关程序中函数的文档。

6.2 函数的参数

我们首先定义一个函数describe_pet:

def describe_pet(animal_type, pet_name):
    """显示宠物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

调用函数时,需要传递参数。传参有两种方式,分别是位置实参关键字实参

# 位置实参
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')

# 关键字实参
print('-----------------')
describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='willie', animal_type='dog')

运行结果:

I have a hamster.
My hamster's name is Harry.

I have a dog.
My dog's name is Willie.
-----------------

I have a hamster.
My hamster's name is Harry.

I have a dog.
My dog's name is Willie.

看代码就知道这两种传参方式的异同了,注意关键字实参就不需要实参与形参的位置一一对应了。

有时候,一个函数中某个参数常常是某值,我们就可以把它设为默认值,这样当不给这个参数传参时,这个参数就取默认值。具体请见下例:

def describe_pet(pet_name, animal_type='dog'):     
    # 这里最后一个参数的默认值为'dog',如果主程序中没有给animal_type传参,就默认它的值为'dog'
    """显示宠物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet('willie') # 这里使用位置实参,因此pet_name置于前部
describe_pet('willie', 'cat')
describe_pet(pet_name='harry', animal_type='hamster')

运行结果:

 
I have a dog.
My dog's name is Willie.

I have a cat.
My cat's name is Willie.

I have a hamster.
My hamster's name is Harry.

列表也可以作为参数进行传递。

可以传递任意数量的参数,仅需在参数前面加上*即可:

def make_pizza(*toppings):
    """概述要制作的比萨"""
    print("\nMaking a pizza with the following toppings:")
    for topping in toppings:
        print("- " + topping)

make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

运行结果:

 
Making a pizza with the following toppings:
- pepperoni

Making a pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese

*toppings中的*让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中,这样可以传入任意多数量的参数。

有时候,需要接受任意数量的实参,但预先不知道传递给参数的会是什么样的信息。这时可将函数编写成能够接受任意数量的键值对,调用语句提供多少就接受多少,用两个星号即可:

def build_profile(first, last, **user_info):
    """创建一个字典,其中包含我们知道的有关用户的一切"""
    profile = {}
    profile['first_name'] = first
    profile['last_name'] = last
    for key, value in user_info.items():
        profile[key] = value
    return profile


user_profile = build_profile('albert', 'einstein', location='princeton', field='physics')
print(user_profile)

运行结果:

{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}

6.3 函数的返回值

用return来返回函数的返回值。主程序中一般应有变量接收返回值。

def add(a, b):
    """对a和b求和"""
    return a+b

sum = add(1, 2)
print(sum)

运行结果:

3

6.4 将函数保存到模块中

假设模块pizza.py中编写了如下的代码:

# pizza.py

def make_pizza(size, *toppings):
    """概述要制作的比萨"""
    print("\nMaking a " + str(size) + "-inch pizza with the following toppings:")
    for topping in toppings:
        print("- " + topping)

我们在pizza.py所在的目录中另建一个文件,不妨取名为making_pizza.py。这个文件要导入模块pizza.py并使用其中的函数。

下面几个代码的运行结果均为

 
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese

(1)导入整个模块

import 模块名

# making_pizza.py

import pizza

pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12,'mushrooms', 'green peppers', 'extra cheese')

(2)导入模块中的特定函数

from 模块名 import 函数名1, 函数名2, ...

# making_pizza.py

from pizza import make_pizza

make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

注:使用*可以导入模块中的全部函数,如from pizza import *,但不建议这样做。

(3)使用as可以为函数指定别名

from 模块名 import 函数名 as 别名

# making_pizza.py

from pizza import make_pizza as mp

mp(16, 'pepperoni')
mp(12,'mushrooms', 'green peppers', 'extra cheese')

第7章 类

7.1 创建和使用类

7.1.1 创建类

下面创建一个名为Dog的类:

class Dog():
    """一次模拟小狗的简单尝试"""

    def __init__(self, name, age):
        """初始化属性name和age"""
        self.name=name
        self.age=age

    def sit(self):
        """模拟小狗被命令时坐下"""
        print(self.name.title() + " is now sitting.")

    def roll_over(self):
        """模拟小狗被命令时打滚"""
        print(self.name.title() + " rolled over!")

注意两点:

  • self前缀:类似于java中的this关键字。以self为前缀的变量可以供类中的所有方法使用,也可以通过类的任何实例来访问这些变量,它们被称为类的属性编写方法时,应当传入self参数,类中的方法通过`self.属性名`来访问和修改属性。

  • __init__ 方法:相当于java中的构造方法,用来对属性进行初始化。后面创建实例时会用到。

7.1.2 创建实例

类由属性和方法构成。类编写好后,大部分时间都将花在使用根据类创建的实例上。下面的语句将由Dog类创建两个实例my_dog和your_dog:

my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)

创建实例时,传入的参数是__init__方法中的参数列表(除self外)。

7.1.3 调用方法

类由属性和方法构成。因此实例也主要涉及对属性和方法的操作。调用方法的方式为:实例名.方法名(参数)。下面的语句将调用Dog类中的sit()和roll()方法。

my_dog.sit()
your_dog.roll()

运行结果:

Willie is now sitting.
Lucy rolled over!

7.1.4 访问和修改属性

  • 访问属性

想知道类的属性的值,可以用实例名.属性来访问属性的值。

print("My dog's name is " + my_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")

运行结果:

My dog's name is Willie.
Your dog is 3 years old.
  • 给属性指定默认值

我们新建一个名为Car的类,并为其中的odometer_reading属性指定默认值:

class Car():
    """一次模拟汽车的简单尝试"""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        # 为属性odometer_reading指定默认值(这样便无需传入包含初始值的形参)
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述性信息"""
        long_name = str(self.year) + " " + self.make + " " + self.model
        return long_name.title()

    def read_odometer(self):
        """打印一条指出汽车里程的信息"""
        print("This car has " + str(self.odometer_reading) + " mile(s) on it.")

它有四个属性,三个方法(含__init__()方法)。其中odometer_reading属性默认值为0。

  • 修改属性

我们将修改odometer_reading属性,这可以直接在实例中修改,也可以创建一个方法专门用来修改。

(1)直接修改

my_new_car = Car('audi', 'a4', 2016)    # 创建实例my_new_car
my_new_car.odometer_reading = 23        # 直接修改属性
my_new_car.read_odometer()              # 打印指出汽车里程的信息

(2)创建方法用来修改属性

我们在类中创建一个方法update_odometer():

def update_odometer(self, mileage):
    """
    将里程表读数设置为指定的值
    禁止将里程表读数往回调
    """
    if mileage >= self.odometer_reading:
        self.odometer_reading = mileage
    else:
        print("You can't roll back an odometer!")

可以通过这个方法来修改属性的值:

my_new_car.update_odometer(200)
my_new_car.read_odometer()

7.2 继承

7.2.1 继承

一个类继承另一个类时,它会获得另一个类的所有属性和方法。原有的类被称为父类,新的类被称为子类

继承的语法:class 子类名(父类名):。继承的类调用父类中的方法时,用super()来指代父类。例如,对于上面的Car类,我们想写一个ElectricCar类来继承它,同时为它添加特有的属性battery_size和特有的方法describe_battery():

class ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self, make, model, year):
        """
        电动汽车的独特之处
        初始化父类的属性,再初始化电动汽车特有的属性
        """
        super().__init__(make, model, year)
        self.battery_size = 70

    def describe_battery(self):
        """打印一条描述电瓶容量的消息"""
        print("This car has a " + str(self.battery_size) + "-kWh battery.")

7.2.2 方法重写

继承的一大目的就是重写父类中的某些方法。例如,假设父类中有方法fill_gas_tank():

# 在Car类中

def fill_gas_tank(self):
    """为油箱加油"""
    print("The gas tank has been filled up!")

而电动汽车不需要加油,因此可以在ElectricCar类中重写这个方法:

# 在ElectricCar类中

def fill_gas_tank(self):
    """电动汽车没有邮箱"""
    print("This car doesn't need a gas tank!")

7.2.3 将实例用作属性

有时候类的细节很多,可以将类的一部分提取出来,作为一个独立的类,然后将在原有的大类中写一个新的小类的实例,作为大类的一个属性。本质上还是新定义一个属性,只不过这个属性的数据类型是原有的类。

例如,我们可以给ElectricCar类中添加一个Battery类的实例:

class Car():
    ...

class Battery():
    """一次模拟电动汽车电瓶的简单尝试"""

    def __init__(self, battery_size=70):
        """初始化电瓶的属性"""
        self.battery_size = battery_size

    def describe_battery(self):
        """打印一条描述电瓶容量的信息"""
        print("This car has a " + str(self.battery_size) + "-kWh battery.")

class ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self, make, model, year):
        """
        电动汽车的独特之处
        初始化父类的属性,再初始化电动汽车特有的属性
        """
        super().__init__(make, model, year)
        self.battery = Battery()

编写如下代码:

my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()

运行结果为:

2016 Tesla Model S
This car has a 70-kWh battery.

7.3 将类保存到模块中

7.3.1 创建包含多个类的模块

建立一个名为car.py的模块,其中保存多个类:

# car.py

"""一组用于表示燃油汽车和电动汽车的类"""  # 模块级文档字符串,简述模块内容

class Car():
    """一次模拟汽车的简单尝试"""

    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """返回整洁的描述性名称"""
        long_name = str(self.year) + " " + self.make + " " + self.model
        return long_name.title()

    def read_odometer(self):
        """打印一条消息,指出汽车的里程"""
        print("This car has " + str(self.odometer_reading) + " mile(s) on it.")

    def update_odometer(self, mileage):
        """
        将里程表读数设置为指定的值
        拒绝将里程表往回拨
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

    def increment_odometer(self, miles):
        """将里程表读数增加指定的量"""
        self.odometer_reading += miles

class Battery():
    """一次模拟电动汽车电瓶的简单尝试"""

    def __init__(self, battery_size=70):
        """初始化电瓶的属性"""
        self.battery_size = battery_size

    def describe_battery(self):
        """打印一条描述电瓶容量的消息"""
        print("This car has a " + str(self.battery_size) + "-kWh battery.")

    def get_range(self):
        """打印一条描述电瓶续航里程的消息"""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270

        message = "This car can go approximately " + str(range)
        message += " miles on a full range."
        print(message)

class ElectricCar(Car):
    """模拟电动汽车的独特之处"""
    def __init__(self, make, model, year):
        """
        初始化父类的属性,再初始化电动汽车特有的属性
        """
        super().__init__(make, model, year)
        self.battery = Battery()

7.3.2 从模块中导入类

有两种导入方式:

(1)从模块中导入特定的类

from 模块名 import 类名1, 类名2, ...

实例化时仅需说明实例属于哪个类即可,例如

from car import Car, ElectricCar

my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())

my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())

注:使用*可以导入模块中的全部类,如from car import *,但不建议这样做。

(2)导入整个模块

import 模块名

实例化时需要用模块名.类名(属性值列表)的方式,例如

import car

my_beetle = car.Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())

my_tesla = car.ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())

最后,也可以在一个模块中导入另一个模块。导入方式即为上面提到的两种方式。

7.3.3 Python标准库

Python标准库是一组模块,安装的Python都包含它,只需要在程序的开头包含一条简单的import语句即可使用标准库中的函数和类。