1. 类的定义和使用

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量(类属性):类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 实例变量(实例属性):定义在方法中的变量,只作用于当前实例的类。
  • 方法:类中定义的函数。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,所以Dog也是一个Animal。
  • 实例化:创建一个类的实例,类的具体对象
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法

类就是一个模板,模板里可以包含多个函数,函数里实现一些功能。对象则是根据模板创建的实例,通过实例对象可以执行类中的函数。

一个典型的类的定义和使用例子如下:

#创建类
class Foo: #class是关键字,Foo是类名
  class_int = 10 #类变量
  #创建类中的函数(方法)
  def bar(self,name):   #self是特殊参数,类的实例化,必须填写。
    print('bar')

obj = Foo() #根据Foo创建对象obj
print('类访问类变量:',Foo.class_int)
print('对象访问类变量:', obj.class_int)
obj.bar(3)

输出:

类访问类变量: 10
对象访问类变量: 10
bar

类的使用请注意:

  1. 调用类属性:
    ⑴类中访问类变量:类名. 类变量名
    ⑵类外访问类变量:类名.类变量名或实例名.类变量名
  2. 调用实例属性:
    ⑴类中访问实例变量:self.实例变量名
    ⑵类外访问实例变量:实例名.实例变量名
  3. 调用实例方法:
    ⑴类中访问实例方法:self.方法名(参数)或类名.方法名(self,参数)
    ⑵类外访问实例方法:实例名.方法名(参数)

2. 对象的三大特性

和所有的面向对象语言一样,python对象也有三大特性,它们分别为封装、继承和多态

2.1 封装

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

(1)通过对象调用被封装的内容

通过:对象.属性名的方式访问实例化对象。具体访问形式如下:

class Foo:
  def __init__(self, name, age):
    self.name = name
    self.age = age

obj = Foo('xiaoming', 22)
print(obj.name,obj.age)
print(type(obj))

输出:

xiaoming 22
<class '__main__.Foo'>

(2)通过self间接访问被封装的内容

其实self就是实例化对象本身,所以可以通过它对实例化对象进行访问。

class Foo:
  def info(self):
    print(self.name,self.age)
  def __init__(self, name, age):
    self.name = name
    self.age = age

obj = Foo('xiaoming', 22)
obj.info()

输出:

xiaoming 22

2.2 继承

和现实中一样,子类可以继承父类中的内容。比如,首先创建一个Animal类,然后cat和dog分别继承它。

class Animal:
    def eat(self):
        print("%s 吃 " % self.name)
    def drink(self):
        print("%s 喝 " % self.name)
    def shit(self):
        print("%s 拉 " % self.name)
    def pee(self):
        print("%s 撒 " % self.name)

class Cat(Animal):
    def __init__(self, name):
        self.name = name
        self.breed = '猫'
    def cry(self):
        print('喵喵叫')

class Dog(Animal):
    def __init__(self, name):
        self.name = name
        self.breed = '狗'
    def cry(self):
        print('汪汪叫')

# ######### 执行 #########

c1 = Cat('小明家的小猫')
c1.eat()

d1 = Dog('小红家的小狗')
d1.eat()
小明家的小猫 吃 
小红家的小狗 吃

2.3 多态

python中的多态,不像C++中父类与子类中的多态一样。它需要根据对象的具体指向来决定方法的指向。具体示例如下,S1和S2都实现了show方法,具体看它的指向来决定调用哪一个。

class F1:
    pass

class S1(F1):
    def show(self):
        print('S1.show')

class S2(F1):
    def show(self):
        print('S2.show')

def Func(obj):
    obj.show()

s1_obj = S1()
Func(s1_obj)

s2_obj = S2()
Func(s2_obj) 

输出:

S1.show
S2.show

3. 属性(变量)绑定

Python作为动态语言,类对象和实例对象都可以在运行时绑定任意属性。因此,类属性的绑定发生在两个地方,类定义时和运行的任意阶段

3.1 类属性绑定

下面程序中介绍了类中和类外的类属性绑定方法,同时类属性也可以被删除

class Dog:
    kind = 'canine' #类中,类属性绑定

Dog.country = 'China'  # 类外,类属性绑定

print(Dog.kind, ' - ', Dog.country)  # 输出: canine  -  China
del Dog.kind #删除类属性
print(Dog.kind, ' - ', Dog.country)  # 类属性被删除,报错!

输出:

canine  -  China
Traceback (most recent call last):
  File "/home/liqiang/workspace/python/python_tutorials/main.py", line 8, in <module>
    print(Dog.kind, ' - ', Dog.country)  # 类属性被删除,报错!
AttributeError: type object 'Dog' has no attribute 'kind'

3.2 实例属性绑定

与类属性绑定相同,实例属性绑定也发生在两个地方:类定义时、运行时任意阶段。

class Dog:
    def __init__(self, name, age):
        self.name = name #类中,实例绑定
        self.age = age

dog = Dog('Lily', 3)
dog.fur_color = 'red'  # 类外,实例属性绑定

print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.fur_color))

输出:

Lily is 3 years old, it has red fur

4. 属性引用

4.1 类属性引用

类属性分为两种:数据属性、方法属性。只是通常很少有引用类函数属性的需求。

数据属性

