Python 是一门特别彻底的面向对象编程(OOP)的语言。

类和对象

对象

面向对象和面向过程都是解决问题的一种方式。面向对象本身是对面向过程的封装(将不同的步骤归类到不同的对象)。

什么是类?是某一个具体对象特征的抽象。

根据抽象的类,产生具体的对象。有一个类叫「不良少年」,定义了各种属性(年龄、身高、体重)和行为(吃喝玩乐)。根据这个类创建不同的对象(张三、李四、王五)。

类:汽车(抽象的概念而非实物)
对象:丰田、宝马、特斯拉(具体的一台车)……

类和对象

类和对象的关系:类可以实例化一个对象。

# 定义一个类
class Money:  
    num = 100  
  
# 通过类创建对象  
one = Money()  
  
# 通过__class__查看对象所属的类  
print(one.__class__)  
# <class '__main__.Money'>  
# 证明:对象one的类为Money

类有经典类和新式类。

# 定义一个类  
class Money:  
    pass  


# 根据这个类,创建(实例化)一个对象  
a = Money()  
print(a)

对象属性

属性和变量

属性和变量的区别?

变量是“可以改变的量值”,属性是“属于某个对象的特征”。

变量根据位置不同访问权限不同(全局变量、局部变量)。属性只能通过对象来进行访问。

属性是某个对象的属性,因为属性存在宿主。

属性在类里,称为类属性。属性在对象里,称为对象属性。

属性增删改查

对象属性的增删改查:

增:让对象拥有属性。

class Person:  
    pass  
  
p = Person()  
p.age = 18  
p.height = 175  
  
print(p.age)  # 18  

# __dict__ 显示对象的所有属性  
print(p.__dict__)  # {'age': 18, 'height': 175}

删:删除对象的属性。

class Person:  
    pass  
  
p = Person()  
p.age = 18 

del p.age  
print(p.age)  
# AttributeError: 'Person' object has no attribute 'age'

改:修改对象的属性。

class Person:  
    pass

p = Person()  
p.age = 18  
print(p.age)  # 18  
p.age = 17  
print(p.age)  # 17

修改可变变量的列表:

class Person:  
    pass  
  
p = Person()  
p.pets = ['张三', '李四']  
print(p.pets, id(p.pets))  
# ['张三', '李四'] 2159760855560  
  
p.pets = ['111', '222']  
print(p.pets, id(p.pets))  
# ['111', '222'] 2159761410952 两者ID不同

查:访问对象的属性。

列表新增 append(是访问操作而非修改操作):

class Person:  
    pass  
  
p = Person()  
p.pets = ['张三', '李四']  
print(p.pets, id(p.pets))  
# ['张三', '李四'] 2159760855560  
  
p.pets.append('王五')  
print(p.pets, id(p.pets))  
# ['张三', '李四', '王五'] 2263310684680 两者ID相同

ps. 通过同一个类创建的不同的对象,对象的属性是不能互相访问的。

class Person:  
    pass  
  
p1 = Person()  
p1.age = 18  
p2 = Person()  
p2.address = '上海'  
  
print(p1.address)  
# AttributeError: 'Person' object has no attribute 'address'  
# P1 对象中并没有address属性(属性是p2的),所以访问会报错。

类属性

在 Python 当中,万物皆对象。类也可以看成一个有些特殊的对象。

属性的增删改查

增:增加类的属性。

# 方式一
class Money:  
    pass  

# 直接给类增加属性count并赋值 
Money.count = 100  

print(Money.count)  # 100  
print(Money.__dict__)  # {…… 'count': 100}

# 方式二
class Money:  
    num = 100  
  
print(Money.__dict__)  
# {…… '__doc__': None}

删:删除类的属性。

class Money:  
    num = 100  
  
# 通过类.属性删除  
del Money.num  
print(Money.num)  
# AttributeError: type object 'Money' has no attribute 'num'  
  
# 通过对象.属性,并不能删除  
one = Money()  
del one.num  
print(one.num) # AttributeError: num  
# 对象one中并没有age属性,所以del one.num语句报错

查:访问类的属性。

class Money:  
    num = 100  
  
# 直接通过类访问类属性  
print(Money.num)  # 100  
  
# 通过类创建的对象进行访问类的属性  
one = Money()  
print(one.num)  # 100

为什么可以通过对象访问类属性?和Python对象的属性查找机制有关。

优先到对象自身去查找属性,如果没有找到,则根据 __class__ 找到对象对应的类,到类里查找属性。

手动改变对象的类:

class Money:  
    num = 100  
  
class Test:  
    age = 18  
  
# 通过类创建对象  
one = Money()  
  
# 将对象one的类手动改为Test  
one.__class__ = Test  
 
