写在前面

参考视频(推荐1.5倍速食用):https://www.bilibili.com/video/BV1A4411v7b2?p=31&vd_source=1a36db16e3fec3ccbe040303ff015aab 参考博客:https://blog.csdn.net/qq_41872653/article/details/109256914 # Chapter1、面向对象基本概念 ## 1、什么是面向对象编程? 面向对象编程(Object-Oriented Programming,OOP)是一种常用的编程思想,它强调万物皆对象,因此在编程时我们可以将现实世界中的事物抽象成程序中的对象,从而更好实现软件的设计与开发。与传统的基于函数的编程不同,面向对象编程注重于将数据与行为封装在一起,即对象既包含数据状态,还包含可调用的行为方法。

面向对象编程的特点在于,它具有封装、继承和多态三大特性。封装意味着将对象的状态和行为进行封装,使其对外只暴露必要的接口,从而提高了安全性和可维护性;继承指的是某个对象可以继承另一个对象的特性,从而快速构建具有相似属性的对象;多态是指同一种行为在不同的对象上具有不同的表现形式,即在不同的情境下,同一个方法可以被不同的对象进行调用。

总之,面向对象编程是一种强大的编程方式,它具有高度封装性、灵活的继承性和强大的多态性,通过使用对象作为程序的基本处理单元,实现了数据和行为的有机结合,可以使程序更加高效、结构清晰,并方便管理和扩展。 ## 2、对象和类的关系 对象可以抽象出某个具体的类,类可以实例化成某个具体的对象。

Chapter2、类的基本语法

1
2
3
4
5
6
7
8
9
class Dog:
d_type = "京巴" #属性,类属性,类变量
def say_hi(self): #方法,第一个参数必须是self self代表实例本身
print("my type is",self.d_type)

d=Dog()#生成一个实例
d.say_hi()#实例、方法

print(d.d_type)#实例、属性

1、类的命名要求首字母大写。

1
2
3
4
class Money:
print(Money.__name__)#打印Money类的类名
xxx=Money#Money作为变量赋值给xxx
print(xxx.__name__) #打印结果还是Money类名

属性相关

2、属性相关概念

变量是可以改变的量值;属性是“属于某个对象的特性”。变量根据访问位置的不同,分为全局变量和局部变量;属性只能通过对象来访问,所以必须先找到对象————而对象又通过变量名来访问,故也遵循访问权限。 ### 3、属性添加

1
2
3
4
5
class Person:
pass
p = Person()#创建对象
p.age = 18#添加属性
print(p.__dic__ )
### 4、属性修改
1
2
3
4
5
6
class Person:
pass
p = Person()#创建对象
p.age = 18#添加属性
p.age = 123#修改
print(p.__dict__ )
当我们修改没有创建过的属性时:
1
2
print(p.sex) 
报错AttributeError:
### P13、属性删除
1
2
3
4
5
6
7
class Person:
pass
p = Person()
p.age = 18
del p.age
print(p.age)#AttributeError:
先删除属性,再删除引用的变量。
### P14、注意事项 不同对象的属性不能互相访问。 ### P15、类属性-增加属性 万物皆对象,类也可以是一个对象。 注意,当我们创建一个类的时候,我们实际上也创建了一些类的内置属性(name,__module__等)
1
2
3
4
class Money:
pass
Money.count = 1 #Money看做对象,Money增加count属性
print(Money.count)
### P17、类属性查询
1
2
3
4
5
6
7
class Money:
pass
class Test:
pass
one=Money()
one.__class__=Test
最后one只能访问到Test的类属性
注意:一个对象,如果要去访问某个属性,它会优先查找自己有没有这个属性,有就返回;若没有,则在类中找。都没有就报错AttributeError: ### P18、类属性修改
1
2
3
4
5
6
7
class Money:
age=28
count=1
num=666

Money.age=22 #通过类名-属性修改
print(Money.age)
注意:不可通过对象修改! one是一个对象,one.age=99是给one对象增加一个age指向99的属性,而不是修改类的属性。 ### P19、类属性删除
1
del Money.age
注意:不能通过对象来删除。

