Python 对象学习一

#   对象的基本理论
#   什么是对象?
#   万物皆对象
#       对象是具体物体
#                       拥有属性
#                       拥有行为
#                       把很多零散的东西,封装成为一个整体
#       举例:王二小
#                   属性
#                           姓名
#                           年龄
#                           身高
#                           体重
#                   行为
#                           走路
#                           吃饭
#                           放羊
#       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) # 10
print(p.age)      # 10

p.age += 5 #    p.age = p.age + 5
#   要理解这个在对象和类的操作方法:首先是计算右边的值,p.age 在对象p中没有,所以他要到类中去取age = 10
#   然后变成10+5 = 15, 然后在p对象中新增加个age属性(以前说过,对象没有就是新增,有的话就是修改)

print(Person.age) # 10
print(p.age)      # 15

#   __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("123")  #这里必须要有个参数,才能调用成功
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)    #   18
#   p.age = 111 #   AttributeError: can't set attribute
#   上面的只读属性,也不是安全的,可以通过设置__dict__来修改
# p.__dict__["_Person__age"] = 999
p._Person__age = 888
print(p.age)    #   888

#   --------------新式类(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)    # 18
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("123","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)) #    2

p2 = p1
print(sys.getrefcount(p1))  #   3
print(sys.getrefcount(p2))  #   3
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")) #   1
print(objgraph.count("Dog"))    #   1

del p
del d
print(objgraph.count("Person")) #   1   这样就造成了内存泄露
print(objgraph.count("Dog"))    #   1

#   --------------内存管理机制    垃圾回收    如何检测循环引用    -----------
#   --------------垃圾回收机制    分代回收    ------------
#   --------------垃圾回收机制中   新增的对象个数 -  消亡的对象个数 达到一定个数才会触发垃圾检测
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")) #   0
print(objgraph.count("Dog"))    #   0

 

posted @ 2018-03-09 22:54  delphiclub  阅读(198)  评论(0编辑  收藏  举报