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