首页 > 编程语言 >《Python从入门到实践》第九章 类

《Python从入门到实践》第九章 类

时间:2024-03-21 18:58:22浏览次数:27  
标签:__ 入门 Python self odometer 第九章 print def name

面向对象编程是最有效的软件编写方法之一

在面向对象编程时,你编写表示现实世界中的事物和情景的,并基于这些类来创建对象

根据类来创建对象称为实例化,这让你能够使用类的实例

创建和使用类

创建Dog类

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

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

    def sit(self):
        """模拟小狗收到命令时坐下"""
        print(f"{self.name} is now sitting.")

    def roll_over(self):
        print(f"{self.name} rolled over!")

在Python中,首字母大写的名称指的是类,因为这是我们创建的全新的类,所以定义时不加括号,然后是一个文档字符串,对这个类的功能做了描述

__init__() 方法

类中的函数称为方法,前面学到的有关函数的一切都适用于方法,就目前而言,唯一重要的差别是调用方法的方式。

__init__()是一个特殊方法,每当你根据Dog类创建新实例时,Python都会自动运行它,在这个方法的名称中,前后各有两个下划线,这是一种约定,是为了避免Python默认方法与普通方法发生名称冲突。

我们将__init__()方法定义成包括三个形参:self、name、age。在这个方法的定义当中,self必不可少,而且必须位于其他形参的前面,因为当Python调用这个方法来创建Dog实例时,将自然传入实参self,该实参是一个指向实例本身的引用,让实例能够访问类中的属性和方法,当我们根据Dog类创建实例时,都只需给最后两个形参(name和age提供值)。

在__init__()方法内定义的两个变量都有前缀self,以self为前缀的变量可供类中的所有方法使用,可以通过类的任意实例来访问,self.name=name获取与形参name相关联的值,并将其赋给变量name,然后该变量被关联到当前创建的实例。

self.age = age的作用与此类似,想这样可通过实例访问的变量称为属性。

Dog类还定义了另外两个方法:sit()和roll_over()。由于这些方法的执行不需要额外的信息,因此只有一个形参self.

根据类创建实例:

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

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

    def sit(self):
        """模拟小狗收到命令时坐下"""
        print(f"{self.name} is now sitting.")

    def roll_over(self):
        print(f"{self.name} rolled over!")


my_dog = Dog('rich', 8)
print(f"My dog's name is {my_dog.name}")
print(f"My dog is {my_dog.age} years old")

访问属性:

my_dog.name

调用方法

my_dog = Dog('rich', 8)
my_dog.sit()
my_dog.roll_over()

练习9.1:

class Restaurant:
    def __init__(self,restaurant_name,cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type

    def describe_restaurant(self):
        print(f"restaurant's name is {self.restaurant_name}")
        print(f"cuisine_type is {self.cuisine_type}")

    def open_restaurant(self):
        print(f"{self.restaurant_name.title()} is opening")


restaurant = Restaurant('dongbei BBQ', 'dun')
restaurant.describe_restaurant()
restaurant.open_restaurant()

练习9.3

class User:
    def __init__(self, first_name, last_name, age, phone_number):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.phone_number = phone_number
        self.username = f"{self.first_name} {self.last_name}"

    def describe_user(self):
        print(f"user's name is {self.username}")
        print(f"{self.username} is {self.age} years old")
        print(f"{self.username}'s phone number is {self.phone_number}")

    def greet_user(self):
        print(f"Hello, {self.username}")


user1 = User('xiong', 'jiajin', 13, 110)
user1.describe_user()
user1.greet_user()

注意:一个类中所有的变量都要在__init__()中定义并完成初始化

使用类和实例

类编写好后,你的大部分时间将花在使用根据类创建的实例上,你需要完成的首要任务之一是,修改实例的属性。

既可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。

class Car:
    """一次模拟汽车的简单尝试"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

    def get_descriptive_name(self):
        """返回格式规范的描述性信息"""
        long_name = f"{self.year} {self.make} {self.model}"
        return long_name


my_new_car = Car('audi', 'A6', 2023)
print(my_new_car.get_descriptive_name())

给属性指定默认值

有些属性无须通过形参来定义,可以在__init__()方法中为其指定默认值,如下

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")


my_new_car = Car('audi', 'A6', 2023)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()

但是实际上出售时里程读表为0的汽车不多,因此需要修改改属性。

修改属性的值

可以用三种不同的方式修改属性的值:直接通过实例修改,通过方法设置,以及通过方法递增(增加特定的值)。下面一次介绍这些方式

①直接修改属性的值

要修改属性里的值,最简单方式是通过实例直接访问它

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")


my_new_car = Car('audi', 'A6', 2023)
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23
my_new_car.read_odometer()

②通过方法修改属性的值

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = mileage


my_new_car = Car('audi', 'A6', 2023)
print(my_new_car.get_descriptive_name())

my_new_car.update_odometer(26)
my_new_car.read_odometer()

还可以对update_odometer()方法进行扩展,使其在修改里程表读书时做一些额外的工作,比如添加一些逻辑,禁止里程表读数往回调整:

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

③通过方法让属性的值递增

有时候需要将属性值递增特定的量,而不是将其设置为全新的值。

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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


my_new_car = Car('audi', 'A6', 2023)
print(my_new_car.get_descriptive_name())

my_new_car.update_odometer(26)
my_new_car.read_odometer()
my_new_car.increment_odometer(100)
my_new_car.read_odometer()

练习9.4:

class Restaurant:
    def __init__(self, restaurant_name, cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type
        self.number_served = 0

    def describe_restaurant(self):
        print(f"restaurant's name is {self.restaurant_name}")
        print(f"cuisine_type is {self.cuisine_type}")

    def open_restaurant(self):
        print(f"{self.restaurant_name.title()} is opening")

    def set_number_served(self, number_served_set):
        if number_served_set >= self.number_served:
            self.number_served = number_served_set
        else:
            print("you enter a wrong statistic")

    def increment_number_served(self, increment_number):
        if increment_number >= 0:
            self.number_served += increment_number
        else:
            print("the number input is less than zero")


restaurant = Restaurant('dongbei BBQ', 'dun')
restaurant.describe_restaurant()
restaurant.open_restaurant()
restaurant.number_served = 136
print(f"{restaurant.number_served} people have been served in {restaurant.restaurant_name}")
restaurant.set_number_served(147)
print(f"{restaurant.number_served} people have been served in {restaurant.restaurant_name}")
restaurant.increment_number_served(9)
print(f"{restaurant.number_served} people have been served in {restaurant.restaurant_name}")

练习9.5:

class User:
    def __init__(self, first_name, last_name, age, phone_number):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.phone_number = phone_number
        self.username = f"{self.first_name} {self.last_name}"
        self.log_attempts = 0

    def describe_user(self):
        print(f"user's name is {self.username}")
        print(f"{self.username} is {self.age} years old")
        print(f"{self.username}'s phone number is {self.phone_number}")

    def greet_user(self):
        print(f"Hello, {self.username}")

    def increment_login_attempts(self):
        self.log_attempts += 1

    def reset_login_attempts(self):
        self.log_attempts = 0


user1 = User('xiong', 'jiajin', 13, 110)
user1.describe_user()
user1.greet_user()
user1.increment_login_attempts()
user1.increment_login_attempts()
print(user1.log_attempts)
user1.reset_login_attempts()
print(user1.log_attempts)

继承:

在编写类时,并非总要从头开始,如果编写的类是一个既有的类的特殊版本,可以使用继承。当一个类继承另一个类。当一个类继承另一个类时,将自动获得后者的所有属性和方法。原有的类称为父类,而新类称为子类。子类不仅继承父类的所有属性和方法,还可以定义自己的属性和方法。

①子类__init__()方法

在既有的类的基础上编写新类,通常要调用父类的__init__()方法。这将初始化在父类的__init__()方法中定义的所有属性,从而让子类也可以使用这些属性。

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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 ElectricCar(Car):
    """电动汽车的独到之处"""
    def __int__(self, make ,model, year):
        """初始化父类的属性"""
        super().__init__(make, model, year)


my_leaf = ElectricCar('nissan', 'leaf', 2023)
print(my_leaf.get_descriptive_name())

在创建子类时,父类必须包含在当前文件中,并且位于子类的前面,在定义子类时,必须在括号内指定父类的名称,__init__()方法接受创建Car实例所需的信息。

super()是一个特殊的函数,让你能够调用父类的方法,从而让ElectricCar实例包含这个方法定义的所有属性,父类也称为超类,函数名super由此得名。

给子类定义属性和方法

让一个类继承另一个类后,就可以添加区分子类和父类所需的新属性和新方法

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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 ElectricCar(Car):
    """电动汽车的独到之处"""
    def __int__(self, make, model, year):
        """
        先初始化父类的属性,在初始化电动车特有的属性
        """
        super().__init__(make, model, year)
        self.battery_size = 20

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


my_leaf = ElectricCar('nissan', 'leaf', 2023)
print(my_leaf.get_descriptive_name())
my_leaf.battery_size = 50
my_leaf.describe_battery()

重写父类中的方法:

再使用子类模拟实物的行为时,如果父类中的一些方法不能满足子类的需求,就可以用下面的办法重写:再子类中定义一个与要重写的父类方法同名的方法,这样Python将忽略这个父类方法,之关注你在子类中定义的相应方法。

将实例用作属性

在使用代码模拟实物时,你可能会发现自己给类添加了太多细节:属性和方法越来越多,文件越来越长。在这种情况下,可能需要将类的一部分提取出来,作为一个独立的类。将大型类拆分成多个协同工作的小类,这种方法称为组合。

一定要注意区分__init__()  和  __int__(),并且两边都是有两个下划线

例如:

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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=40):
        self.battery_size = battery_size

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


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


my_leaf = ElectricCar('nissan', 'leaf', 2023)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()

我们定义了一个名为Battery的新类,它没有继承任何类,__init__()方法在self之外还有一个形参battery_size。这个形参是可选的:如果没有给它提供值,电池容量将被设置为40,describe_battery()方法也被移到了这个类中。

在ElectricCar类中,添加一个名为self.battery的属性,这行代码让Python创建一个新的Battery实例(因为没有指定容量,所以默认值为40),并将该实例赋给属性self.battery。每当__init__()方法被调用时,都将执行该操作,因此现在每个ElectricCar实例都包含一个自动创建的Battery实例。

这看似做了很多额外的工作,但是现在想多详细地描述电池都可以,且不会导致ElectricCar类混乱不堪。

下面再给Battery类添加一个方法,它更具电池容量报告汽车的续航里程:

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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=40):
        self.battery_size = battery_size

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

    def get_range(self):
        """打印一条消息,指出电池的续航里程"""
        if self.battery_size == 40:
            range = 150
        elif self.battery_size ==65:
            range =225
        print(f"This car can go about {range} miles on a full charge")


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


my_leaf = ElectricCar('nissan', 'leaf', 2023)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()

模拟实物:

对现实世界的建模方法没有对错之分,有些方法的效率更高,但要找出效率最高的表示法,需要一定的实践,只要代码能够像你希望的那样运行,就说明你已经做得很好了!

练习9.6

class Restaurant:
    def __init__(self,restaurant_name,cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type
        self.flavors = ['orange', 'milk', 'apple']

    def describe_restaurant(self):
        print(f"restaurant's name is {self.restaurant_name}")
        print(f"cuisine_type is {self.cuisine_type}")

    def open_restaurant(self):
        print(f"{self.restaurant_name.title()} is opening")

    def describe_flavor(self):
        for flavor in self.flavors:
            print(f"{self.restaurant_name} provide {flavor} ice-cream")


restaurant = Restaurant('dongbei BBQ', 'dun')
restaurant.describe_restaurant()
restaurant.open_restaurant()

IceCreamStand = Restaurant('蜜雪冰城', '冰淇淋店')
IceCreamStand.describe_flavor()

练习9.7

class User:
    def __init__(self, first_name, last_name, age, phone_number):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.phone_number = phone_number
        self.username = f"{self.first_name} {self.last_name}"
        self.log_attempts = 0
        self.privileges = ['can add post', 'can delete post', 'can ban user']

    def describe_user(self):
        print(f"user's name is {self.username}")
        print(f"{self.username} is {self.age} years old")
        print(f"{self.username}'s phone number is {self.phone_number}")

    def greet_user(self):
        print(f"Hello, {self.username}")

    def increment_login_attempts(self):
        self.log_attempts += 1

    def reset_login_attempts(self):
        self.log_attempts = 0

    def show_privileges(self):
        for privilege in self.privileges:
            print(f"{self.username}'s privileges include {privilege}")


user1 = User('xiong', 'jiajin', 13, 110)
user1.show_privileges()

练习9.8

class User:
    def __init__(self, first_name, last_name, age, phone_number):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.phone_number = phone_number
        self.username = f"{self.first_name} {self.last_name}"
        self.log_attempts = 0

    def describe_user(self):
        print(f"user's name is {self.username}")
        print(f"{self.username} is {self.age} years old")
        print(f"{self.username}'s phone number is {self.phone_number}")

    def greet_user(self):
        print(f"Hello, {self.username}")

    def increment_login_attempts(self):
        self.log_attempts += 1

    def reset_login_attempts(self):
        self.log_attempts = 0


class Privileges:
    def __init__(self):
        self.privileges = ['can add post', 'can delete post', 'can ban user']

    def show_privileges(self):
        for privilege in self.privileges:
            print(f"manager's privileges include {privilege}")


class Admin(User):
    def __init__(self, first_name, last_name, age, phone_number):
        super().__init__(first_name, last_name, age, phone_number)
        self.privilege = Privileges()


user1 = Admin('xiong', 'jiajin', 13, 110)
user1.privilege.show_privileges()

super().__init__()后面不含有self

练习9.9

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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=40):
        self.battery_size = battery_size

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

    def get_range(self):
        """打印一条消息,指出电池的续航里程"""
        if self.battery_size == 40:
            range = 150
        elif self.battery_size ==65:
            range =225
        print(f"This car can go about {range} miles on a full charge")

    def upgrade_battery(self):
        if self.battery_size != 65:
            self.battery_size = 65


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


my_leaf = ElectricCar('nissan', 'leaf', 2023)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()
my_leaf.battery.upgrade_battery()
my_leaf.battery.get_range()

导入类:

①导入单个类

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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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

允许将类存储在模块中,然后再主程序中导入所需的模块

my_car.py

from car import Car

my_new_car = Car('audi', 'A6', '2024')
print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23
my_new_car.read_odometer()

从car.py中导入类Car,这让你的主程序文件变得整洁易读,还让你能够将大部分逻辑存储在独立的文件中。

②在一个模版中存储多个类

尽管同一个模块中的类之间应该存在某种相关性,但其实可以根据需要在一个模块中存储任意数量的类。Battery类和ElectricCar类都可帮助模拟汽车,下面将它们都加入模块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 = f"{self.year} {self.make} {self.model}"
        return long_name

    def read_odometer(self):
        """打印一条指出汽车行驶里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it")

    def update_odometer(self, mileage):
        """将里程表设置为指定的数"""
        self.odometer_reading = 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=40):
        self.battery_size = battery_size

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

    def get_range(self):
        """打印一条消息,指出电池的续航里程"""
        if self.battery_size == 40:
            range = 150
        elif self.battery_size ==65:
            range =225
        print(f"This car can go about {range} miles on a full charge")

    def upgrade_battery(self):
        if self.battery_size != 65:
            self.battery_size = 65


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