print(one.__class__)  
# <class '__main__.Test'>  
# 证明:对象one的类现在变为了Test

通过对象查找属性时,会优先找对象本身的属性,没有再找类的属性。

class Money:  
    num = 100  
  
one = Money()  
one.num = 200  
  
print(one.num)  # 优先找对象本身的属性

改:修改类的属性。

查找时,对象本身没有就会去类属性。但修改不同,通过给对象赋值并不会修改到类本身。

class Money:  
    num = 100  
  
# 通过类修改类属性  
Money.num = 200  
print(Money.num)  # 200  
  
# 修改对象属性并没有用  
one = Money()  
one.num = 300  
# 此时并没有修改类的num属性,而是给对象one新增一个num属性并指向300

属性的内存存储

对象中有一个默认的 __dict__ 字典,保存了所有的对象属性。

class Money:  
    num = 100  
  
one = Money()  
one.__dict__ = {'name': '张三', 'age': 18}  
print(one.name)  # 张三

类的属性也保存了类的 __dict__ 字典中,是只读的,不能修改(可通过其他方式修改)。

class Money:  
    num = 100  
  
print(Money.__dict__)  
# {'num': 100, ……}

# 修改类属性,可以
Money.num = 200  
print(Money.num)  # 200  

# 修改类的__dict__字典,报错:不能被写
Money.__dict__ = {'sex': '男'}  
# AttributeError: attribute '__dict__' of 'type' objects is not writable

类属性被对象共享

类属性的添加、修改,会被各个对象所共享。

class Money:  
    num = 100  
 
# 修改类的属性
Money.num = 200  
  
one = Money()  
print(one.num)  # 200

限制对象属性添加 __slots__

class Money:
    __slots__ = ['num']
    pass

one = Money()
one.num = 100
print(one.num)  # 100

one.age = 18
print(one.age)
# AttributeError: 'Money' object has no attribute 'age'

方法

方法和函数

方法是描述一个目标的行为动作。和函数类似,都封装了一系列行为动作,都可以被调用之后执行一系列行为动作。区别在于调用方式不同。

def eat():  
    pass  
  
# 调用eat函数  
eat()  
  

class Person:  
    def eat(self):  
        pass  
  
one = Person() 

# 调用eat方法  
one.eat()

实例 = 对象

实例化:对象是由类实例化出来的。我们一般将实例化的对象叫做「实例」。

也就是说,类和实例都是一个对象,实例是类创建出来的。

实例中的3种方法

方法划分为三类:实例方法、类方法、静态方法。

  • 实例方法:默认第一个参数需要接收到一个实例。
  • 类方法:默认第一个参数需要接收到一个类。
  • 静态方法:第一个参数没有接收。
class Person:  
    # 实例方法  
    def a1(self):  
        print('这是一个实例方法')  
  
    # 类方法  
    @classmethod  
    def a2(cls):  
        print('这是一个类方法')  
  
    # 静态方法  
    @staticmethod  
    def a3():
        print('这是一个静态方法')

所有的方法都是存在 「类」 里面的 __dict__ 字典当中(和类属性存储位置一样)。

字典键值对的「值」,可以是任何数据类型(函数、方法等)。

实例方法

标准调用:

使用实例调用实例方法,不用手动传,自动调用对象本身传递

类方法

@classmethod 装饰器的作用:在保证原本函数不改变的前提下,直接给这个函数增加一些功能。

静态方法

3种方法对2种属性的访问

  • 3种方法:实例方法、类方法、静态方法。
  • 2种属性:类属性、方法属性。

实例方法的self,能访问实例属性和类属性。

类方法的cls,能访问类属性,不能访问实例属性。

类方法,能访问类属性,不能访问实例属性。一般不会用到。

类的补充

元类

元类,是创建类的类。

对象由类创建出来的,类本身也是对象,类对象也是另外一个类创建出来的,这个类就是元类。

类对象的创建方式

type是元类,也能通过type创建一个类。

类对象的创建流程

  • 1、查找类的内部是否有定义 __metaclass__
  • 2、查找父类是否定义 __metaclass__
  • 3、查找模块级别是否定义 __metaclass__
  • 4、通过内置 type 元类创建这个类对象

类的描述

目的:方便理清逻辑思路、方便多人合作开发沟通、方便生成项目文档。

生成项目文档

python -m pydoc -b

写入html文件 python -m pydoc -w 2401272037

属性的补充

私有化属性

Python没有真正的私有化,但可以用下划线完成伪私有效果。类属性(方法)和实例属性(方法)遵循相同的规则。

公有属性:类内部访问,子类访问,模块(文件)内其他位置访问、跨模块访问。

#doto 40 https://www.bilibili.com/video/BV1A4411v7b2?t=253.1&p=41