class Dog:
    kind = 'canine'

Dog.country = 'China'

print(Dog.kind, ' - ', Dog.country) #这两个都是类数据属性的引用

输出:

canine  -  China

4.2 实例属性引用

实例对象可以引用类属性和实例属性,遵循的规则如下:

  1. 先查找实例属性,后查找类属性
  2. 属性绑定时,总是为实例对象创建新属性(即使存在相同的类属性),属性存在时,只更新属性执行的对象

代码示例1:

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与实例对象dog均有属性country,按照规则,dog.country会引用到实例对象的属性;但实例对象dog没有属性kind,按照规则会引用类对象的属性。

代码实例2:

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)
print(dog.__dict__)

dog.kind = 'feline' #新增实例属性,不会改变类属性的值

print(dog.name, dog.age, dog.kind, dog.country)
print(dog.__dict__)
print(Dog.kind) #类属性并没有改变

输出:

Lily 3 canine Britain
{'name': 'Lily', 'age': 3, 'country': 'Britain'}
Lily 3 feline Britain
{'name': 'Lily', 'age': 3, 'country': 'Britain', 'kind': 'feline'}
canine

说明:类外使用新增实例属性,并不会影响类属性

4.3 可变类属性引用

下列代码中 self.tricks.append(trick)为可变类属性引用,而不是实例属性!

class Dog:
    tricks = []

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks.append(trick) #这里是可变的类属性引用,而不是实例子属性


d = Dog('Fido')
e = Dog('Buddy')
d.add_trick('roll over')
e.add_trick('play dead')
print(d.tricks)

输出:

['roll over', 'play dead']

如果想要使用实例属性,可以在先定义self.tricks,然后再append。如下:

class Dog:
    tricks = []

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks = []
        self.tricks.append(trick) 


d = Dog('Fido')
e = Dog('Buddy')
d.add_trick('roll over')
e.add_trick('play dead')
print(d.tricks)
print(e.tricks)

输出:

['roll over']
['play dead']

4.4 一个例子说明类属性、实例属性与普通变量

class TestClass(object):
    val1 = 100

    def __init__(self):
        self.val2 = 200

    def fcn(self, val=400):
        val3 = 300

        self.val4 = val
        self.val5 = 500


if __name__ == '__main__':
    inst = TestClass()

    print(TestClass.val1)
    print(inst.val1)
    print(inst.val2)
    #print(inst.val3) # val3为局部变量,报错!!!
    #print(inst.val4) # val4不是实例属性,报错!!!
    #print(inst.val5)# val5不是实例属性,报错!!!
    print(inst.__dict__)

输出:

100
100
200
{'val2': 200}

可以看出inst只有一个实例属性,也就是val2

  1. val1是类变量,可以由类名直接调用,也可以有对象来调用;
  2. val2是实例变量,可以由类的对象来调用,这里可以看出成员变量一定是以self.的形式给出的,因为self的含义就是代表实例对象
  3. val3既不是类变量也不是实例变量,它只是函数fcn内部的局部变量
  4. val4和val5也都不是实例变量,虽是以self.给出,但并没有在构造函数中初始化

5. 方法

5.1 实例方法、类方法和静态方法

  • 实例方法:一般在类中定义的方法,默认都为实例方法。实例方法最大的特点就是最少要包含一个self参数,该参数必须定义,但调用时不需要传。类比C++中的this指针。
  • 类方法:类方法至少需要包含一个参数(cls),但在调用类方法时,无需显式为cls参数传递参数。类方法需要使用修饰语句: @classmethod类和实例对象都可以调用类方法
  • 静态方法与普通函数类似,只是它在类命名空间中定义,而函数实在程序的全局命名空间中定义。它有以下特点:
  1. 类静态方法没有self、cls这样的特殊参数;
  2. 类静态方法中无法调用任何类和对象的属性和方法,类静态方法与类的关系不大;
  3. 静态方法需要使用@staticmethod修饰;
  4. 可以使用类或实例对象调用它。
  • 类方法举例
class CLanguage:
    def __init__(self):
        self.name = "小明"
        self.age = "22"

    # 下面定义了一个类方法
    @classmethod
    def info(cls):
        print("正在调用类方法", cls)


# 使用类名直接调用类方法
CLanguage.info()
# 使用类对象调用类方法
clang = CLanguage()
clang.info()

输出:

正在调用类方法 <class '__main__.CLanguage'>
正在调用类方法 <class '__main__.CLanguage'>
  • 静态方法举例
class CLanguage:
    @staticmethod
    def info(name, age):
        print(name, age)


# 使用类名直接调用静态方法
CLanguage.info("xiaoming", "22")

# 使用类对象调用静态方法
clang = CLanguage()
clang.info("xiaohong", "23")

输出:

xiaoming 22
xiaohong 23

5.2 实例方法中调用其它方法

内部调用实例方法需要加slef

class Dog():
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def get_dog_information(self):
        dog_information = "name is {0},age is {1}".format(self.name, self.age)
        return dog_information

    def get_dog_speak(self, love):
        dog_speak = self.get_dog_information() + love #内部调用实例方法
        return dog_speak


dog = Dog("jake", 13)
print(dog.get_dog_speak("swimming"))

输出:

name is jake,age is 13swimming
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