主程序:

my_car.py

from car import ElectricCar

my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()

从一个模块中导入多个类:

可以根据需要再程序文件中导入任意数量的类。如果要在同一个程序中创建燃油汽车和电动汽车,就需要将Car类和ElectricCar类都引入

from car import ElectricCar,Car

my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()

my_mustang = Car('ford', 'mustang', 2024)
print(my_mustang.get_descriptive_name())

当从一个模块中导入多个类时,用逗号分隔各个类。导入必要的类后,就可根据需要创建每个类的任意数量的实例了

导入整个模块

还可以先导入整个模块,再使用点好访问需要的类。这种导入方法很简单,代码也易读,由于创建类实例的代码都包含模块名,因此不会与当前文件使用的任何名称发生冲突。

import car

my_leaf = car.ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()

my_mustang = car.Car('ford', 'mustang', 2024)
print(my_mustang.get_descriptive_name())

导入模块中的所有类:

要导入模块中的每个类,可使用下面的语法:

from module_name import *

不推荐这种导入方式:

一方面最好只看一下文件开头的import语句,就能清楚地知道程序使用了哪些类,但这种导入方式没有明确地指出使用了模块中的哪些类。

另一方面,这种导入方式还可能引发名称方面的迷惑,如果一不小心导入了一个与程序文件中的其他东西同名的类,将引发难易诊断的错误。

