面向对象进阶

一、isinstance 和 issubclass

1、对象与类之间的关系:判断第一个参数是否是第二个参数的实例

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

# 2 == 3   # 值是否相等
# 2 is 3   # 内存地址是否相等
class A:pass
class B(A):pass
class C(B):pass
c = C()
print(isinstance(c,A))   # 包含继承关系的判断
print(type(c) is B)
print(type(c) is A)      # type只关心创建这个对象的类
身份运算

2、类与类之间的关系

第一个参数是疑似子类,第二个参数是疑似父类.
最终结果如果真的是父子类关系,则返回True
class A:pass
class B(A):pass
print(issubclass(A,B))-----F
print(issubclass(B,A))-----T

二、反射

定义:通过字符串来操作Python代码中的函数、变量、方法和类

 

1、getattr   获取属性

2、hasattr  判断有没有该属性

class A:
    name = 'alex'   # 静态 属性
    age = 83        # 静态 属性

# hasattr getattr
print(getattr(A,'name'))

print(hasattr(A,'name'))
>>>
alex
True

 

在类中使用 类中获取类的静态属性
tag = input('>>>')
if hasattr(A,tag):
    print(getattr(A,tag))
属性的值 = getattr(类名,字符串数据类型的属性名)

 如果第二个参数是不存在的属性名,则会报错

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        for key in self.__dict__:
            print(key,self.__dict__[key])

yuan = Student('苑昊',38)
yuan.show()  
>>
name 苑昊
age 38

if hasattr(yuan,'name'):
    print(getattr(yuan,'name'))
>>>苑昊

if hasattr(yuan,'show'):
    func = getattr(yuan,'show')
    func()
>>>
name 苑昊
age 38
View Code
 hasassr  & getattr

类.静态属性:
  getattr(类,'静态属性')

对象.方法:
 getattr(对象,'方法')() 直接反射得到一个方法之后调用
对象.对象属性

应用场景 : 网络编程 从文件中读取信息反映到编程中

setattr(设置、修改属性)接受3个参数
delattr (删除属性)

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        for key in self.__dict__:
            print(key,self.__dict__[key])

hei = Student('小黑',18)
# hei.sex = '不详'
# print(hei.sex)
setattr(hei,'sex','不详')  # 增改操作
print(hei.sex)
setattr(hei,'sex','male')
print(hei.sex)
print(hei.__dict__)
delattr(hei,'sex')    # 删除操作
print(hei.__dict__)
>>>
不详
male
{'name': '小黑', 'age': 18, 'sex': 'male'}
{'name': '小黑', 'age': 18}
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        for key in self.__dict__:
            print(key,self.__dict__[key])

hei = Student('小黑',18)

def wahaha(a,b):   # 专属于某一个对象的静态方法
    print(a,b)
setattr(hei,'func',wahaha)  #这样写有问题
print(hei.__dict__)
hei.func(1,2)

>>>
{'name': '小黑', 'age': 18, 'func': <function wahaha at 0x0000000001D01E18>}
1 2

 

总结:

hasattr  判断某一个 变量 是否能够.调用一个名字,返回True或者False
getattr 直接获取一个变量中的名字的值
setattr 为一个变量增加或者修改一个属性
delattr 删除一个变量中的属性或者方法
反射类中的名字
getattr(类名,'静态属性')
getattr(类名,'类方法')()
getattr(类名,'静态方法')()

反射对象中的名字
getattr(对象名,'对象属性')
getattr(对象名,'方法名')()

反射模块中的名字
import 模块名
getattr(模块名,'模块中的变量')
getattr(模块名,'模块中的函数')()
getattr(模块名,'模块中的类名')

反射当前模块中的名字
import sys
getattr(sys.modules[__name__],'变量')
getattr(sys.modules[__name__],'函数')()
getattr(sys.modules[__name__],'类名')
反射总结

 

import my_moudle
print(my_moudle.money)
print(getattr(my_moudle,'money'))
getattr(my_moudle,'qqxing')()


def sww():
print('爽歪歪')
count = 0
import sys
print(sys.modules[__name__]) # 一定是aaa.py
print(sys.modules['__main__']) # 不确定的
print(getattr(sys.modules[__name__],'count'))
getattr(sys.modules[__name__],'sww')()
print(sys.modules[__name__])
# print(sys.modules['my_moudle'])
# print(my_moudle)
print(getattr(sys.modules['my_moudle'],'qqxing'))