总结类属性操作

增、删、改类属性都只能通过类。查询可通过对象和类操作。

P20、类属性的内存存储

1)one访问某个属性,实际上访问的是生成的对象里面__dict__字典的值。

1
2
3
4
5
6
class Money:
pass
one=Money()
one.__dict__={'age':99}
print(one.age)
>>>99
2)的__dict__属性不能被写,只读。
1
2
3
4
5
class Money:
age=20

Money.__dict__={'sex':'男'}
>>>报错
反过来讲,对象的dict可以随便改www ### P21、类属性会被各个对象所共享
1
2
3
4
5
6
7
8
class Money:
age=20

one=Money()
two=Money()##均指向类的age=20,因为自身没有age属性

print(one.age,two.age)
>>>都是20
### P23、限制对象属性的添加__slots__
1
2
3
4
5
6
7
class Person:
__slots__ = ["age"]#限制对象不能添加age属性
pass

p=Person()
p.age=6
>>>报错

方法相关

P25、概念和作用

1.描述一个目标的行为动作 2.和函数非常类似,都封装了一系列动作,都可以被调用之后执行一系列行为动作,最主要的时调用方式

1
2
3
4
5
6
7
class Person
def eat2(self):
print(1)
print(2)
print(3)
p = Person()
p.eat2()
### P26、类、对象、类对象、实例对象、实例的叫法规范 ### P27、方法的划分 · 实例方法:第一个参数接受实例 · 类方法:第一个参数接受类 · 静态方法:non 划分的依据:方法的第一个参数必须接受的数据类型
1
2
3
4
5
6
7
8
9
10
class Person:
def eat2(self):
print('这是一个实例方法',self)
@classmethod
def leifangfa(cls):
print('这是一个类方法',cls)
@staticmethod
def jiangtaifanfa():
print('这是一个静态方法')

1
2
Person.eat2()
>>>TypeError #确少self
### P28、方法的储存 (1)函数也是对象 (2)方法也保存在类的__dict__中,没有在实例当中的 ### P29、要求 使用注意: 1.语法 2.不同类型的方法的规则 3.不同方法的调用 ### P30、实例方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#标准调用
class Person:
def eat(self,food):
print("在吃饭",food)

p=Person()
p.eat("potato")#只需要传一个参数
----------------------------------
class Person:
def eat(): #报错,因为以为没有要求传self,但p.eat实例调用时硬塞了一个
实例参数self
print('在吃饭')

p.eat()
### P31、类方法
1
2
3
4
5
6
7
8
9
10
11
12
13
class Person:
@classmethod #装饰器的作用:在保证原函数不变的情况下,直接给这个函数增加一些功能
def leifangfa(cls,a):
print("这是一个类方法" , a)

Person.leifangfa(123)

p = person()
p.leifangfa(666)

func = Person.leifangfa
func(111)

### P32、静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
class Person:
@staticmethod #装饰器的作用:在保证原函数不变的情况下,直接给这个函数增加一些功能
def jingtai(cls):
print("这是一个类方法")

Person.jingtai()

p = Person()
p.jingtai()

func = Person.jingtai
func()

### P33、不同类型的方法中访问不同类型的属性的权限问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person:
age = 0
def shilifangfa(self):
print(self)
print(self.age)
print(self.num)#可访问到对象属性
@classmethod
def leifangfa(cls):
print(cls)
print(cls.age)
print(cls.num) #不能通过类访问实例属性
@staticmethod
def jingtaifangfa():
print(Person.age) #可以通过类访问类属性
P = person()
P.num = 10
### 类相关补充 ### P34、补充-元类 类也是由类创建出来的,这个类就是元类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
num = 1
print(num.__class__) #输出int
%------------------------------------------
s = "abc"
print(s.__class__) #输出str
%------------------------------------------
class Person:
pass
p = Person()
print(p.__class__) #输出Person
%------------------------------------------
print(int.__class__) #输出type
#其实也是num.__class__.__class___
print(type.__class__)#依然输出type
type即为元类 ### P35、补充-类对象的创建方式 可以class直接创建 也可以调用type函数创建
1
2
3
4
5
6
7
8
9
def run(self):
print(self)
xxx = type("Dog",(),{"count":0,"run":run})
print(xxx)
print(xxx.__dict__)

