python 面向对象的进阶

isinstance和issubclass

isinstance(obj,cls)检查是否obj是否是类 cls 的对象

isinstance(obj,cls)检查是否obj是否是类 cls 的对象

class A:pass
class B(A):pass
a = A()
print(isinstance(a,A))   #t
print(issubclass(B,A)) #t
print(issubclass(A,B)) #f

反射

反射:是用 字符串类型的名字 去操作 变量。有 hasattr、getattr、 setattr、 delattr 四个相关函数。
与eval相似,但eval主要用来网络传输,操作文件或别人的代码,存在安全隐患。反射值操作写在内存中的名字,没有安全隐患。
反射对象中的属性和方法(getattr)
class A:
    def func(self):
        print('in func')

a = A()
a.name = 'alex'
a.age = 63
# 反射对象的属性
ret = getattr(a,'name')  # 通过变量名的字符串形式取到的值
print(ret)
print(a.__dict__)
变量名 = input('>>>')   # func
print(getattr(a,变量名))
print(a.__dict__[变量名])  # 不能用于方法

# 反射对象的方法
a.func()
ret = getattr(a,'func')
ret()
反射类中的属性和方法(getattr/hasattr)
class A:
    price = 20
    @classmethod
    def func(cls):
        print('in func')
# 反射类的属性
# A.price
print(getattr(A,'price'))

# 反射类的方法 :classmethod staticmethod
# A.func()
if hasattr(A,'func'):
    getattr(A,'func')()
反射模块的属性和方法
import my
反射模块的属性
print(my.day)
print(getattr(my,'day'))

反射模块的方法
getattr(my,'wahaha')()

# 内置模块也能用
#time
asctime
import time
print(getattr(time,'time')())
print(getattr(time,'asctime')())
反射自己模块的属性和方法
def qqxing():
    print('qqxing')
year = 2018
import sys
print(sys.modules['__main__'].year)
# 反射自己模块中的变量
# print(getattr(sys.modules['__main__'],'year'))

# 反射自己模块中的函数
# getattr(sys.modules['__main__'],'qqxing')()
变量名 = input('>>>')
print(getattr(sys.modules[__name__],变量名))
要反射的函数有参数怎么办?当有多个参数不同时,不可使用
print(time.strftime('%Y-%m-%d %H:%M:S'))
print(getattr(time,'strftime')('%Y-%m-%d %H:%M:S'))
一个模块中的类也能反射得到,只要是有 . 的都可以反射。
import my
print(getattr(my,'C')()) # <my.C object at 0x0046BB70>
if hasattr(my,'name'):
    getattr(my,'name')
setattr 、delattr
# 重要程度半颗星
# setattr  设置修改变量
class A:
    pass
a = A()
setattr(a,'name','nezha')
setattr(A,'name','alex')
print(A.name)
print(a.name)

# delattr 删除一个变量
delattr(a,'name')
print(a.name)
delattr(A,'name')
print(a.name)
类的内置方法
内置的类方法 和 内置的函数 之间有着千丝万缕的联系。
__str__/__repr__
双下方法
obj.__str__  str(obj) 
obj.__repr__ repr(obj)
class Teacher:
    def __init__(self,name,salary):
        self.name = name
        self.salary = salary
    def __str__(self):
        return "Teacher's object :%s"%self.name
    def __repr__(self):
        return str(self.__dict__)
    def func(self):
        return 'wahaha'
nezha = Teacher('哪吒',250)
print(nezha)  # 打印一个对象的时候,就是调用a.__str__
print(repr(nezha))
print('>>> %r'%nezha)

a.__str__ --> object object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址 l = [1,2,3,4,5] # 实例化 实例化了一个列表类的对象 print(l) 走的是list类里面的__str__ %s str() 直接打印 实际上都是走的__str__ %r repr() 实际上都是走的__repr__ print(obj)/'%s'%obj/str(obj)的时候,(打印一个对象)
实际上是内部调用了obj.__str__方法,如果str方法有,那么他返回的必定是一个字符串。
如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类中的__str__。
父类是自定义类时,如果没有__str__方法,会先到父类找str,再找自己的repr。再去找objiect类的str,repr
总之,object在最后。

repr(),只会找__repr__,如果没有找父类的。
repr 是str的备胎,但str不能做repr的备胎
内置的方法有很多
不一定全都在object中
class Classes:
    def __init__(self,name):
        self.name = name
        self.student = []
    def __len__(self):
        return len(self.student)
    def __str__(self):
        return 'classes'
