Python 面向对象进阶篇

一、isinstance和issubclass

1、isinstance 判断一个对象是否属于该类

class Foo(object):
     pass  
a = Foo()
isinstance(a, Foo)
#判断a是否是Foo的对象 答案:True

2、issubclass(sub, super)检查sub类是否是 super 类的派生类 

class Foo(object):    
    pass
class Son(Foo):
    pass

issubclass(Son, Foo) #判断Son是否是Foo的派生类
答案:True

二、反射

1 什么是反射

  反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

反射对象中的属性和方法   # hasattr getattr setattr delattr

getattr
class A:
    def func(self):
        print('in func')

a = A()
a.name = 'amy'
a.age = 63
# 反射对象的属性
ret = getattr(a,'name')  # 通过变量名的字符串形式取到的值
print(ret)
#amy
hasattr
class A:
    price = 20
    @classmethod
    def func(self):
        print('in func')
ret = getattr(A,'price') # 通过变量名的字符串形式取到的值
print(ret)
if hasattr(A,'func'):   #如果A中有func,就使执行getattr方法
    getattr(A,'func')()
setattr
class Foo:
    role = 'teacher'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def say_hi(self):
        print('hi,%s'%self.name)
obj = Foo('alex',23)
setattr(obj,'sb',True)
print(obj.__dict__)         #{'age': 23, 'sb': True, 'name': 'alex'}
print(getattr(obj,'sb'))    #True
setattr(obj,'show',lambda self:self.name+'sb')
print(obj.show(obj))  #alexsb

delatter

# 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)
class Foo(object):
 
    staticField = "old boy"
 
    def __init__(self):
        self.name = 'wupeiqi'
 
    def func(self):
        return 'func'
 
    @staticmethod
    def bar():
        return 'bar'
 
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')
类也是对象

 

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__],变量名))
反射自己模块中的函数与变量

导入其他模块,利用反射查找该模块是否存在某个方法

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def test():
    print('from the test')
导入模块(函数)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
"""
程序目录:
    module_test.py
    index.py
 
当前文件:
    index.py
"""

import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')(
View Code
导入的模块有类
class A:
    day = 'Monday'
    # @classmethod
    @staticmethod
    def wahaha():
        print('wahahahaha')
导入模块
import my
#调用类的方法
getattr(my.A,'wahaha')()

from my import A
getattr(A,'wahaha')()
print(getattr(A,'day'))

print(getattr(my.A,'wahaha')()
#调用类中的属性
if hasattr(my.A,'day'):
    print(getattr(my.A,'day'))
View Code

 

__str__和__repr__

改变对象的字符串显示__str__,__repr__

自定制格式化字符串__format__

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 __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)

'''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''
print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd'))
View Code
class Teacher:
    def __init__(self,name,salary):
        self.name = name
        self.salary = salary
        self.student = []
    def __str__(self):
        return "Teacher's object:%s" %self.name
    def __len__(self):
        return len(self.student)
    def __repr__(self):
        return str(self.__dict__)
    def func(self):
        return 'wahaha'
nazha = Teacher('nazha',2300)
print(nazha)
print(repr(nazha))
print('%r'%nazha)
print('%s'%nazha)
print(str(nazha))
%s %r str repr

__del__

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

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

class Foo:

    def __del__(self):
        print('执行我啦')

f1=Foo()
del f1
print('------->')

#输出结果
执行我啦
------->
View Code

__len__

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))
View Code

 

item系列

__getitem__、__setitem__、__delitem__

class Foo:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    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]
f = Foo('zzm',38,'')  #实例化一个对象
print(f['name'])    #zzm
f['hobby'] = 'swim' 
print(f.hobby)  #swim
print(f['hobby'])  #swim
del f['name']   #删除name
print(f.__dict__)  
View Code

__new__

new()方法的特性: 
new()方法是在类准备将自身实例化时调用。 
new()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。

#在实例化开始之后,在调用 init()方法之前,Python首先调用new()方法:
class A:
    def __init__(self):
        self.x = 1
        print('in init function')
    def __new__(cls, *args, **kwargs):
        print('in new')
        return object.__new__(A, *args, **kwargs)
a = A()
#in new
#in init function
print(a.x)  #1
View Code

我们还可以利用__new__来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton) 。

因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。

class Singleton:
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance

one = Singleton()
two = Singleton()

two.a = 3
print(one.a)
# 3
# one和two完全相同,可以用id(), ==, is检测
print(id(one))
# 29097904
print(id(two))
# 29097904
print(one == two)
# True
print(one is two)

单例模式
单例模式

new()和ini()的区别,在新式类中new()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法init()使其丰满。 

__call__

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

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

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print('__call__')


obj = Foo() # 执行 __init__
obj()       # 执行 __call__
View Code

 

__hash__

class A:
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
    def __hash__(self):
        return hash(self.name+self.sex)

a = A('egon','')
b = A('egon','')
print(hash(a))
print(hash(b))
#hash a,b之后,两个值相同,但对于字符串来说,每次得到的值都会发生变化。
View Code

__eq__

使用eq方法可以对比两个属性或者值的大小
class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # def __eq__(self,other):
    #     if self.name == other.name:
    #         return True
    #     return False
ob1 = A('egon',23)
ob2 = A('egon',23)
print(ob1.age == ob2.age)   #True
print(ob1==ob2) #False
print(hash(ob1))    #347809
print(hash(ob2))    #347811
View Code

 

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])
纸牌游戏2

 

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

    def __hash__(self):
        return hash(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(84):
    p_lst.append(Person('egon',i,'male'))

print(p_lst)
print(set(p_lst))   #{<__main__.Person object at 0x004BE9D0>}
面试题

 



posted @ 2018-01-22 23:05  amyleell  阅读(79)  评论(0)    收藏  举报