此篇主要是Python类属性、类方法的调用、实例对象、类继承等实例的讲解。
必须知道的概念
1)类 Class:
用来描述具体相同的属性和方法的对象的集合,定义了该集合中每个对象所共有的属性和方法,对象是类的示例。
2)类变量:
类变量在整个实例化的对象中是公用的,类变量定义在类中且在函数体之外,类变量通常不作为实例变量使用。
3)实例变量:
定义在方法中的变量,只作用于当前实例的类。
4)数据成员:
类变量或者实例变量用于处理类及其实例对象的相关数据。
5)方法:
类中定义的函数,在类内部使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。
6)构造函数:
即__init()__,特殊的方法,在对象创建的时候被自动调用。
7)析构函数:
即__del()__,特殊的方法,在对象被销毁时被自动调用。
8)实例化:
创建一个类的实例,类的具体对象,就是将创建的类赋值给另一个变量。理解为赋值即可,a = class(),这个过程,就叫做实例化。
9)对象:
通过类定义的数据结构实例,对象包括两个数据成员(类变量和实例变量)和方法。
10)继承:
即一个派生类(derived class)继承基类(base class)的字段和方法,继承也允许把一个派生类的对象作为一个基类对象对待。
11)方法重写:
如果从父类继承的方法不能满足子类的需求,可以对其 进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
类的定义
Python使用class关键字来定义类,class关键字之后是一个空格,接下来是类的名字。
如果派生自其它基类的话则需要把所有父类放到一对圆括号中并使用逗号分隔,然后是一个冒号,最后换行并定义类的内部实现。
类名的首字母一般要大写;
class ClassName:
语句1
...
语句n
需要注意几点:
① 类定义与函数定义(def语句)一样;
只有在被执行才会起作用,在定义阶段只是语法检查。
② 类是属性和方法的组合;
所以语句1可能是内部变量(数据、属性)的定义和赋值语句,也可能是内部方法(函数)的定义语句。
③ 进入类定义时,就会创建一个新的命名空间,并把它用作局部作用域。
④ 正常离开(从结尾出)类定义时,就会创建一个类对象。
示例:
class MyClass:
"""定义一个MyClass类"""
i = 12345
def func(self):
return 'hello world'
类中的self
在类内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
# 实例化类
p = people('runoob',10,30)
p.speak()
self只有在类的方法中才会有,且self在定义类的方法时是必须有的,但是在调用时不必传入相应的参数。
另外,self名称不是必须的,只是约定成俗的东西,在python中self不是关键词,你可以定义成a或b或其它名字都可以(尽量不要取奇怪的名称)。
class Person:
def _init_(myname,name):
myname.name=name
def sayhello(myname):
print('My name is:',myname.name)
p=Person('Bill')
print(p)
尤其需要注意的一点:self指的是类实例对象本身,
不是类本身。
class Test:
def ppr(self):
print(self)
print(self.__class__)
t = Test()
t.ppr()
执行结果:
<__main__.Test object at 0x000000000284E080>
<class '__main__.Test'>
上述例子中,self指向的是t这个对象,而不是类本身。
在Python解释器的内部,当我们调用t.ppr()时,实际上Python解释成Test.ppr(t),也就是把self替换成了类的实例。
class Test:
def ppr():
print(self)
t = Test()
t.ppr()
运行结果:
Traceback (most recent call last):
File "cl.py", line 6, in <module>
t.ppr()
TypeError: ppr() takes 0 positional arguments but 1 was given
class Test:
def ppr():
print(__class__)
Test.ppr()
运行结果:
<class '__main__.Test'>
类方法
大体分为 3 类,分别是:
类方法
实例方法
静态方法
其中实例方法用的是最多的;
# 调用类方法1:类名.方法名(参数名1=value1, 参数名2=value2,...)
# 调用类方法2:类名.方法名(value1, value2,...)
# 如果没有参数:类名.方法名()
MyClass.myClassMethod()
# 调用类属性:类名.属性名
value = MyClass.classAndInstanceProperty
# 设置类属性值:类名.属性名 = newValue
MyClass.classAndInstanceProperty = 'hello world'
我们知道,实例方法的调用方式其实有2种,既可以采用类对象调用,也可以直接通过类名调用。
通常情况下,我们习惯使用类对象调用类中的实例方法,但如果想用类调用实例方法,不能像如下代码:
class Study:
def info(self):
print("学 Python")
#通过类名直接调用实例方法
study.info()
运行出现报错:
Traceback (most recent call last):
File "D:\python3.6\demo.py", line 5, in <module>
study.info()
TypeError: info() missing 1 required positional argument: 'self'
最后一行报错信息提示我们,调用 info() 类方式时缺少给 self 参数传参。
这意味着,和使用类对象调用实例方法不同,通过类名直接调用实例方法时,Python 并不会自动给 self 参数传值
所以如果想通过类名直接调用实例方法,就必须手动为 self 参数传值。
修改上面的代码示例:
class Study:
def info(self):
print("学 Python")
clang = Study()
#通过类名直接调用实例方法
study.info(clang)
运行结果:
学 Python
可以看到,通过手动将 clang 这个类对象传给了 self 参数,使得程序得以正确执行。实际上,这里调用实例方法的形式完全是等价于clang.info()。
类对象
在python中,把具有相同属性和方法的对象归为一个类(class),定义一个类后,就相当于有了一个类对象了:Python中一切皆对象。
类也称为"类对象",前面例子中定义了类MyClass,其也可以成为类对象。
类对象支持两种操作:属性引用和实例化;
① 实例化:
使用instance_name = class_name()的方式实例化,实例化操作创建该类的实例(格式:实例对象名 = 类名(),实例对象名是我们自己定义的)。
② 属性引用:
使用class_name.attr_name的方式引用类属性(类名.属性名)。
示例:属性引用
class MyClass:
"""定义一个MyClass类"""
i = 12345
def func(self):
return 'hello world'
print(MyClass.i) # 引用类属性
print(MyClass.func) # 引用实例方法:实例方法可以这样被引用,但是这样引用无意义(知道即可)
# 类属性也可以被赋值,因此可以通过赋值来更改类属性的值
MyClass.i = 123
print(MyClass.i)
"""
12345
<function MyClass.func at 0x00000229FB3F0840>
123
"""
示例:实例化
class MyClass:
"""定义一个MyClass类"""
i = 12345
def func(self):
return 'hello world'
#实例化一个类
my_class = MyClass()
print(my_class)
# <__main__.MyClass object at 0x0000025C05DFE4A8>
#可以看到实例化类后返回的是一个MyClass对象,这个对象跟python中的数字、字符串、列表等是一样的
#对象都可以拥有属性、方法
上面类对象的实例化就是:my_class = MyClass()。这就创建了一个类的新实例并将此对象分配给局部变量my_class。
实例化操作可以看成是"调用"类对象:将一个类实例化后获得的对象(所赋值的变量)称为实例对象。my_class就称为实例对象。
类只是一个抽象的概念,只有经过实例化后(获得实例对象),才会有意义,才能正常使用这个类中的属性和方法。
实例对象
实例对象就是具有类属性和方法的具体事物,比如类可以看做制作饼干的模板,那么通过这个模板制作出来的一块块饼干就是实例对象。
格式:实例对象名 = 类名()
一个类可以实例化出无数个实例对象,这些实例对象之间的属性和方法都是独立的,互不干扰。
比如:一个饼干模具可以生产出无数块饼干。
实例对象仅支持一个操作:属性引用;
实例对象名.属性名
实例对象名.方法名()
示例:
class MyClass:
"""定义一个MyClass类"""
i = 12345
def func(self):
return 'hello world'
#第一个实例对象
my_class = MyClass()
print(id(my_class))
print(my_class.i) # 引用类属性
print(my_class.func()) # 引用实例方法
#第二个实例对象
my_class1 = MyClass()
print(id(my_class1))
# 类属性重新赋值
my_class1.i = 123
print(my_class1.i) # 引用类属性
print(my_class1.func()) # 引用实例方法
#第三个实例对象
my_class2 = MyClass()
print(id(my_class2))
print(my_class2.i) # 引用类属性
print(my_class2.func()) # 引用实例方法
"""
2205374276776
12345
hello world
2205374276552
123
hello world
2205374279632
12345
hello world
"""
类的继承
一个类继承另一个类时,会自动获得另一个类的所有属性和方法,被继承的类称之为父类,新类称为子类。
子类拥有父类所有的属性和方法,并且可以定义自己的属性和方法。
格式如下:
class 子类名(基类1[,基类2,...]):
语句块
例如:class Cat(Animal) ,这种形式就是从父类继承
Animal就是Cat的父类,也称为基类、超类。
Cat就是Animal的子类,也称为派生类。
① 单继承
一个子类只从一个父类派生;
简单示例:
class Fruit():
def color(self):
print("colorful")
class Apple(Fruit):
pass
class Orange(Fruit):
pass
apple = Apple()
orange = Orange()
apple.color()
orange.color()
# 输出
# colorful
# colorful
Fruit为父类,Apple和Orange为子类,子类继承了父类的特性,因此Apple和Orange也拥有Color方法。
子类除了可以继承父类的方法,还可以覆盖父类的方法;
class Fruit():
def color(self):
print("colorful")
class Apple(Fruit):
def color(self):
print("red")
class Orange(Fruit):
def color(self):
print("orange")
apple = Apple()
orange = Orange()
apple.color()
orange.color()
# 输出
# red
# orange
② 多类继承
在单类继承中,super()函数用于指向要继承的父类,且不需要显式的写出父类名称。
但在多类继承中,会涉及到查找顺序(MRO)、钻石继承等问题。MRO 是类的方法解析顺序表,也就是继承父类方法时的顺序表。
钻石继承:
A
/ \
B C
\ /
D
A是父类,B和C继承A,D继承B和C,示例说明钻石继承的继承顺序:
class Plant():
def __init__(self):
print("Enter plant")
print("Leave plant")
class Fruit(Plant):
def __init__(self):
print("Enter Fruit")
super().__init__()
print("Leave Fruit")
class Vegetable(Plant):
def __init__(self):
print("Enter vegetable")
super().__init__()
print("Leave vegetable")
class Tomato(Fruit, Vegetable):
def __init__(self):
print("Enter Tomato")
super().__init__()
print("Leave Tomato")
tomato = Tomato()
print(Tomato.__mro__)
# 输出
# Enter Tomato
# Enter Fruit
# Enter vegetable
# Enter plant
# Leave plant
# Leave vegetable
# Leave Fruit
# Leave Tomato
# (<class '__main__.Tomato'>, <class '__main__.Fruit'>, <class '__main__.Vegetable'>, <class '__main__.Plant'>, <class 'object'>)
类的嵌套使用
这里的嵌套值得是将一个类作为另一个类的属性;
看下列语法示例:
class Food:
def __init__(self):
self.favorite_food = 'banana'
class Person:
def __init__(self):
self.food = Food()
def show_favorite(self):
print("My favorite food is :" + self.food.favorite_food.title())
person = Person();
person.show_favorite()
首先我们定义好food类,然后将food类作为person类的属性,使用和普通的属性没有区别,只不过这个属性还可以调用自身的方法。
输出:
My favorite food is :Banana
类的封装
类的封装可有数据封装、方法封装、属性封装;
示例1:数据的封装
class User:
def __init__(self,name,age):
self.name=name
self.age=age
示例2:方法封装
class User:
def __init__(self,name,age):
self.name=name
self.age=age
def get_name(self):
return self.name
需要注意的是:方法的封装通过定义方法,让对象调用方法得到数据。
示例的两种封装方法对于数据的安全保护不够强烈,因为对象可以直接通过objeect.name='like'之类的办法修改,获得类中的数据,外界对象可以直接获得类中的数据。
属性的封装有两种
① 规则的封装
通过在变量前加一个下划线,例如:self._name=name,这种封装和前面的数据封装没有太大区别,只是通过行业的规则进行限制。
② 通过方法封装属性
如下示例:
class User:
def __init__(self,name,age):
self.__name=name
self.__age=age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name=name
def get_age(self):
return self.__age
def set_age(self,age):
'''
可以再set_age中添加限制条件进行数据的限制
'''
self.__age=age
u=User('tom',60)
print(u.get_name(),u.get_age())
内容小结
Python 中使用 class 关键字声明一个类
Python 中的类,继承基类不是必须的
类的方法和只读属性都是通过 def 定义,并且第一个参数必须是类的实例(或类名)
类的读写属性是特别的,既是实例属性又是类属性
在属性/方法名前加2个 _ 即变为私有属性/方法
self 和 cls 非指定名称,可以换成别的名称
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/11138/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料
查 看2022高级编程视频教程免费获取