py_s9= Classes('python全栈9期')
py_s9.student.append('二哥')
py_s9.student.append('泰哥')
print(len(py_s9)) #走len
print(py_s9)#走str
一个应用的小例子

__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class A:
    def __del__(self):   # 析构函数: 在删除一个对象之前进行一些收尾工作
        self.f.close()
a = A()
a.f = open()   # 打开文件 第一 在操作系统中打开了一个文件 拿到了文件操作符存在了内存中
del a          # a.f 拿到了文件操作符消失在了内存中
del a   # del 既执行了这个方法,又删除了变量

__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class A:
    def __init__(self,name):
        self.name = name
    def __call__(self):
        '''
        打印这个对象中的所有属性
        '''
        for k in self.__dict__:
            print(k,self.__dict__[k])
a = A('alex')()

item系列 __getitem__\__setitem__\__delitem__

class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __getitem__(self, item):
        if hasattr(self,item):
            return self.__dict__[item]
    def __setitem__(self, key, value):
        self.__dict__[key] = value
    def __delitem__(self, key):
        del self.__dict__[key]
a = A('lily',23)
print(a['name'])
a['age']=18
print(a.age)
print(a['age'])
del a['age']# 通过自己实现的
del a.age   # object 原生支持  __delattr__
print(a.__dict__)
(因为self的属性和值,通过字典实现,这个方法也可用于列表,用于下标取值)

__new__

# __init__ 初始化方法
# __new__  构造方法 : 创建一个对象
class A:
    def __init__(self):
        self.x=1
        print('in init')
    def __new__(cls, *args, **kwargs):
        print('in new')
        return object.__new__(A)
a = A()
# in new
# in init
# 单例模式(一个类始终只有一个对象)
class A:
    __obj = False
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __new__(cls, *args, **kwargs):
        if cls.__obj:
            return  cls.__obj
        cls.__obj = object.__new__(A)
        return cls.__obj
a1 = A('lisa',19)
print(a1.__dict__)
a2 = A('JISOO',20)
a2.cloth = 'red-T'
print(a2.__dict__)
print(a1.__dict__) #与a2一样
单例模式(一个类始终只有一个对象)

__hash__

class A:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
    def __hash__(self):
        return hash(self.name+self.sex)
a = A('lisa',19,'women')
b = A('jenny',23,'women')
print(hash(a))
print(hash(b))

__eq__

未定义是比较的是内存地址,可以自定义比较的内容,灵活应用。
class A:
    def __init__(self,name):
        self.name = name
    def __eq__(self, other):
        if self.__dict__ == other.__dict__:
            return True
        else:
            return False
a = A('lisa')
b = A('lisa')
print(a==b)
    有一个类的init方法如下:
    class Person:
        def __init__(self,name,age,sex,weight):
            self.name = name
            self.sex = sex
            self.age = age
            self.weight = weight
    假设有100个person的对象,
    若两个对象的obj1,obj2的name和sex属性相同
    即obj1.name==obj2.name and obj1.sex==obj2.sex
    我们认为两个对象为同一个对象,已知一个列表中的100个对象,对这100个对象进行去重。
    提示:
        重写Person类重的两个内置方法

class A:
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age

    def __eq__(self, other):
        if self.name == other.name and self.sex == other.sex:
            return True
        return False

    def __hash__(self):
        return hash(self.name + self.sex)
a = A('egg','',38)
b = A('egg','',37)
print(set((a,b)))   # unhashable
应用(面试题)-- set 依赖对象的 hash eq
import json
from collections import namedtuple
Card = namedtuple('Card',['rank','suit'])   # rank 牌面的大小 suit牌面的花色
class FranchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')   # 2-A
    suits = ['红心','方板','梅花','黑桃']

    def __init__(self):
        self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
                                        for suit in FranchDeck.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

    def __setitem__(self, key, value):
        self._cards[key] = value

    def __str__(self):
        return json.dumps(self._cards,ensure_ascii=False)

deck = FranchDeck()
print(deck)
from random import choice
print(choice(deck)) #deck是对象,不是列表也可以吗
# print(choice(deck))
# 洗牌
from random import shuffle
shuffle(deck)
# print(deck)      #把列表序列化后输出
# print(deck[:5]) #依赖于item方法
应用- 纸牌游戏























原文地址:https://www.cnblogs.com/olivia2018/p/8330206.html