Python 对象学习一

时间:2021-02-22 19:02:25
#   对象的基本理论
# 什么是对象?
# 万物皆对象
# 对象是具体物体
# 拥有属性
# 拥有行为
# 把很多零散的东西,封装成为一个整体
# 举例:王二小
# 属性
# 姓名
# 年龄
# 身高
# 体重
# 行为
# 走路
# 吃饭
# 放羊
# Python中的体现
# 是一门特别彻底的面向对象编程(OOP)的语言
# 其他语言:基本数据类型,对象类型
# python全部类型都是对象类型
# 面向对象是面向过程的封装
# 对象和类的关系:对象 可以抽象为类 类可以实例化为对象 class Money:
pass print(Money) #<class '__main__.Money'>
one = Money()
print(one, type(one)) #<__main__.Money object at 0x030CFBB0> <class '__main__.Money'> class Person:
pass # 对象的操作:增
p = Person()
# 查看对象的所有属性
print(p.__dict__) #{}
p.age = 18
p.height = 180
print(p.__dict__) #{'age': 18, 'height': 180} # 对象的操作:删
del p.age # 对象的操作:改
p.height = 185 # 对象里面如果有这个属性,就是修改,否则就是增加这个属性 # 类里面的 __dict__ 不可以修改,只读的
# 对象里的 __dict__ 可以修改
class Test:
age = 18 #Test.__dict__["age"] = 20 #TypeError: 'mappingproxy' object does not support item assignment one = Test() one.__dict__ = {"name":"abc", "height":180} # __dict__字典里面生存储属性的变量
print(one.__dict__) #{'name': 'abc', 'height': 180} # 理解下面的内容
class Person:
age = 10 p = Person() print(Person.age) #
print(p.age) # p.age += 5 # p.age = p.age + 5
# 要理解这个在对象和类的操作方法:首先是计算右边的值,p.age 在对象p中没有,所以他要到类中去取age = 10
# 然后变成10+5 = 15, 然后在p对象中新增加个age属性(以前说过,对象没有就是新增,有的话就是修改) print(Person.age) #
print(p.age) # # __slots__
class Person:
__slots__ = {"age"} #只能加入age的属性 p1 = Person()
p1.age = 18
print(p1.age) # 方法:实例方法,类方法,静态方法 class Person:
def eat(self):
print("这是个实例方法", self) @classmethod
def eat2(cls):
print("这是个类方法", cls) @staticmethod
def eat3():
print("这是个静态方法") p = Person()
print(p)
p.eat()
p.eat2()
p.eat3()
# <__main__.Person object at 0x032F54F0>
# 这是个实例方法 <__main__.Person object at 0x032F54F0>
# 这是个类方法 <class '__main__.Person'>
# 这是个静态方法
print("-" * 30)
#另外的调用方式:
Person.eat("") #这里必须要有个参数,才能调用成功
Person.eat2()
Person.eat3() print("-" * 30) # 实例方法,类方法,静态方法的访问权限问题(包括类属性,实例属性)
class Person:
age = 10
# 实例方法
def shilie(self):
print(self)
print(self.age)
print(self.num) # 类方法
@classmethod
def leifangfa(cls):
print(cls)
print(cls.age)
print(cls.num) # 不可以使用实例属性 # 静态方法
@staticmethod
def jingtai():
print(Person.age) # 能使用类里面的属性,但很少这样去调用的 p = Person()
p.num = 11 p.shilie() # 实例方法:可以调用实例属性和类属性
#p.leifangfa() # 类方法:不可以使用实例属性
p.jingtai() # 静态方法:可以使用类属性,不可以使用实例属性 # 元类
num = 123
str = "abc"
print(num.__class__.__class__) # <class 'type'>
print(str.__class__.__class__) # <class 'type'>
print(Person.__class__) # <class 'type'>
print(Person.__class__.__class__)# <class 'type'>
print(p.__class__.__class__) # <class 'type'> # ----------------------------另外一种创建类的方式-------------------------
def run(self):
print(self) dog = type("Dog",(),{"name":"abc","run":run}) #字典里面可以是类属性,或者类方法
print(dog.name) #abc
print(dog.run) #<function run at 0x02B56C90> # ---------------------------类的创建流程---------------------------------- class Animal:
# __metaclass__ = xxx
pass class Person(Animal):
# __metaclass__ = xxx
pass # -------------------------类的描述, pydoc 模块---------------------------------------
class Person:
"""
关于类的描述,类的左右,类的构造函数
Attribute:
属性的描述
"""
def run(self, distence, step):
"""
函数的作用
:param distence:参数含义,数据类型,默认值
:param step:
:return: 返回值类型
"""
return distence / step # help(Person) # 可以这样看帮助文档 # ------------------------ 私有化属性(类的内部,子类内部,模块内部,模块外部)4大块 ------- class Animal:
x = 10
_y = 20
__z = 30
def test(self):
print(Animal.x)
print(self.x)
print(Animal._y)
print(self._y)
print(Animal.__z)
print(self.__z)
print("-" * 30) class Dog(Animal):
def test2(self):
print(Dog.x)
print(self.x)
print(Dog._y)
print(self._y)
# print(Dog.__z) # 错误
# print(self.__z) # 错误
print("-" * 30) # 类的内部访问
a = Animal()
a.test() # 成功打印x # 子类的内部访问
d = Dog()
d.test2() # 成功打印x # 模块内部访问
# print(Animal.x) # 成功打印x
# print(Dog.x) # 成功打印x
# print(a.x) # 成功打印x
# print(d.x) # 成功打印x
# print(a.__z) # 有错误
#
# print(Animal._y) # 成功打印_y,但有警告
# print(Dog._y) # 成功打印_y,但有警告
# print(a._y) # 成功打印_y,但有警告
# print(d._y) # 成功打印_y,但有警告
# print(a.__z) # 有错误
# print(d.__z) # 有错误 print(Animal.__dict__)
print(Animal._Animal__z) # 伪私有 30
# 模块外的访问
import public
print(public.num) # 成功打印num
print(public._num2) # 另外一种模块导入方法
from public import *
# 直接写public 模块中的变量
print(num) # 成功打印num
# print(_num2) # 有错误 # ------------------------ 私有化属性应用场景 ---------------------------------
# 数据保护,数据过滤
class Person: def __init__(self):
self.__age = 18 def setAge(self, value):
if isinstance(value, int) and 0 < value < 200 :
self.__age = value
else:
print("you input data error!!!") def getAge(self):
print("you age is ", self.__age)
return self.__age p = Person()
p.setAge(100)
print(p.getAge()) # --------------- 私有化的2个规范---------------------
# 1. x_ 这样命名的主要是区分系统的关键字,但又想用这个名字,所以在下面加下划线,比如 int_, class_
# 2. __x__ 这种命名的主要是系统的内置命名功能的变量 # --------------- 只读属性-------------------------
# __x 这样在类中命名的变量,既不能在实例属性中读取和修改,除非通过间接的办法来实现;
# 比如在类中通过写个函数来读取类中的 __x 变量;如果现在来改写一下只能读取的方式;
class Person:
def __init__(self):
self.__age = 18 @property
def age(self): # 这样就可以像正常通过实例属性来访问,但却不能通过实例属性来修改和增加
return self.__age p = Person()
print(p.age) #
# p.age = 111 # AttributeError: can't set attribute
# 上面的只读属性,也不是安全的,可以通过设置__dict__来修改
# p.__dict__["_Person__age"] = 999
p._Person__age = 888
print(p.age) # # --------------新式类(python 3.xx,继承object) 和 经典类(python 2.xxx 默认形式不继承object) ----------
class Person:
pass print(Person.__bases__) # (<class 'object'>,) 3.xx默认情况 # 也可以显示的显示如下,最好这样写,可以兼容2.xx:
class Person(object):
pass print(Person.__bases__) # (<class 'object'>,) # ------------- 设置只读属性的正确方法 ---------------------------
class Person:
# 需要只读的key 列表
attr_key = ["age","name"] # 当我们通过:实例.key = value 操作的时候都会调用这个方法 __setattr__
# 在这个方法的内部,在会把key : value 这些值存储到__dict__对象里面
def __setattr__(self, key, value):
print(key, value)
if key in self.attr_key and key in self.__dict__.keys() :
print("this is {} attrute only read ".format(key))
else:
# self.key = value # 这样写会有问题,涉入死循环
self.__dict__[key] = value p = Person()
p.age = 18 #执行到这里,就会打印 age 18
print(p.age) #
print(p.__dict__) # {'age': 18} p.age = 19 # 这里赋值后就会提示上面的错误 this is age attrute only read # --------------------------内置特殊属性----------------------
#类属性
# __dict__ 类的属性
# __bases__ 类的所有父类构成的属性
# __doc__ 类的文档字符串
# __name__ 类名
# __module__ 类定义中的模块
# __str__ 类定义字符串
#__call__ 实例直接调用 p() #实例属性
# __dict__ 实例属性
# __class__ 实例属性对应的类 class Person:
def __call__(self, *args, **kwargs):
print(args,kwargs) def __str__(self):
return "这个是个人类的类(字符串)" def __repr__(self):
return "这是个_repr_" p = Person()
p() # 类中有了__call__,就可以这样调用了,打印() {}
p("","abc", name="cctv") #('123', 'abc') {'name': 'cctv'} print(p.__str__()) #这个是个人类的类(字符串)
print(p) #这个是个人类的类(字符串)
print(p.__repr__()) #这是个_repr_
print(repr(p)) #这是个_repr_ # ------------------------ 索引操作 -------------------------------- class Person:
def __init__(self):
self.cache = {} def __setitem__(self, key, value):
print(key, value)
self.cache[key] = value def __getitem__(self, key):
print(key)
return self.cache[key] def __delitem__(self, key):
print(key)
del self.cache[key] p = Person()
p["name"] = "abc"
print(p["name"])
del p["name"] print(p.cache) #{} # --------------------- 比较操作 -----------------------------------
class Person:
# == ,!= , >, >= , < , =<
def __init__(self, age, height):
self.age = age
self.height = height def __eq__(self, other):
# print(self.age, other.age)
return self.age == other.age def __ne__(self, other):
return self.age != other.age def __gt__(self, other): #大于
pass def __ge__(self, other): #大于等于
pass def __lt__(self, other): #小于
pass def __le__(self, other): #小于等于
pass p1 = Person(18, 180)
p2 = Person(18, 190)
print(p1 == p2) # True print(p1 != p2 ) # False # -------------------- 上下文的布尔判断 -----------------------------
class Person:
def __init__(self):
self.age = 19 def __bool__(self):
return self.age >= 18 p1 = Person()
if (p1):
print("p Ture") # p Ture # --------------------遍历操作 --------------------------------------
class Person:
def __init__(self):
self.result = 0 # 和上面的索引操作一样
def __getitem__(self, item):
self.result += 1
if (self.result > 5 ):
raise StopIteration("停止遍历")
return self.result # 这个要优先于__getitem__ 运行
def __iter__(self):
self.result = 0 # 迭代器次重复使用
return self def __next__(self):
self.result += 1
if (self.result > 5):
raise StopIteration("next停止遍历")
return self.result p = Person()
for v in p :
print(v) # 1 2 3 4,5 # ----------------------- 描述器 ---------------------------
# 方法一:举例
class Person:
def __int__(self):
self.__age = 18 def get_age(self):
return self.__age def set_age(self, value):
if value < 0 :
value = 0
self.__age = value def del_age(self):
del self.__age # 方法一
age = property(get_age, set_age, del_age) p = Person()
p.age = 10 # 一定要赋值,不然下面调用就会错误
print(p.age) class Person:
def __int__(self):
self.__age = 18 @property
def age(self):
return self.__age
@age.setter def age(self, value):
if value < 0:
value = 0
self.__age = value @age.deleter
def del_age(self):
del self.__age p = Person()
p.age = 20 # 一定要赋值,不然下面调用就会错误
print(p.age) # -------------------方法二------------------------
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() p = Person()
p.age = 10
print(p.age) # -------------------使用类,实现装饰器 -----------------------
# 以前学过通过函数来实现装饰器,如:
def checkLogin(func):
def inner():
print("正在登陆认证")
func()
return inner @checkLogin
def fashuoshuo():
print("发说说") fashuoshuo() #正在登陆认证 发说说 # 现在换成类的形式
class Check:
def __init__(self, func):
self.f = func def __call__(self, *args, **kwargs):
print("正在登陆认证")
self.f() @Check
def fatupian():
print("发图片") fatupian() # 正在登陆认证 发图片 # ---------- 几个监听对象生命周期的方法-------------
class Person:
# def __new__(cls, *args, **kwargs):
# print("新建一个对象的时候, 但被我拦截了")
def __init__(self):
print("这个类被初始化了") def __del__(self):
print("这个对象被释放了") p = Person() # 新建一个对象的时候, 但被我拦截了
print(p) # None
p = Person() #这里要把 __new__ 给注释掉,不然会被拦截 # ---------- 几个监听对象生命周期的方法:小案例-------------
# Person, 打印一下,当前这个时刻,由Person类,产生的实例,有多少个
# 创建了一个实例,计数+1,如果删除了一个实例 计数-1 class Person:
__personCount = 0 def __init__(self):
self.__class__.__personCount += 1 # 和下面的Person.__personCount 的方法是一样的 def __del__(self):
# Person.__personCount -= Person.__personCount - 1 有些问题
self.__class__.__personCount -= 1
@staticmethod
def log():
# print("当前创建人的实例有{}个".format(Person.__personCount))
print("当前创建人的实例有%d个"%Person.__personCount) # 或者写成下面的形式
@classmethod
def log2(cls):
print("当前创建人的实例有%d个" % cls.__personCount) p = Person()
p2 = Person()
Person.log() # 当前创建人的实例有2个
Person.log2() # 当前创建人的实例有2个
del p2
Person.log() # 当前创建人的实例有1个
Person.log2() # 当前创建人的实例有1个 # ----------------对象 内存管理机制 存储 ---------------------
num1 = 1
num2 = 1
print(id(num1), id(num2) ) #相同数值的变量地址一样,访问的是同一个地址,这是Python的机制决定的,优化访问时间 class Person:
pass p = Person()
p2 = Person()
print(id(p), id(p2)) # 打印地址不一样 # ----------------引用计数器 ---------------------
import sys
#
class Person:
pass p1 = Person()
# 获得对象的引用次数
print(sys.getrefcount(p1)) # p2 = p1
print(sys.getrefcount(p1)) #
print(sys.getrefcount(p2)) #
del p1 del p2 # ------------- 引用计数器机制-特殊场景--循环引用问题-----------
# 内存管理机制:引用计数器机制 + 垃圾回收机制
# 当一个对象被引用时 +1, 删除一个引用 -1 ,0:自动释放
# objgraph
# objgraph.count(), 可以查看,垃圾回收器,跟踪的对象个数 import objgraph
class Person:
pass class Dog:
pass p = Person()
d = Dog() p.pet = d
d.master = p
print(objgraph.count("Person")) #
print(objgraph.count("Dog")) # del p
del d
print(objgraph.count("Person")) # 1 这样就造成了内存泄露
print(objgraph.count("Dog")) # # --------------内存管理机制 垃圾回收 如何检测循环引用 -----------
# --------------垃圾回收机制 分代回收 ------------
# --------------垃圾回收机制中 新增的对象个数 - 消亡的对象个数 达到一定个数才会触发垃圾检测
import gc
#查看阀值,700个对象,10次
print(gc.get_threshold()) # (700, 10, 10)
gc.set_threshold(200,5,5) # 设置参数
print(gc.get_threshold()) # (200, 5, 5) # --------------垃圾回收机制 触发时机(自动,和手动)
import gc # 自动回收
# 查看垃圾回收机制是否开启,默认是开启的
print(gc.isenabled()) # True
# 达到一定的阀值才会执行
# 关闭垃圾回收机制
gc.disable() # 手动回收
import gc
import objgraph class Person:
pass class Dog:
pass p = Person()
d = Dog() p.pet = d
d.master = p del p
del d
gc.disable() #关闭垃圾回收后,下面语句也有效果
# 通过“引用计数器机制”无法回收;需要借助“垃圾回收机制”进行回收
gc.collect() # 参数有:空,0,1,2 空代表全部代的回收,0,代表0代回收,2,代表0,1,2代都回收
# 查看
print(objgraph.count("Person")) #
print(objgraph.count("Dog")) #