d.xxx() #不是d.Dog
print(d)
d.run()
### P36、类对象创建时,元类的查找机制 1.检测类对象是否有明确的__mateclass__属性。 2.检测父类中是否存在__mateclass__属性。 3.检测模块中是否存在__mateclass__属性。 4.通过内置的type这个元类来创建这个类对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
查找一般是现在自己里面找,没有就去父类,父类没有就往上找模块,模块没有就是type
#1模块级别的指定
__metaclass__ = xxx
#2
class Animal:
pass
#3
class Dog(Animal):
pass
#4
class Dog:
__metaclass__ = xxx
pass

### P37、补充-类的描述
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person:
"""
关于这个类的描述,类的作用,类的构造函数等等;类属性的描述
Attributes:
count: int 代表人的个数
"""
count = 1
def run(self, disance, step):
"""
这个方法的作用效果
:param distance:blahblah
:param step:blahblah
:return:
"""
print("跑步")
return distance,step
help(Person) #
### P38、生成注视文档 ### 属性相关补充 ### P39、补充-私有化属性的概念和意义 限定属性的访问的方法 ### P40、补充-访问权限测试区域划分 ### P41、补充-访问权限测试区域划分 注意:python并没有真正的私有化支持,但是,可以使用下划线完成伪私有的效果。如_y、__z。 一个_为保护,两个_为私有化 ### P41、私有化属性-共有属性 1.类的内部访问,也就是类的实例方法中 2.子类(延伸类)内部访问 3.模块其他位置访问 * 1.类访问(父类,派生类) * 2.实例访问(父类实例,派生类实例 4.跨模块访问 import/from xxx import *

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Animal:
x = 10
def test(self):
print(Animal.x)
print(self.x)
pass
%----------------------
class Dog(Animal):
def test2(self):
print(Dog.x)
print(self.x)
pass

a = Animal()
a.test() #类的内部访问,通过类内部定义的函数访问

d = Dog()
d.test2() #延伸类的访问(通过延伸类内部定义的函数访问)

print(Animal.x) #模块的其他部分
print(Dog.x)
print(a.x)
print(b.x)

import xxx #模块的其他部分访问
print(xxx.a)
from xxx import *
print(a)

P42、私有化属性-受保护的属性

_y:一个下划线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Animal:
_x = 10
def test(self):
print(Animal._x)
print(self._x)
pass
#--------------------
class Dog(Animal):
def test2(self):
print(Dog._x)
print(self._x)
pass

a = Animal()
a.test() #类的内部访问

d = Dog()
d.test2() #延伸类的访问

print(Animal._x) #模块的其他部分,可以强行访问,有警告
print(Dog._x)
print(a._x)
print(b._x)

import xxx #模块的其他部分访问,不可访问
print(xxx.a)
from xxx import *
print(a)

一般只能在类内部访问,或者子类内部访问。 ### 43、私有化保护-私有属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Animal:
__x = 10
def test(self): #定义一个实例方法
print(Animal.__x)
print(self.__x)
pass

#--------------------

class Dog(Animal):
def test2(self):
print(Dog.__x)
print(self.__x)
pass

a = Animal()
a.test() #类的内部访问,可以访问

d = Dog()
d.test2() #延伸类的访问,不可以访问

print(Animal.__x) # 模块的其他部分,不可访问
print(Dog.__x)
print(a.__x)
print(d.__x)

a = 1
import xxx #模块的其他部分访问,不可访问
print(xxx.a)
from xxx import *
print(a)

### 45、补充-私有属性的应用场景
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Person:
#作用:当我们创建好一个实例对对象之后,会自动调用这个方法,来初始化这对象
#init是单词初始化initialization的省略形式
def __init__(self)
self.__age = 18
def setAge(self,value):
if isinstance(value,int) and 0<value<200:
self.__age = value
else:
print("您输入的数据有误,请重新输入")
def getAge(self):
return self.__age


