python之路--面向对象之反射

isinstance和issubclass

isinstance(对象,类)判断一个对象是不是这个类的对象

class Foo:pass

class Son(Foo):pass

s = Son()
# 判断一个对象是不是这个类的对象,传两个参数(对象,类)
print(isinstance(s,Son))
print(isinstance(s,Foo))
print(type(s) is Son)
print(type(s) is Foo)

issubclass(子类,父类)判断一个类是不是另一类的子类

class Foo:pass

class Son(Foo):pass

# 判断一个类是不是另一个类的子类,传两个参数(子类,父类)
print(issubclass(Son,Foo))
print(issubclass(Son,Foo))
print(issubclass(Son,object))
print(issubclass(Foo,object))
print(issubclass(int,object))

staticmethod和classmethod

相同点

都可以直接被类调用,不需要实例化

不同点

  1. 类方法必须一个cls参数表示这个类
  2. 静态方法不需要,静态方法不能直接使用

绑定方法

  • 普通方法:默认有一个self对象传进来,并且只能被对象调用 --绑定到对象
  • 类方法:默认有一个cls传进来表示被类,并且可以被类和对象调用(不推荐) --绑定到类

非绑定方法

  • 静态方法:没有默认参数,并且可以被类和对象调用(不推荐) --非绑定
class Student:
    title = 'hello world'
    def __int__(self):pass

    @staticmethod  # 静态方法 :让类的方法正常被调用,就像正常的函数一样
    def show_student_info():
        print('小明 男')
    @classmethod   # 类方法:默认参数cls,可以直接用类名调用,可以和类属性交互
    def hello(cls):
        print(cls.title)

Student.show_student_info()
s = Student()
s.show_student_info()
s.hello()

反射

什么是反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

python面向对象中的反射

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

实现反射的4个函数

常用
  • hasattr
  • getattr
不常用
  • setattr
  • delattr

对象反射

# 对象反射
class Foo:
    def __init__(self):
        self.name = 'egon'
        self.age = 73
    def func(self):
        print(123)

# 反射 可以用字符串的方式去访问对象的属性、调用对象的方法
egg = Foo()

print(hasattr(egg,'name'))      # 判断属性时候,存在与否都返回布尔值
print(getattr(egg,'name'))      # 得到该属性的值
print(getattr(egg,'func'))      # 判断方法时,存在返回内存地址,不存在报错
func = getattr(egg,'func')      # 把内存地址重新赋值给变量func
func()                          # 加括号直接调用

setattr(egg,'sex','nv')
print(egg.sex)
setattr(egg,'show_name',lambda self:self.name + 'sb')
print(egg.show_name(egg))
delattr(egg,'name')
print(egg.name)

类反射

class Foo:
    f = 456

    @classmethod
    def class_method_demo(cls):
        print('class_method_demo')

    @staticmethod
    def static_method_demo():
        print('static_method_demo')
if hasattr(Foo,'f'):
    print(getattr(Foo,'f'))
print(hasattr(Foo,'class_method_demo'))
method = getattr(Foo,'class_method_demo')
method()
print(hasattr(Foo,'static_method_demo'))
method2 = getattr(Foo,'static_method_demo')
method2()

模块反射

# 在其他模块应用反射
import my_module
print(hasattr(my_module,'test'))
getattr(my_module,'test')()

def demo1():
    print('demo1')


# 在本模块中应用反射
import sys
module_obj = sys.modules[__name__]
print(hasattr(module_obj,'demo1'))
模块反射关联文件(同级目录下的my_module)
def test():
    print('test')

内置方法

  • __str__和__repr__

  1. 当打印一个对象的时候,如果实现了__str__,打印其中的返回值
  2. 当__str__没有被实现的时候,就会调用__repr__
  3. 当用字符串格式化的时候%s和%r会分别帝欧用对应的__str__和__repr__
  4. 不管是在字符串格式化的时候还是在打印对象的时候,__repr__都可以作为__str__的替补,反之不是
  5. 如果__str__和__repr__方法你只能实现一个,先实现__repr__
  6. 必须要有return return的对象必须是字符串
class Foo:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        return 'obj info in str'

    def __repr__(self):
        return 'obj info in repr'

f = Foo('8192bit')
print('%s'%f)
print('%r'%f)
print(repr(f))      # 等于f.__repr__()
print(str(f))
  • __format__

# 自定制 __format__
format_dict = {
    "nat": '{obj.name}-{obj.address}-{obj.type}',
    "nta": '{obj.name}:{obj.address}:{obj.type}',
    "tan": '{obj.name}/{obj.address}/{obj.type}',
}
class School:
    def __init__(self,name,address,type):
        self.name = name
        self.address = address
        self.type = type
    def __str__(self):
        return "school_name:%s,school_address:%s"%(self.name,self.address)
    def __repr__(self):
        return "school(%s,%s)"%(self.name,self.type)

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


s = School('oldboy','北京','私立')
print('%s'%s)
print('%r'%s)
print(format(s,'nat'))
print(format(s,'nta'))
print(format(s,'tan'))
print(format(s,'nataaaaaaaaaa'))
  • __del__

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

f= Foo()
print(123)
print(123)
print(123)
del f       # 默认最后执行,本次为指定执行
print(123)
print(123)
  • item 系列(__getitem__,__setitem__,__delitem__)

class Foo:
    def __init__(self):
        self.name = '8192bit'
        self.age = 18

    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]

f = Foo()
print(f['name'])
f['sex'] = 'nv'
print(f['sex'])
del f['sex']
  • __new__

class A:
    def __init__(self):
        self.x = 1
        print('in init function')
    def __new__(cls, *args, **kwargs):
        print('in new function')
        return object.__new__(A,*args,**kwargs)
a = A()
print(a.x)

实现单例模式

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()
three = Singleton()
go = Singleton()
print(one,two)

one.name = 'alex'
print(two.name)
  • __call__

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

    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')

obj = Foo() # 执行 __init__
obj()       # 执行 __call__
  • __len__

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

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))
  • __hash__

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

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
  • __eq__

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

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)

纸牌游戏

from collections import namedtuple
Card = namedtuple('Card',['rank','suit'])  #没一个card的对象就是一张纸牌

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

    def __call__(self, *args, **kwargs):
        return self._cards

deck = FranchDeck()
# print(deck[0])    # 按顺序取牌
# print(deck[3])
# print(deck[2])
# print(deck[1])
# from random import choice # 随机拿牌
# print(choice(deck))
# print(choice(deck))

from random import shuffle  # 洗牌
shuffle(deck)
print(deck())
shuffle(deck)
print(deck())

面试题

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))

感谢

感谢eval美女倾囊相授





posted @ 2017-08-17 15:35  8192bit  阅读(112)  评论(0编辑  收藏  举报