但是我们还是要去了解这种导入方式,因为我们可能在别人编写的代码中见到它

在一个模块中导入另一个模块

有时候,需要将类分散到多个模块中,以免模块太大或者在同一个模块中存储不相关的类,在将类存储在多个模块中时,你可能会发现一个模块中的类依赖于另一个模块中的类,在这种情况下,可在前一个模块中导入必要的类。

现在可以分别从每个模块中导入类,以根据需要创建任意类型的汽车了

from car import Car

from electric_car import ElectriCar

使用别名

给类指定别名

from electric_car import ElectricCar as EC

给模块指定别名

import electric_car as ec

找到合适的工作流程

一开始应让代码结构尽量简单,首先尝试在一个文件中完成所有的工作,确定一切都能正确运行后,在将类移到独立的模块中国,如果你喜欢模块和文件的交互方式,可在项目开始时就尝试将类存储到模块中。先找出让你能够编写出可行代码的方式,再尝试让代码更加整洁。

练习9.11

import statistic
user1 = statistic.Admin('xiong', 'haha', 18, 110)
user1.privilege.show_privileges()

练习9.12

statistic.py

class User:
    def __init__(self, first_name, last_name, age, phone_number):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.phone_number = phone_number
        self.username = f"{self.first_name} {self.last_name}"
        self.log_attempts = 0

    def describe_user(self):
        print(f"user's name is {self.username}")
        print(f"{self.username} is {self.age} years old")
        print(f"{self.username}'s phone number is {self.phone_number}")

    def greet_user(self):
        print(f"Hello, {self.username}")

    def increment_login_attempts(self):
        self.log_attempts += 1

    def reset_login_attempts(self):
        self.log_attempts = 0