sys.modules[__name__]-----> 引用当前模块的内容

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show_student(self):
        for key in self.__dict__:
            print(key,self.__dict__[key])

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

    def show_teacher(self):
        for key in self.__dict__:
            print(key, self.__dict__[key])

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

    def show_manager(self):
        for key in self.__dict__:
            print(key, self.__dict__[key])

import sys
main = sys.modules[__name__]

cls_name = input('>>>')

# 根据输入反射找到具体的类
if hasattr(main,cls_name):
    cls = getattr(main,cls_name)

# 实例化对象
alex = cls('alex',81)
print(type(alex))
# 展示这个对象中的所有方法
for i in alex.__dict__:
    print(i,alex.__dict__[i])

>>>
<class '__main__.Teacher'>
name alex
age 81
如何反射一个类

 

 三、面向对象中的内置方法

   __方法名__

内置方法:直接和Python内部隐形相关的

len()内置函数    __len__()
hash()哈希函数 __hash__()
str() __str__()
class A:
    def __init__(self,name,cls,age,sex):
        self.name = name
        self.cls = cls
        self.age = age
        self.sex = sex
    def __eq__(self, other):
        # if self.__dict__ == other.__dict__:return True
        return True
    def __len__(self):
        return len(self.__dict__)

hei = A('小黑','py10期',18,'')
hei2 = A('小2黑','py11期',17,'')
def len(obj):
    return obj.__len__()
print(len(hei))       # 4
print(hei.__dict__)   # {'name': '小黑', 'cls': 'py10期', 'age': 18, 'sex': '无'}
print(hei2.__dict__)  # {'name': '小2黑', 'cls': 'py11期', 'age': 17, 'sex': '无'}
print(hei == hei2)    # Ture
eq 和 len()

 

# _*_coding:utf-8_*_