p1 = Person()
p1.setAge(20)
p2 = Person()
print(p1.getAge()) #访问age

print(p1.__age) #报错,只能在类内部访问
print(p2.__age)

### P48、只读属性-方案1
1
2
3
4
5
6
7
class Person:
def init(self): #初始化方法,通过方法设置属性
self.__age = 18
def getAge(self): #部分公开,通过方法实现
return self.__age
p1 = person()
print(p1.getAge())
### P49、只读-方案一优化 这节讲得真好,承上启下。
1
2
3
4
5
6
7
8
9
10
11
## 49-python-面向对象-只读属性-方案一的优化
1. ```python
class Person(object):
def __init__(self):
self.__age = 18
# 主要作用:可以以使用属性的方法来使用这个方法
@property
def age(self): #部分公开,通过方法实现
return self.__age
p1 = person()
print(p1.age())
### P50、property的作用 property的作用:将“一些属性的操作方法”关联到另一个属性,间接地管理私有属性。
1
2
3
4
5
6
class C(object):
def getx(self): return self._x
def setx(self,value): self._x = value
def delx(self): del self._x
x = property(getx, setx, delx)
#此时,x就是一个属性,可以直接调用x的属性来调用方法
### P51、经典类和新式类 - 经典:没有继承object - 新式:继承object Py3中,定义一个类,已经隐式地继承object,默认下已经是一个新式类。
1
2
3
4
class Person:
pass

print(Person.__bases__) #查看父类(基类)
### P52、property在新式类中的使用

  • property函数方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Person(object):
    def __init__(self):
    self.__age = 18
    def get_age(self):
    ruturn self.__age
    def set_age(self, value):
    self.__age = value
    age = property(get_age, set_age)

    p = Person()
    print(p.age)

    p.age = 30
    print(p.age)
    print(p.__dict__) #输出只有_person__age:
  • 装饰器方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Person(object):
    def __init__(self):
    self.__age = 18
    @property
    def age(self):
    return self.__age
    @age.setter
    def age(self, value):
    delf.__age = value

    p = Person()
    p.age = 20 #既可以读取也可以设置

    ### P53、property在经典类中的使用 放弃吧,都用新式类叭! ### P54、只读属性-方案二 总之就是,__ age只不过是把他改了个名字,改成_ 类名 __ age,你知道他的新名字的话你当然可以改。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Person:
    #当我们通过实例.属性 = 值,给一个实力增加一个属性,或者修改属性的时候,就会自动调用这个方法,
    #在这个方法内部才会正真地把这个属性,以及对应的数据存储到__dict__字典里面
    def __settter__(self, key, value):
    print(key, value)
    #1.判定,key,是否是我们要设置的只读属性
    if key = "age" and key in self.__dict__.keys():#只能新增属性,不能修改属性
    print("这个属性是只读属性,不能设置数据")
    #2.如果不是只读属性,就给他添加到实例里面去
    else:
    #self.key = value #这样会陷入死循环
    self.__dict__[key] = value

    ### P55、常用内置属性
  1. 类属性:
    • dict:类属性
    • bases:类的所有父类构成元组
    • __doc__类的文档字符
    • __name__类名
    • __module__类定义所在模块
  2. 实例属性
  • dict:类的实例
  • class:实例对应的类
1

内置方法

内置方法的作用;完成一些特定的功能 ### P57、信息格式化操作-* __ str __ *

1
2
3
4
5
6
7
8
9
10
class Person:
def __init__(self,n,a):
self.age = a
self.name = n
def __str__(self):
return "name is %s , age is %s . "%(self.name,self.age)

p=Person(Ray,18)
print(p)
>>> name is Ray, age is 18.

P58、信息格式化操作-* __ repr __ *

主要面向开发者

1
2
3
4
def Person:
def __init__(self):
return"repr"

如果没有定义__str__,那么str也返回的是__repr__的内容。 触发__str__的方法: - 直接打印:print(p1) - str方法:s=str(p1) print(s) 触发__repr的方法: - s=repr(p1) print(s) - 在交互模式里面将对象名称写出,敲回车 ### P60、* call __ * __call__的作用:使得对象具有当作函数来调用的能力(将对象变为可调用对象)。当你把对象写出调用函数的形式,就会自动去找call
1
2
3
4
5
6
7
class Person:
def __call__(self):
print("xxx")
pass
p = Person()
p() #调用__call__函数

### P61、call的使用例子
1
2
3
4
5
6
7
8
class PenFactory:
def __init__(self, p_type):
self.p_type = p_type #这个类只有一个属性
def __call__(self, p_color):
print("创建了一个%s类型的画笔,他是%s颜色的"%(self.p_type, p_color))
gangbiF = penFactory("钢笔") #创建一个对象
gangbiF('红色')

### P62、索引操作 需要一个字典属性,才可以对对象进行索引操作
1
2
3
4
5
6
7
8
9
10
11
12
class Person:
def __init__(self):
self.cache = {} #定义cache属性,为一个字典
def __setitem__(self, key, value):
self.cache[key] = value
def __getitem__(self, key):
return self.cache[key]
def __delitem__(self, key):
del self.cache[key]
p = Person()
p['name'] = 'sz' #执行这行代码的时候,会调用第一个方法
print(p['name']) #调用第二个方法
### P63、切片操作 没听懂orz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person:
def __init__(self):
self.items = [1, 2, 3, 4, 5, 6, 7, 8] #定义了一个items属性

def __setitem__(self, key, value):
if isinstance(key,silce):
self.items[key] = value #注意切片操作只能修改,不能新增
#self.items.[key.start: key.stop: key.step] = value #这样赋值也可以
def __getitem__(self, key):
return(key.items[key]) #这里可能有错
def __delitem__(self, key):
del self[key]
p = Person()
p[0: 4: 2] = ["a","b"]
print(p.items[0: 4: 2])
### P64、比较操作 映射的内置方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person:
def __init__(self, age, height):
self.age = age
self.height = height
def __eq__(self, other):
return self.age == other.age #指定相等的比较通过哪个属性比较,
def __ne__(self, other):
return self.age != other.age #指定相等的比较通过哪个属性比较,
p1 = Person(18, 180)
p2 = Person(19, 183)
print(p1 == p2)
#类似的还有:
#gt >
#ge >=
#lt <
#le <=
#可以通过调换参数的方式定义比较方法,进而简化代码
### P65、比较操作 注意到p1 < p2,等价于p2 > p1。 如果对于反向操作的比较符,只定义了其中一个方法,但使用的是另外一种比较运算,那么,解释器会采用调换参数的方式进行调用该方法。 ### P66、比较操作-方案2(通过装饰器自动补全) 解决小于等于,大于等于的反向操作。
1
2
3
4
5
6
7
8
import functools

@functools.total_ordering #此装饰器会自动补全所需要的方法
class Person
def __lt__(self, other):
pass
def __eq__(self, other):
pass
### P67、上下文布尔值 此方法使对象可以被作为一个布尔值使用。
1
2
3
4
5
6
7
8
9
class Person():
def __bool__(self): #通过bool值判定实例是True或False
return False #这里也可以是一个返回布尔值的语句
pass

p = Person()
if p:
print("xx")
>>>不打印
结合比较操作
1
2
3
4
5
6
7
8
9
10
class Person:
def __init__(self):
self.age=20
def __bool__(self):
if self.age >= 18:
return True

p = Person()
if p:
print("已成年")
### P68、遍历操作-getitem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")

return relf.result
pass
p = person()

for i in p: #当执行for循环时,自动进入__getitem__方法,使用这个方法的返回值作为数据
print(i)

### P69、遍历操作-iter iter优先级高于getitem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")

return relf.result
def __iter__(self):
print("hfkjasdf")
p = person()

for i in p: #当执行for循环时,自动进入__geritem__方法,使用这个方法的返回值作为数据
print(i)
首先调用iter,返回一个迭代器,然后调用__next__方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
#return iter([1,2,3,4]) 如果返回是迭代器,则自动进入迭代器的__next__方法
return relf.result
def __iter__(self):
return self
def __next__(self):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.result
p = person()

for i in p:
print(i)
总之就是,遍历对象时,先去找有没有iter,如果有的话,再去找next看他的输出,如果可以输出则迭代,如果输出停止不能输出了就停止迭代。 ### P70、便利操作-直接next遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
#return iter([1,2,3,4]) 如果返回是迭代器,则自动进入迭代器的__next__方法
return relf.result

def __next__(self):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.result
p = person()

print(next(p)) #直接进入__next__方法
print(next(p))
print(next(p))
print(next(p))
print(next(p)) #抛出异常,停止遍历

### P71、便利操作-迭代器的复用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person:
def __init__(self):
self.age = 1

def __iter__(self):
self.age = 1 # 如果没有这行命令,那么迭代器只能使用一次
return self

def __next__(self):
self.age += 1
if self.age >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.age

p = person()
for i in p:
print(i)
import collection
print(isinstance(p, collection.Iterator))
#返回值为True,表明确实是一个迭代器,需要同时有两个方法__iter__、__next__
next(p) #只要有一个方法__next__就可以访问
通过item里面的age归位,调为初始值。否则第一次迭代后age就变为终止值了,不满足迭代的条件。 ### P72、遍历操作-迭代器-可迭代的判定依据
1
2
3
import collection
print(isinstance(p, collection.Iterable))#判定是否为可迭代对象,只要一个方法__iter__就可以

一个可迭代对象一定可以通过for in访问,可以通过for in访问的不一定是可迭代对象。 ### P73、遍历操作-iter()的使用 我超这一点都不便利www ### P74、描述器 概念和作用:描述器是一个对象,可以描述一个属性的操作;其作用是对属性的操作做验证和过滤,如对一个人的年龄赋值时,不能赋值为负数,这是需要验证和过滤,但由于属性数量多,不能在赋值前进行验证,所以用到描述器,每次验证时就会进入描述器中进行相关操作 ### P75、描述器-定义方式1-property
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Person:
def __init__(self):
self.__age = 10

@property
def age(self):
return self.__age

@age.setter
def age(self, value):
if value < 0:
value = 0
self.__age = value

@age.deleter
def age(self):
del self.__age


p = Person()
p.age #注意:这里的age是方法里面的age,不是属性的age
del p.age

### P76、描述器-定义方式2-封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Age:        #描述器类
def __get__(self, instance, owner):
print("get")
def __set__(self, instance, value):
print("set")
def __delete__(self, instance):
print("delete")

class Person: #主类
age = Age()

p = Person()
p.age = 10

### P77-P79、调节细节 ### P80、调节优先级 - 资料描述器 get set - 非资料描述器 仅仅实现了get - 资料>实例>非资料 ### P81、数据存储问题 弹幕:这么理解吧,age=Age(),本身这个就是在建立相同的对象,就是self打印的地址一样,instance就是self下的小单元,操作这个每个对象才有不同值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Age:
def __get__(self, instance, owner):
print("get")
return self.v
def __set__(self, instance, value):
print("set")
self.v = value

def __delete__(self, instance):
print("delete")

class Person:
age = Age()

p = Person()
p.age = 10
print(p.age)
>>>set
get
10
--------------------------------------------------
p2 = Person()
p2.age = 11
print(p2.age)
>>>11
这时候如果再打印p的话
>>>11
因为都是储存在age里,也就是Age只有一个对象self,即age
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
如果绑定在instance上的话:
class Age:
def __get__(self, instance, owner):
print("get")
return instance.v
def __set__(self, instance, value):
print("set")
instance.v = value

def __delete__(self, instance):
print("delete")

class Person:
age = Age()

就可以分别打印,分别存储
### P82、装饰器-类函数 引入:在不改变某个def函数本身的情况下,增加这个函数的功能,如何?

注意层级,def fashuoshuo()是函数并不是方法,fashuoshuo接收了check,所他自己就是check实例了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def check(func):
def inner():
print("登录成功")
func()
return inner


@check
def fashuoshuo():
print("发说说")

fashuoshuo()
>>>
"登录成功"
"发说说"