admin.py

import statistic


class Privileges:
    def __init__(self):
        self.privileges = ['can add post', 'can delete post', 'can ban user']

    def show_privileges(self):
        for privilege in self.privileges:
            print(f"manager's privileges include {privilege}")


class Admin(statistic.User):
    def __init__(self, first_name, last_name, age, phone_number):
        super().__init__(first_name, last_name, age, phone_number)
        self.privilege = Privileges()

main_idea.py

import admin
user1 = admin.Admin('xiong', 'haha', 18, 110)
user1.privilege.show_privileges()

Python标准库

python标准库是一组模块,在安装Python时以及包含在内。

我们可以使用标准库中的任何函数和类,只需在程序开头添加一条简单的import语句即可

例如模块random:

random中的一个有趣的函数是randint()。她将两个整数作为参数,并随机返回一个位于这两个整数之间(含)的整数。

from random import randint

print(randint(1, 6))

另一个很有用的参数是choice(),它将一个列表或元组作为参数,并随机返回其中一个元素

from random import choice

players = ['LBL', 'kari', 'KOBE', 'jordan']
first_up = choice(players)
print(first_up)

还可以从其他地方下载外部模块!

练习9.13

from random import randint


class Die:
    def __init__(self, sides):
        self.sides = sides

    def roll_die(self):
        print(randint(1, self.sides))


die1 = Die(6)
die1.roll_die()

die2 = Die(10)
die2.roll_die()

die3 = Die(20)
die3.roll_die()

练习9.14

from random import choice

statis = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'x', 'l', 'j', 'z', 'h']


def open_result(group):
    number = 0
    while number < 4:
        number += 1
        print(choice(group))


open_result(statis)

练习9.15

from random import choice

statis = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'x', 'l', 'j', 'z', 'h']

my_ticket = ['x', 'j', '3', '0']


def open_result(group):
    price_result = []
    number = 0
    while number < 4:
        number += 1
        price_result.append(choice(group))
    print(price_result)
    return price_result


number1 = 0
open_number = []
while open_number != my_ticket:
    number1 += 1
    open_number = open_result(statis)


print(f"循环了{number1}次才中奖了")

要了解Python标准库,一个很不错的资源是网站Python 3 Module of the Week

类的编程风格

类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,并且不适用下划线。

实例名和模块名都采用全小写格式,并在单词之间加上下划线。

对于每个类,都应该在类定义后面紧跟一个文档字符串,简要地描述类的功能。

