没接触过任何语言之前,我了解到的类,好像只有 Java 和 C 里面才有,也觉得特别高大上,就像我第一次接触函数一样,函数可能好理解一点,类就是正儿八经的面对对象编程了。
在书上看了一下类,没接触过的我,确实有点难理解。
通过举例和实际操作来理解一下吧,我也刚接触,无法用概念性的方式表达。
因为是面向对象编程,所以使用类可以进行创建对象,也叫 实例化,要实现这样的功能,就需要类具备一些统一的特点,或者说在定义类对象都有通用行为,也就是有相同的特点,比如,狗,都会跑、跳、蹲,就可以创建一个狗的类,用来实例化,每一只狗,让狗来完成类中定义的 方法,可以是各种不同的狗,因为狗都会跑、跳、蹲,所以都适用于此方法。
类 和 函数 的优点相同,让相似的代码可以高效,也可以放在模块中进行调用
创建类
就以上面的例子来创建一个 Dog 类,来表达狗
根据 Dog 类创建的每个实例(对象)都将存储名字和年龄。然后给每条狗一个蹲、打滚、跳的能力
class Dog():
def __init__(self, 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!")
def jump(self):
print(self.name.title() + " is jumped ~")
class Xxx(): 是定义类的格式,在 Python 中,首字母大写的名称指的是类,这个类定义中的括号是空的,因为要从空白创建这个类。
方法 __init__():类中函数就叫方法,每个空白类都有这样一个方法,__init__ 是一个特殊的方法,每当根据这个类创建新实例时,Python都会自动运行__init__ 方法,在这个方法的名称中,开头和末尾都有两个下划线,这是一种约定,是为了避免 Python 默认方法与普通方法发生名称冲突。
以上 __init__ 中包含了三个形参:self、name和age。形参 self 必不可少,还必须在其他形参的前面,Python在调用 __init__ 时,将自动传入实参 self。每个与类相关联的方法调用都自动传递实参 self,是一个指向实例本身的引用,让实例能够访问类中的属性和方法。所以手动调用传参时,也不需要给 self 传参。直接给 name 和 age 按顺序提供值即可。
self.name = name:以 self 为前缀的变量都可以让类中的所有方法使用,这种形式的变量也叫属性。
剩余的 def 定义的方法就是实例化时可以做的动作,如果这是一个做机器狗的代码,就可以将方法替换为机器狗可以做的动作。
创建类实例
my_dog = Dog('包子', '3')
print("My dog's name is " + my_dog.name.title() + ".")
print(my_dog.name.title() + " is " + my_dog.age + " years old.")
以上代码中使用 Dog 类定义 my_dog 变量,并分别传参给了类中 __init__ 函数的 name 和 age 形参,my_dog 就可以成为是 Dog 类的实例,print 语句就是使用该实例化后的参数,所以 my_dog.name 的值为“包子”,my_dog.age 的值为“3”。
调用类方法
根据创建好的实例,调用 Dog 类中的其他方法
my_dog.sit()
my_dog.roll_over()
my_dog.jump()
直接运行以上代码将会得到在类中定义好的输出。可以自行想一个场景,自己做一个联系来巩固类的基础用法。
这里我创建一个简单的示例,同时也方便后续的操作。
class User():
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + ",I am " + str(self.age) + " years old!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
me_user = User('Chai', 'Yanjiang', '26')
me_user.describe_user()
me_user.greet_user()
只要弄懂了类的使用方法,看懂这段毫不费力。
给属性指定默认值
这里的属性指的就是 __init__ 中进行初始化的各类变量值。类中的每个属性都必须有初始值,哪怕为0或者为空,比如宝宝一直未出生之前,年龄一直为0,类中可以这样写。
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.age = 0
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + ",I am " + str(self.age) + " years old!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
me_user = User('Chai', 'Yanjiang')
me_user.describe_user()
me_user.greet_user()
这种情况可以让 age 属性一直为0,不需要传参。
但是宝宝出生后,年龄是会有变化的,所以修改的途径还得有。
me_user = User('Chai', 'Yanjiang')
me_user.age = 26
me_user.describe_user()
通过方法传递参数的变化
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.age = 0
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + ",I am " + str(self.age) + " years old!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
def age_change(self, change):
self.age = change
me_user = User('Chai', 'Yanjiang')
me_user.age_change(23)
me_user.describe_user()
为了防止使用者会将年龄回调,这里可以加个判断。
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.age = 0
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + ",I am " + str(self.age) + " years old!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
def age_change(self, change):
if change > self.age:
self.age = change
else:
print('Your input is not reasonable')
me_user = User('Chai', 'Yanjiang')
me_user.age_change(23)
me_user.describe_user()
再多一种操作,当每年递增的时候,每年都要算多少岁,直接在原来的基础上加就好了。
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.age = 0
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + ",I am " + str(self.age) + " years old!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
def age_change(self, change):
if change >= self.age:
self.age = change
else:
print('Your input is not reasonable')
def increasing_age(self, increasing):
self.age += increasing
me_user = User('Chai', 'Yanjiang')
me_user.age_change(23)
me_user.describe_user()
me_user.increasing_age(2)
me_user.describe_user()
### 输出内容 ###
My name is Chai Yanjiang,I am 23 years old!
My name is Chai Yanjiang,I am 25 years old!
举的例子可能不太恰当,但是就是这么个事儿。
下面为贴2个例子
示例1:
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.login_attempts = 0
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + ".")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
def increment_login_attempts(self):
self.login_attempts += 1
print("User " + self.first_name + " " + self.last_name + " attempts to log in " + str(self.login_attempts) + " times!!!")
def reset_login_attempts(self):
self.login_attempts = 0
print("User " + self.first_name + " " + self.last_name + " logins have been reset to " + str(self.login_attempts) + ".")
login_user = User('Chai', 'Yanjiang')
login_user.increment_login_attempts()
login_user.increment_login_attempts()
login_user.increment_login_attempts()
login_user.increment_login_attempts()
login_user.reset_login_attempts()
示例2:
class Restaurant():
def __init__(self, restaurant_name, cuisine_type):
self.restaurant_name = restaurant_name
self.cuisine_type = cuisine_type
self.number_served = 0
def desscribe_restaurant(self):
print("This is a " + self.cuisine_type + ".")
print("It's called " + self.restaurant_name + ".")
def open_restaurant(self):
print("Restaurant is open")
print("There are " + str(self.number_served) + " people in the restaurant now.")
def set_num_served(self, set_num):
if set_num >= self.number_served:
self.number_served = set_num
print("There are " + str(self.number_served) + " people eating at " + self.restaurant_name + " " + self.cuisine_type + ".")
def increment_num_served(self, inc_num):
self.number_served += inc_num
print("There are " + str(inc_num) + " new people in the restaurant.")
print("There are " + str(self.number_served) + " people in the restaurant now.")
restaurant = Restaurant('FeiYi', 'Farmhouse')
restaurant.desscribe_restaurant()
restaurant.open_restaurant()
restaurant.set_num_served(3)
restaurant.increment_num_served(5)
继承
类的继承是指一个类继承另一个类中的所有属性和方法。原有的类称为父类,新类称为子类。子类可以继承父类的所有属性和方法,也可以定义属于自己的属性和方法。
子类通过 __init__
来继承父类的属性和方法。还以上面 User 例子来使用。
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + "!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
创建子类时,父类必须在同一代码文件中,且位于子类前面。
class New_User(User): # 括号内指定父类的名字
def __init__(self, first_name, last_name): # __init__ 和父类一致
super().__init__(first_name, last_name) # 这行代码让python调用父类User的__init__方法。
super()
函数用来串联父类和子类。让 New_User
包含父类的所有属性,父类也叫超类(superclass),super()
函数也是这么来的。
子类的使用方法和父类一致。
hello = New_User("chai", "yanjiang") # 定义变量,使用子类并按照父类传参
hello.describe_user() # 使用变量,调用父类方法执行
python2.7
在继承父类时,需要给 super()
传参,具体查一下吧,这里就以 python3
为例了。
定义子类私有属性
继承父类后,子类也可拥有属于自己的属性和方法。
class New_User(User):
def __init__(self, first_name, last_name):
super().__init__(first_name, last_name)
self.age = 0 # 新增一个属性,默认值为0
def new_age(self): # 新增一个方法,输出人物年龄
print(self.first_name.title() + " " + self.last_name + "'s age is " + str(self.age))
使用子类中的新增属性和方法
hello = New_User("chai", "yanjiang")
hello.age = 26 # 修改子类属性值
hello.new_age() # 调用子类方法
重写父类方法
重写其实也可以理解为覆盖,在子类中命名一个和父类中某一方法同名的即可。在调用子类中的该方法时,python 会忽略父类中的同名方法。
使用场景是,如果父类中的方法,在子类的使用过程中不适用的情况。
这个很简单,就不举例了。
将实例用作属性
在定义某一个类时,添加的方法和属性会越来越多,单个类的大小长度也随之变大,可以将大型类拆分成多个小类进行协同使用。
还以上面的代码为例
# 这是最初始的类,用来传入名字,进行介绍和打招呼
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + "!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
# 想要给这个方法增加一个年龄的属性,假设以上类已经足够大了,重新创建一个类来表示年龄
class User_Age():
def __init__(self, user_age=0):
self.user_age = user_age
def age_info(self):
print("This is people's age is " + str(self.user_age))
# 上述两个类并无实际关系,然后使用继承和实力属性化的方式结合起来
class New_User(User):
def __init__(self, first_name, last_name):
super().__init__(first_name, last_name) # 继承User父类的属性和方法
self.age = User_Age() # 这里直接调用了 User_Age() 类,在使用时,self.age 就已经是一个类了
通过子类使用以上三个类
# 定义变量的值为子类并传参
hello = New_User("chai", "yanjiang")
# 使用变量通过子类调用父类方法
hello.describe_user()
# 使用变量通过子类中定义的属性age,调用表示年龄的类
hello.age.age_info() # hello.age 中的age 就是 New_Uesr 中 init 方法中的 self.age,即 User_Age()
我尝试了好几次,怎么改这个age的参数,最后改了 User_Age 类为如下:
class User_Age():
def __init__(self, user_age=0):
self.user_age = user_age
def age_info(self, age):
self.user_age = age
print("This is people's age is " + str(self.user_age))
使用时传入年龄参数 hello.age.age_info(26)
。
导入类
随着在使用类的过程中,功能越来越多多,代码越来越多,程序文件会变得越来越长,为了让文件更简洁,Python 允许将类存储在模块中,然后在其他程序文件中导入所需的模块。
使用下面代码作为一个类模块存储,也就是将这个类单独放在一个文件中。
# name.py
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def describe_user(self):
print("My name is " + self.first_name + " " + self.last_name + "!")
def greet_user(self):
print("Hi, " + self.first_name + self.last_name + "!")
在同级目录创建另一个程序文件来导入上面的类模块
# my_name.py
from name import User
my_name = User("Fei", "Yi")
my_name.describe_user()
from name
表示来自 name.py
,import User
表示导入 name.py
中的 User
类,这里可以看出,也可以导入多个类,也就是 name.py
中可以写入多个类供其他程序文件使用。
一次性导入同一个模块的多个类可以表示为 from name import class1, class2
,当然如果存储的模块中有大量类,也可以直接全部导入,使用 import name
。
import name
# 此处调用类需要使用name.class_name
my_name = name.User("Fei", "Yi")
my_name.describe_user()