Python-基础入门-学习笔记(5):函数和类
一、函数
函数是带名字的代码块,用于完成具体的工作。
1、定义函数
def greet_user(): #定义函数
·······
greet_user() #调用函数
在冒号之后的所有缩进行构成了函数体。
(1)向函数传递信息
将需要传递的值写在括号内,即可。
def greet_user(username): #其中username接受我们指定的任意值
(2)实参和形参
变量username相当于形参,即函数完成其工作所需的一项信息;而值’jesse’相当于实参,即用户想要赋的值。
传递时,是将实参赋给形参
练习
2、传递实参
函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。
(1)位置实参
关联方式是基于实参的顺序。
def describe_pet(animal_type, pet_name):
······
describe_pet('hamster','harry')
位置实参的顺序千万不能反
(2)关键字实参
关键字实参是传递给函数的名称-值对。
def describe_pet(animal_type, pet_name):
······
describe_pet(animal_type='hamster', pet_name='harry')
这样的做法可以避免对应错误问题
(3)默认值
给形参指定默认值后,可在函数调用中省略相应的实参。
# 将动物类型默认为
def describe_pet(animal_type='dog', pet_name):
······
describe_pet(pet_name='harry')
如果显示地给animal_type赋值的话,将会覆盖掉默认值
练习
3、返回值
函数返回的值被称为返回值,在函数中,可使用return语句将值返回到调用函数的代码行。
def get_formatted_name(first_name,last_name):
"""返回整洁的姓名"""
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi','hendrix')
print(musician)
上述代码将full_name的值转换为首字母大写,并将结果返回到函数调用行。
调用返回值的函数时,需要提供一个变量,用于存储返回的值。
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
练习
4、传递函数
(1)将列表传递给函数后,函数就能直接访问其内容。
def greet_users(names):
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hannah','ty','margot']
#将列表传递给函数
greet_users(usernames)
(2)将列表传递给函数后,函数就可对其进行修改,这个修改是永久性的。
类似于C语言中封装某个函数(.c和.h文件),并在main函数中进行调用,调用时执行该函数,并将返回值重新赋给主函数。这有助于将复杂的任务划分成一系列的步骤,并且调用灵活。
(3)如果要禁止函数修改列表,可向函数传递列表的副本而不是原件;这样函数所做的任何修改都只影响副本,而丝毫不影响原件。
#切片表示法[:]创建列表的副本,函数所做的修改不会影响到列表本身。
function_name(list_name[:])
如果没有特殊要求,尽量使用原始版本,因为会避免花时间和内存创建副本,从而提高效率。
练习
5、传递任意数量的实参
def make_pizza(*toppings):
"""打印顾客点的所有配料"""
print(toppings)
make_pizza('a','b','c')
形参名*topping中的星号让Python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中。
不论收到的实参是多少个,都适用。
(1)当结合位置实参时,需要将位置实参放在前面,将任意数量的实参放到后面。
def make_pizza(size,*toppings):
(2)有时候使用任意数量的实参,可将函数编写成能够接受任意数量的键-值对。
def build_profile(first,last,**user_info)
形参**user_info中的两个星号让Python创建一个名为user_info的空字典。
练习
6、将函数存储在模块中
将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。
(1)导入整个模块
首先先将要封装的函数存储在一个单独的文件中,例如pizza.py,接下来我们在pizza.py目录下创建另一个名为making_pizza.py的文件,再进行调用。
import pizza #调用pizza.py文件
pizza.make_pizza(16,'pepperoni') #指定导入模块名称和函数名,用点隔开
代码import让Python打开文件 pizza.py,并将其中的所有函数都赋值到这个程序中,但是看不到代码。
(2)导入特定的函数
from module_name import function_name
导入module_name中的特定函数function_name
from module_name import function_0,function_1,function_2
导入module_name中的某三个函数
使用这种方法时,不用在下方进行(模块.函数名)的操作。
(3)使用as给函数指定别名
from pizza import make_pizza as mp
类似于给函数起个外号,从模块pizza中取函数make_pizza函数,并给它取名为mp。
在接下来调用时,则调用函数mp即可,通常是函数名的前几个字母的缩写。
(4)使用as给模块指定别名
import pizza as p
p.make_pizza(16,'pepperoni')
(5)导入模块中的所有函数
from pizza import *
这种方法可将pizza模块中的每个函数都复制到这个程序文件中。
最佳做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。
练习
(1)首先创建一个包括所调用函数的模块。
(2)之后将子模块和主模块放在同一个文件夹下。
(3)在主模块中调用子模块。
结果证明,均能实现!
二、类
1、创建和使用类
基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。类是一个整体,表示的不是某个事物,而是这个事物的任意事物。
例如创建一个小狗的类,它表示的不是一个小狗,而是任意小狗:
class Dog(): #首字母大写的名称为类
"""一次模拟小狗的简单尝试"""
#每当根据Dog类创建新实例时,都会自动运行
def __init__(self,name,age): #self是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
"""初始化属性name和age"""
self.name = name #获取存储在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!")
类中的函数_init_ 称为方法,与函数的唯一差别就是调用方式不同,通过前后添加下划线的方法,避免Python默认方法与普通方法发生名称冲突。
如果运行后出现错误:take no arguments。那么请检查init左右两个有几个下划线,正确的为左右各两个!!!!!!
命名规则:首字母大写的名称指的是类,小写的名称指的是根据类创建的实例。
(1)访问属性:可使用句点表示法。
my_dog.name
(2)调用方法:在根据类创建完实例之后,就可以使用类中的语句进行控制了。
class Dog():
--snip--
my_dog = Dog('willie',6)
my_dog.sit() #让XX打滚(其中XX是你定义好的小狗的名字)
我们还可以同时创建多个实例,同时执行,例如你还可以添加这么一行代码:
your_dog = Dog('lucy',3)
同样会执行上述命令,只不过名字和年龄发生了改变。
练习
2、使用类和实例
实例的属性可以直接修改,也可以编写方法以特定的方式进行修改。
(1)给属性指定默认值
class Car():
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0 #给属性赋初值为0
def get_descriptive_name(self):
--snip--
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has " + str(self.odometer_reading) + "miles on it.")
my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
可以在方法__init__中规定属性初值。
(2)修改属性的值
方法一:直接修改属性的值
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
方法二:通过方法修改属性的值
class Car():
--snip--
def update_odometer(self,mileage):
"""将里程表读数设置为指定的数"""
self.odometer_reading = mileage
my_new_car.update_odometer(23)
通过添加一个专门用来修改属性的方法来进行修改。
方法三:通过方法对属性的值进行递增
......
def increment_odometer(self,miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
这样可以保证不是给属性赋一个全新的值,而是在原有的基础上进行改变。
练习
#设置和修改属性的默认值
class Restaurant():
"""创建一个餐馆的类"""
def __init__(self,restaurant_name,cuisine_type):
"""初始化属性"""
self.name = restaurant_name
self.type = cuisine_type
#添加一个属性并赋初值
self.number_served = 0
def describe_restaurant(self):
"""打印餐馆信息"""
print("The restaurant " + self.name.title() + " is " + self.type.title())
def open_restaurant(self):
"""打印餐馆营业信息"""
print("The restaurant " + self.name.title() + " is now opening!")
def read_number(self):
"""打印就餐人数"""
print("The restaurant has " + str(self.number_served) + " people.")
def set_number_served(self,number):
"""修改属性的值"""
self.number_served = number
def increment_number_served(self,number):
"""将人数增加指定的人"""
self.number_served += number
#属性赋初值
my_restaurant = Restaurant('KFC','fast food')
#调用方法
my_restaurant.describe_restaurant()
my_restaurant.open_restaurant()
#方法一:直接修改属性的值
my_restaurant.number_served = 1
my_restaurant.read_number()
#方法二:通过方法修改属性的值
my_restaurant.set_number_served(2)
my_restaurant.read_number()
#方法三:通过方法对属性的值进行递增
my_restaurant.increment_number_served(1)
my_restaurant.read_number()
class User():
"""创建一个用户的类"""
def __init__(self,first_name,last_name,age,country):
"""初始化属性"""
self.name = first_name + last_name
self.age = age
self.country = country
self.login_attempts = 0
def describe_user(self):
"""打印用户信息"""
print("The user " + self.name.title() + " is " + str(self.age) +
" years old,and live in " + self.country.title()
)
def greet_user(self):
"""打印欢迎信息"""
print("\nHello! " + self.name.title())
def increment_login_attempts(self):
"""将属性的值加1"""
self.login_attempts += 1
def reset_login_attempts(self):
"""将属性的值归零"""
self.login_attempts = 0
def printing_attempts(self):
"""打印属性的值"""
print(self.login_attempts)
my_user = User('Bill ','Gates',24,'china')
my_user.describe_user()
my_user.greet_user()
my_user.printing_attempts() #打印为0
my_user.increment_login_attempts() #0+1=1
my_user.increment_login_attempts() #1+1=2
my_user.increment_login_attempts() #2+1=3
my_user.printing_attempts() #打印为3
my_user.reset_login_attempts() #清零
my_user.printing_attempts() #打印为0
3、继承
编写类时,并非要从空白开始,如果是另一个现成类的特殊版本,可使用继承。一个类继承另一个类,将自动获得另一个类的所有属性和方法;原有的类成为父类,新类成为子类。
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.name + ' ' +self.model
return long_name.title()
def read_odometer(self):
print("This car has " + str(self.odometer_reading) + " miles 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 incremeter_odometer(self,miles):
self.odometer_reading +=miles
class ElectricCar(Car):
"""电动车的独特之处"""
def __init__(self,make,model,year)
"""初始化父类属性"""
super().__init__(make,model,year) #super函数帮助Python将父类和子类关联起来。
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
创建子类时,父类必须包含在当前文件夹中,且位于子类前面。
(1)给子类定义属性和方法
#前面相同
.........
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.")
......#之后再调用即可
我们将新添加的属性写到了class ElectricCar(Car)中,即写到了子类中,所以父类不具备该属性。如果要想使父类和子类同时具有某属性,那么将属性添加到父类中即可。
(2)重写父类的方法
可在子类中定义一个方法与父类中的方法同名,那么可以将父类方法重写。
练习
#继承之给子类添加属性
class Restaurant():
"""创建一个餐馆的类"""
def __init__(self,restaurant_name,cuisine_type):
"""初始化属性"""
self.name = restaurant_name
self.type = cuisine_type
def describe_restaurant(self):
"""打印餐馆信息"""
print("The restaurant " + self.name.title() + " is " + self.type.title())
def open_restaurant(self):
"""打印餐馆营业信息"""
print("The restaurant " + self.name.title() + " is now opening!")
#父类为Restaurant,子类为IceCreamStand
class IceCreamStand(Restaurant):
"""冰激凌小店的独特之处"""
def __init__(self,restaurant_name,cuisine_type,flavors):
"""初始化父类属性"""
super().__init__(restaurant_name,cuisine_type)
self.flavors = flavors
def describe_flavors(self):
"""打印冰激凌的风味"""
print("The icecream's flavor is " + self.flavors)
#属性赋初值
my_restaurant = IceCreamStand('KFC','fast food','strawberry')
#调用方法
my_restaurant.describe_restaurant()
my_restaurant.open_restaurant()
#创建实例并调用它
my_restaurant.describe_flavors()
#继承之创建实例并调用
class User():
"""创建一个用户的类"""
def __init__(self,first_name,last_name,age,country):
"""初始化属性"""
self.name = first_name + last_name
self.age = age
self.country = country
def describe_user(self):
"""打印用户信息"""
print("The user " + self.name.title() + " is " + str(self.age) +
" years old,and live in " + self.country.title()
)
def greet_user(self):
"""打印欢迎信息"""
print("Hello! " + self.name.title())
#父类为User,子类为Admin
class Admin(User):
def __init__(self,first_name,last_name,age,country,privileges):
super().__init__(first_name,last_name,age,country)
self.privileges = privileges
def show_privileges(self):
print("\nYou can "+ self.privileges)
#创建实例
my_user = Admin('Bill ','Gates',24,'china','add post')
#调用方法
my_user.describe_user()
my_user.greet_user()
my_user.show_privileges()
#继承之实例用作属性
class User():
"""创建一个用户的类"""
def __init__(self,first_name,last_name,age,country):
"""初始化属性"""
self.name = first_name + last_name
self.age = age
self.country = country
def describe_user(self):
"""打印用户信息"""
print("The user " + self.name.title() + " is " + str(self.age) +
" years old,and live in " + self.country.title() + "."
)
def greet_user(self):
"""打印欢迎信息"""
print("Hello! " + self.name.title() + ".")
class Privileges():
"""编写一个只有特权属性的类"""
def __init__(self,privileges='add post'):
self.privileges = privileges
def show_privileges(self):
print("\nYou can " + self.privileges)
#父类为User,子类为Admin
class Admin(User):
def __init__(self,first_name,last_name,age,country):
super().__init__(first_name,last_name,age,country)
self.privileges = Privileges()
#创建实例
my_user = Admin('Bill ','Gates',24,'china')
#调用方法
my_user.describe_user()
my_user.greet_user()
my_user.privileges.show_privileges()
4、导入类
(1)导入单个类
假设我们创建了一个Car类,并保存在模块car.py中,在导入该类时我们可以这样写:
form car import Car #从模块car中导入类Car
导入之后就相当于Car类是这个文件中定义的一样,所以Car类中所包含的方法可以直接使用。
(2)在一个模块中存储多个类
如果在car.py中存储多个类,如下所示:
class Car():
--snip--
class Battery():
--snip--
class ElectricCar(Car):
--snip--
我们要是想导入某一个类,可以这样做:
from car import ElectricCar
........
(3)从一个模块中导入多个类
from car import Car,ElectricCar #导入了Car和ElectricCar这两个类
......
(4)导入整个模块
import car #导入整个car模块
......
#在使用时记得用'.'号访问类
my_bettle = car.Car('volkswagen','bettle',2016)
my_tesla = car.ElectricCar('tesla','roadster',2016)
(5)导入模块中的所有类
from cao import * #导入整个car模块
......
尽量不使用导入模块中所有类的方法,因为不清晰,容易引发错误。
(6)在一个模块中导入另一个模块
如果发现一个模块中的类依赖于另一个模块中的类,可在前一个模块中中导入必要的类。
假设子类Battery和ElectricCar需要用到父类Car,那么我们必须要先从Car模块中调用Car父类,才可以正常使用。
一般先尽可能在一个文件中完成所有的工作,确定一切都能正常运行后,再将类移到独立的模块中。
练习
(1)导入单个类
首先建立一个单独的模块,只存储一个类
restaurant.py
"""一组用于描述餐厅信息的类"""
class Restaurant():
"""创建一个餐馆的类"""
def __init__(self,restaurant_name,cuisine_type):
"""初始化属性"""
self.name = restaurant_name
self.type = cuisine_type
def describe_restaurant(self):
"""打印餐馆信息"""
print("The restaurant " + self.name.title() + " is " + self.type.title())
def open_restaurant(self):
"""打印餐馆营业信息"""
print("The restaurant " + self.name.title() + " is now opening!")
导入该模块中的类,并创建restaurant实例
from restaurant import Restaurant
my_restaurant = Restaurant('KFC','fast food')
my_restaurant.describe_restaurant()
my_restaurant.open_restaurant()
我们可以发现能正常执行!
(2)在一个模块中存储多个类
建立一个模块,里面存储了多个类
admin.py
"""一组用于表示用户信息的类"""
class User():
"""创建一个用户的类"""
def __init__(self,first_name,last_name,age,country):
"""初始化属性"""
self.name = first_name + last_name
self.age = age
self.country = country
def describe_user(self):
"""打印用户信息"""
print("The user " + self.name.title() + " is " + str(self.age) +
" years old,and live in " + self.country.title() + "."
)
def greet_user(self):
"""打印欢迎信息"""
print("Hello! " + self.name.title() + ".")
class Privileges():
"""编写一个只有特权属性的类"""
def __init__(self,privileges='add post'):
self.privileges = privileges
def show_privileges(self):
print("\nYou can " + self.privileges)
#父类为User,子类为Admin
class Admin(User):
def __init__(self,first_name,last_name,age,country):
super().__init__(first_name,last_name,age,country)
self.privileges = Privileges()
再将该模块中的一个类添加到主模块中进行使用
from admin import Admin
#创建实例
my_user = Admin('Bill ','Gates',24,'china')
#调用方法
my_user.describe_user()
my_user.greet_user()
my_user.privileges.show_privileges()
(3)错误示例
如果我们没有导入某个类,但是使用了其中的方法,那么会报错。
5、Python标准库
我们可以使用其他程序员编好的模块,因此只需在程序开头包含一条简单的import语句即可。
练习
使用Python中自带模块collections的OrderedDict类(OrderedDict实例的行为几乎与字典相同,区别在于记录了键值对的添加顺序。)
from collections import OrderedDict
languages = OrderedDict()
languages['peter'] = 'C'
languages['jack'] = 'verilog'
languages['lucy'] = 'python'
languages['tom'] = 'ruby'
for key,value in languages.items():
print(key.title() + " love the language " + value.title())
创建一个随机的数利用类randint
"""创建一个随机的数"""
from random import randint
class Die():
"""模拟随机数的产生,并打印"""
def __init__(self):
self.sides = 6
def roll_die(self):
"""打印这个数"""
x = randint(1,6)
self.sides = x
print("The number is " + str(self.sides))
def roll_die10(self):
x = randint(1,10)
self.sides = x
print("The number is " + str(self.sides))
def roll_die20(self):
x = randint(1,20)
self.sides = x
print("The number is " + str(self.sides))
#自己指定面数
def roll_die_x(self,number):
x = randint(1,number)
self.sides = x
print("The number is " + str(self.sides))
die = Die()
print("6 sides")
for i in range(0,10):
die.roll_die()
print("10 sides")
for i in range(0,10):
die.roll_die10()
print("20 sides")
for i in range(0,10):
die.roll_die20()
print("you show!")
for i in range(0,10):
#指定面数为15
die.roll_die_x(15)