每个模块后也都应包含一个文档字符串,对其中的类可用来做什么进行描述

在类中,可以使用一个空行来分隔方法

在模块中,可以使用两个空行来分隔类

当需要同时导入标准库中的模块和你编写的模块时,先编写导入标准模块的import语句,再添加一个空行,然后编写导入你自己编写的模块的import语句。这样让人更容易明白程序使用的模块来自哪里

标签:__,入门,Python,self,odometer,第九章,print,def,name
From: https://blog.csdn.net/a_bear_in_Spring/article/details/136783216

相关文章

  • python代码小题(4)
    #输出等腰三角形i=1whilei<=5:print(""*(5-i),end="")j=1whilej<=2*i-1:print("*",end="")j+=1print("")i+=1#for循环输出9*9乘法表forjinrange(1,10):......
  • nginx入门-31-学习笔记
    nginx入门-31-学习笔记环境环境:虚拟机ip:10.0.1.0网关:10.0.1.2子网掩码:255.255.255.0测试机器ip:10.0.1.101概念1.安装nginx软件安装:yum安装yuminstallepel-releaseyuminstallnginx-ysystemctlstartnginx编译安装(生产环境)yum-yinstallpcr......
  • Python的特点是什么?
    一、Python的特点是什么?Python是一种广泛使用的编程语言,具有许多引人注目的特点,以下是Python的主要特点:简单易学:Python的语法清晰明了,易于学习,这使得初学者能够快速上手。此外,Python的代码可读性强,易于编写和理解。面向对象:Python支持面向对象的编程范式,这使得开发者能够创建......
  • requests.post传的data如果是直接使用python dict封装,有些服务端接收不了这种数据类型
    平时在自己的php项目里,使用dict方式组装data,然后requests.post,一点问题都没有。但是调了后端一个java的微服务接口,结果就一直报错422: 最后问了一下开发,得到提示“python好像还有个毛病,python的json对象转字符串的时候,转出来的字符串不是标准json字符串,还要做个字符串处理,变成......
  • Python爬虫-数据采集和处理
    文章目录数据数据类型数据分析过程数据采集数据采集源数据采集方法数据清洗清洗数据数据集成数据转换数据脱敏数据《春秋左传集解》云:“事大大其绳,事小小其绳。”体现了早期人类将事情的“大小”这一性质抽象到“绳结大小”这一符号上从而产生数据的过程。数据......
  • Python安全脚本之自动化子域名收集
    声明:本工具仅用于日常学习使用,禁止用于非法域名收集,否则后果由使用者承担!!!在信息收集中少不了一些脚本的辅助,本文将讲解如何编写一个自动化子域名收集脚本代码及注释如下:fromconcurrent.futuresimport*importrequestsbanner='''_________......
  • 解决[TSP旅行商]问题,请列出[4]个可以用[Python]编程的优化路径算法,展开写出这[4]个算
    TSP(旅行商问题)是一个经典的组合优化问题,其目标是找到访问所有城市并返回起点的最短可能路线。在Python中,有多种算法可以用来解决TSP问题,以下是四个常用的算法及其编程难度级别、时间复杂度和所需的库:回溯法(Backtracking)编程难度级别:中等时间复杂度:指数级,因为需要遍历所有......
  • python操作kafka
    目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细节2.1生产者demo2.2消费者demo2.3消费者(消费群组)2.4消费者(读取目前最早可读的消息)2.5消费者(手动设置偏移量)2.6消费者(订阅多个主题)......
  • python 多进程并发:生产者+多消费者模式
    多任务场景中,为了节省大量子任务串行执行的耗时,通常采用并发方式充分利用cpu和内存来节省整体任务运行时间。对于多任务并发,常见的做法自然是抽象出功能函数,借助multiprocess类在主进程中并发出多个子进程,或者构建进程池,将任务构造好后丢入进程池中来实现并发。这种方式对于......
  • python 异常捕获、断言(assert 、finally) 与日志(loguru.logger)
    异常捕获常见的异常类型代码执行顺序从上到下依次运行的,如果出错了,后面的代码不会出错。--所以要对异常做处理。常见的异常的类型,不需要记;平时写代码的时候经常会报错,积累常见错误,排查问题。常见异常的报错的类型:NameError,IndexError,KeyError,ValueError,ZeroDivisionE......