2.4.1Python-类基础
总目录:https://blog.****.net/qq_41106844/article/details/105553392
Python - 子目录:https://blog.****.net/qq_41106844/article/details/105553333
类是用来描述具有相同的属性和方法的对象的集合。
如何定义一个类
类代码块以class关键字开头,后紧接类标识符。类标识符通常是大写开头的单词。
类内容以冒号起始,并且缩进。
类的描述
类包含属性和方法
一个对象的特征称为"属性",一个对象的行为称为"方法"。属性在代码层面上来看就是变量,方法实际就是函数,通过调用这些函数来完成某些工作
在类中定义方法的形式和函数差不多,但其不称为函数,而是叫方法。方法的调用需要绑定到特定的对象上(通过self.),而函数不需要。
语法格式
class ClassName:
语法块
类的使用
类的使用分两种方式,分别是属性引用和实例化。
属性引用
例子
class My:
i = 123
def a(self):
return 'hello world'
# 访问类的属性和方法
print(My.i)
print(My.a())
123
hello world
如果要引用对象里的方法和属性,使用点操作符( . )即可。
My.i用于调用类的属性,也就是我们前面所说的类变量;My.a()用于调用类的方法。
属性引用相当于直接去类中调用需要调用的属性和方法,但是此时的类还是一个类,还不是一个对象,还不能进行复杂的对象操作,只能简单的调用。那么为了让类变成对象,需要进行类的实例化。
类实例化
我们在上一个例子上扩展
class My:
i = 123
def a(self):
return 'hello world'
x = My() #类的实例化
# 通过实例化的对象访问类的属性和方法
print(x.i)
print(x.a())
123
hello world
在未实例化类前,只是定义了对象的属性和方法,此时其还不是一个完整的对象。
将定义的这些称为类。需要使用类来创建一个真正的对象,这个对象就叫做这个类的一个实例,也叫作实例对象。(一个类可以有无数个实例)
创建一个对象也叫做类的实例化,即x = My()。(此时得到的x变量称为类的具体对象)
注意此时类名后面是跟着小括号的,这跟调用函数一样。
需要先创建好实例再进行类的实例化。
知识点扩展
类中定义方法的要求
在类中定义方法时,除第一个参数必须是self外,类的方法和普通的函数没有区别。
在类中调用方法的要求
调用一个方法,在实例变量上直接调用即可。除了self不用传递,其他参数正常传入
类和对象的区别
类是一个抽象的概念,对象则是一个具体的东西。
我们说小明有两个眼睛,一个嘴巴,两条腿,一个脑袋,但是这些只是我们对小明的形容。如果我们说:有两个眼睛,一个嘴巴,两条腿,一个脑袋的东西是小明,这就是类的实例化。
在举一个例子,楼房的设计图就是类,通过设计图使用钢筋混凝土盖出来的东西才是楼房。
类是对对象的描述,对象是类的具体实现。
self是什么
self其实就相当于C++中的this指针
我们通过小明的例子再拓展,小明有两条腿,他如果要行走,必须要分的清左右腿,那么self就相当于与一个标识,一个能让小明分得清他用的是左腿还是右腿的标识。
如果一个类中有很多一样的方法,那么这些方法可以理解为楼房中的房间,self就是门牌号。
python的self参数就是这样一个道理,同一个类可以生成无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么python就知道需要操作哪个对象的方法了。
继承
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
我们先定义一个动物类 Animal,让他有一个run方法:
class Animal(object):
def run(self):
print('Animal is running...')
之后我们定义两个类,分别是猫类和狗类,让他们直接继承Animal。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
对于他们来说,Animal就是他们的父类,他们就是Animal的子类。
继承最大的用途是子类能够拥有父类的所有属性和方法。
dog = Dog()
dog.run()
Animal is running...
cat = Cat()
cat.run()
Animal is running...
但是不管我们dog.run()或者cat.run(),出来的都是Animal is running...,所以我们需要重新定义Dog和Cat的run方法。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
dog = Dog()
dog.run()
Dog is running...
cat = Cat()
cat.run()
Cat is running...
我们重新在子类中定义了run方法,子类的run方法会覆盖掉他继承父类的run方法。
多态
多态用大白话来说,就是这个量有多重状态,举个例子
小明是第三小学的学生,同样他是北京人。小明就有个多个身份,这就是多态。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
a = Animal()# b是Animal类型
d = Dog()# c是Dog类型
print(isinstance(a, Animal))
print(isinstance(d, Dog))
print(isinstance(d, Animal))
True
True
True
d不仅是Dog类型,也是Animal类型。
对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定。
这就是多态真正的威力:
调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。
这就是著名的“开闭”原则:
对扩展开放:允许新增Animal子类;
对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
类变量和实例变量
我们先看一个例子
class My2:
def setname(self,name):
self.name = name
def kick(self):
print("我是%s" % self.name)
a = My2()
b = My2()
c = My2()
a.setname("A")
b.setname("B")
c.setname("C")
print(a.kick())
print(b.kick())
print(c.kick())
我是A
我是B
我是C
从上面例子可以看出,有Ball类生成了三个实例对象a,b,c,这三个对象在调用kick()方法时,是通过self参数去确定究竟当前是哪个对象在调用方法的。因此在写类方法时一定要写self参数且其位置在第一个。
实例变量是每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法。
即某个属性对于每个实例都是独有的,就需要将其定义为实例变量;是每个实例同共有的就可以定义为类属性
实例
class Dog:
dress ="china"
def __init__(self,name):
self.name = name
x = Dog()
TypeError: __init__() missing 1 required positional argument: 'name'
#在实例化类时需要传入参数
y = Dog('哈士奇')
print(y)
<__main__.Dog object at 0x0000020E8D26C2E8>
print(y.name)
哈士奇
在这个实例中,dress是类属性,这个类中所有的实例都可以调用它。name是实例属性,只有这个实例可以调用它。
调用时需要注意的地方
在类中调用实例属性时使用self. 实例属性 ,在类外调用时使用实例名.实例属性
类中存在__init__方法时,在实例化类时需要传入参数(实例变量的实参),在调用类的方法时也需要传入方法的实参(方法中存在形参时)。
类对象和实例对象
一切皆对象
类对象不需要多加赘述,我们来看一些实例对象。
实例对象是类对象实例化的产物,实例对象仅支持一个操作:属性引用
属性绑定
不管是类对象还是实例对象,属性都是依托对象而存在的。我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作。
绑定有两种情况:如果属性存在,则覆盖,反之直接添加。
类属性绑定
Python是一个动态语言,绑定可以发生在任意时刻。
class Dog:
kind ='canine'
Dog.country ='China'
print(Dog.kind, ' - ', Dog.country)
canine - China
del Dog.kind
print(Dog.kind, ' - ', Dog.country)
AttributeError: type object 'Dog' has no attribute 'kind'
这是使用类名绑定属性的方法。
实例属性绑定
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
dog = Dog('Lily', 3)
dog.color = 'red'
print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.color))
Lily is 3 years old, it has red fur
这里是使用objname.attr = attr_value语句的方式。
属性引用
属性应用分为类属性引用和实例属性引用。
类属性引用
类属性的引用,肯定是需要类对象的,属性分为两种:数据属性、函数属性
这些我们在讲述类的时候讲述过了,这里就就简单举个例子
class Dog:
kind ='canine'
def tell_kind():
print(Dog.kind)
print(Dog.kind) #类数据属性引用
print(Dog.tell_kind) #类函数属性引用
实例属性引用
使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:
先到实例对象中查找属性,再到类属性中查找属性;
实例
class Dog:
kind ='canine'
country ='China'
def __init__(self, name, age, country):
self.name = name
self.age = age
self.country = country
dog = Dog('Lily', 3, 'Britain')
print(dog.name, dog.age, dog.kind, dog.country)
Lily 3 canine Britain
dog.country会引用到实例对象的属性;但实例对象dog没有属性kind,按照规则会引用类对象的属性。