format_dict={
    'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
    'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __format__(self, format_spec):
        return format_spec.format(obj=self)

s1=School('oldboy1','北京','私立')
print(format(s1,format_dict['tna']))
print(format(s1,format_dict['nat']))
print(format(s1,format_dict['tan']))
print(format(s1,'tna'))
print(format(s1,'tan'))

>>>
oldboy1-北京-私立
私立/北京/oldboy1
tna
tan
format

 

class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type
    def __str__(self):
        return str(self.__dict__)
    def __repr__(self):  # repr是str的备胎
        return 'repr : school的repr对象'
s1=School('oldboy1','北京','私立')
print(str(s1))
print('%s'%s1)
print(s1)

print(repr(s1))
print('%r'%s1)

>>>
{'name': 'oldboy1', 'addr': '北京', 'type': '私立'}
{'name': 'oldboy1', 'addr': '北京', 'type': '私立'}
{'name': 'oldboy1', 'addr': '北京', 'type': '私立'}
repr : school的repr对象
repr : school的repr对象
str 和 repr

 

1、__del__     析构方法:删除一个对象的时候调用的方法

 

import time
class A:
    def __del__(self):   # 析构函数
        print('删除一个对象的时候调用我')

a = A()
time.sleep(1)
析构函数
class A:
    def __init__(self):
        self.f = open('userinfo','a')
    def consume(self):
        pass
    def __del__(self):
        '''在删除一个对象之前做一些收尾工作'''
        self.f.close()
        print('删除一个对象的时候调用我')

a = A()
time.sleep(1)
del a   删除一个对象
删除一个对象的时候,如果内部存在__del__方法,
那么在删除一个对象之前先执行__del__方法中的代码

2、__new__  构造方法

new一个对象

obj.__new__(  )

class A:
    def __init__(self):
        print('执行init方法了')
    def __new__(cls):
        print('执行new方法了')
        return object.__new__(cls)   # 创造对象,将对象返回
a = A()
print(type(a))
print(type(A))

>>>
执行new方法了
执行init方法了
<class '__main__.A'>
<class 'type'>
View Code
先执行__new__方法 创造出一个对象
然后把创造出来的对象传递给__init__方法

会把self自动的返回,被a接收

元类:

有一个元类 在创建类
# type()  所有直接用class创建出来的类的元类都是type
# 
# class 类名(B,classMeta = 元类名)
# class 类名(B,classMeta = type)  # 默认
# 
# 元类 创造 类     所以所有的类的type都是它的元类,默认是type
# 类   创造 对象   具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类

python中 一切皆对象
变量 都有它属于的数据类型

 

3、设计模式---单例设计(关联__new__)

一个类 可以被多次实例化 但是同一时间,在python的内存中,只能有一个实例
class A:
    _instance = None
    def __init__(self,name):
        '''给娃穿衣服'''
        self.name = name
    def __new__(cls, *args, **kwargs):
        '''生娃的过程'''
        if not A._instance:
            A._instance = object.__new__(cls)
        return A._instance
a1 = A('alex')  # 第一次实例化的时候创造一个实例
print(a1.name)
a2 = A('egon')
print(a1,a2)  # 'alex' 'alex'

>>>
alex
egon   egon
单例模式

也可以使用hasattr()方法

class A:
    def __init__(self,name):
        '''给娃穿衣服'''
        self.name = name
    def __new__(cls, *args, **kwargs):
        '''生娃的过程'''
        if not hasattr(A,'_instance'):
            A._instance = object.__new__(cls)
        return A._instance
a1 = A('alex')  # 第一次实例化的时候创造一个实例
print(a1.name)
a2 = A('egon')
print(a1.name,a2.name)  # 'alex' 'alex'
hasattr方法

 

4、item系列  -  ---- 与字典dict样式关联

a.属性>>>>a [ 属性 ]

 

 

class A:
    def __init__(self,name):
        self.name = name
        self.age = 81
    def __getitem__(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('alex')
print(a['name'])  # 对应了类中一个方法的语法 相当于 a.name
print(a['age'])  # 对应了类中一个方法的语法  相当于 a.age

# 增加 和 修改一个属性
a['sex'] = '不详'
# a.sex = '不详'
print(a.__dict__)
print(a.sex)
print(a['sex'])
a['sex'] = ''
print(a.__dict__)
# 删除
del a['sex']
print(a.__dict__)
# del a
# print(a)   报错

>>>>
alex
81
{'name': 'alex', 'age': 81, 'sex': '不详'}
不详
不详
{'name': 'alex', 'age': 81, 'sex': ''}
{'name': 'alex', 'age': 81}

 

 

5、__call__方法  ------   对应 类名(  ) (  )

  (装X方法)

class A:
    def __call__(self,a):
        print('执行我了',a)
    def call(self,a):
        print('执行我',a)
a = A()
a('aaa')   # __call__ 对应 对象()
a.call('aaa')

>>>
执行我了 aaa
执行我 aaa

 

6、hash 方法

  

class A:
    def __hash__(self):
        return 123
a = A()
b = A()
print(hash(a))   # object.__hash__()
print(hash(a))   # object.__hash__()

>>>
123
123

# hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法
# hash的结果就是__hash__方法的返回值
# 且在一次成的执行过程中是不会发生变化的
# 且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法

 

补充:

一、面试试题

# 金融公司面试题
# 有一个类,对应这个类产生了100个对象
# 每个对象有三个属性 : 姓名 年龄 性别
# 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象
# 问最简便的方法?
class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def __hash__(self):
        return hash('%s%s'%(self.name,self.sex))
    def __eq__(self, other):
        if self.name == other.name and  \
            self.sex == other.sex:
            return True
p_lst = []
for i in range(100):
    p_lst.append(Person('egon',i,'male'))

print(p_lst)
print(set(p_lst)) # 报错不可hash  完成了__hash__

# 去重需要两个条件
# hash是否相等   __hash__
# 值是否相等     __eq__
面试题
收获1
对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法
都有可能依赖于类中的内置方法
收获2
set方法依赖集合中元素对象的__hash__ __eq__

二、纸牌游戏

class FranchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')
    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]

deck = FranchDeck()
print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))
纸牌游戏一

 

class FranchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')
    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

deck = FranchDeck()
print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))

from random import shuffle
shuffle(deck)
print(deck[:5])
纸牌游戏二(洗牌)

 

 
posted @ 2018-03-12 15:31  GuoXY  阅读(99)  评论(0编辑  收藏  举报