pyt---------面向對象進階


一、isinstance 和 issubclass

isinstance(obj,cls)檢查obj是否是類cls的對象,是則返回True

class Foo(object):
    pass

obj = Foo()
print(isinstance(obj,Foo))

 issubclass(sub,super)檢查sub類是否是supper 類的派生類

class Foo(object):
    pass

class Bar(Foo):
    pass

print(issubclass(Bar,Foo))

 二、反射

1、什么是反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所采用,並在Lisp和面向對象方面取得了成績。

2、python面向對象中的反射:

通過字符串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)

 

四個可以實現自省的函數

下列方法適用於類和對象(一切皆對象,類本身也是一個對象)

def hasattr(*args, **kwargs): # real signature unknown
    """
    Return whether the object has an attribute with the given name.
    
    This is done by calling getattr(obj, name) and catching AttributeError.
    """
    pass
hasattr
def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass
getattr
def setattr(x, y, v): # real signature unknown; restored from __doc__
    """
    Sets the named attribute on the given object to the specified value.
    
    setattr(x, 'y', v) is equivalent to ``x.y = v''
    """
    pass
setattr
def delattr(x, y): # real signature unknown; restored from __doc__
    """
    Deletes the named attribute from the given object.
    
    delattr(x, 'y') is equivalent to ``del x.y''
    """
    pass
delattr
class Foo:
    f = '類的靜態變量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#檢測是否含有某屬性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))

#獲取屬性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()

print(getattr(obj,'aaaaaaaa','不存在啊')) #報錯

#設置屬性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
print(obj.show_name(obj))

#刪除屬性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,則報錯

print(obj.__dict__)
四個方法的使用演示
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')
類也是對象
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')
反射當前模塊成員

導入其他模塊,利用反射查找該模塊是否存在某個方法

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

def test():
    print('from the test')
View Code
#!/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

 

類名 反射 靜態屬性

對象名 反射 對象屬性和方

模塊 反射 模塊中的名字

反射 自己所在文件中的名字

x.y 這樣的形式都可以用反射

'aaa'.startswith('a')
print('aaa'.startswith)

ret = getattr('aaa','startswith')    #把startswith轉換為字符串來處理,就是可以通過字符串來拿打一個值
print(ret)
class Person:
    role = 'Person'
    def __init__(self,name):
        self.name =name
    def eat(self):print('eating')
    def drink(self):print('drinking')
    def play(self):print('playing')
    def sleep(self):print('sleeping')

alex = Person('alex')

print(getattr(alex,'name'))    #反射 對象屬性和方法
print(getattr(Person,'role'))  #反射 靜態屬性

while True:
    inp = input("請輸入:")
    if hasattr(alex,inp):           #判斷alex,inp是否有內容
        getattr(alex,inp)()

 

首先 getattr獲取一個名字,如果在這個對象的命名空間中沒有這個名字會報錯
getattr的反射好伴侶hasatter 一般同時出現
如果使用getattr獲取一個方法,那么只能拿到這個方法的內存地址 加上括號執行

模塊反射

#模塊 mymodule.py內容
# 模塊就是一個py文件
# 所謂的模塊導入 就是執行了這個文件而已
money = 100
def func1():
    print('func1')

def func2():
    print('func2')

class Manager:
    def eat(self):
        print('eating')
mymodule.py
import mymodule
import time

#原來方法
print(mymodule.money)
print(mymodule.func1())
Manager = mymodule.Manager
a = Manager()
a.eat()

#反射
print(getattr(mymodule,'money'))
print(getattr(mymodule,'func1')())
Manager = getattr(mymodule,'Manager')
b = Manager()
b.eat()
模塊反射

反射自己所在文件中的名字

import sys
value = '123'

print(sys.modules['__main__'])  #拿到自己模塊
print(getattr(sys.modules['__main__'],'value'))   #拿到123 反射自己模塊名字
View Code

__str__和__repr__

改變對象的字符串顯示__str__,__repr__

自定制格式化字符串__format__

#_*_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 __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 B:

     def __str__(self):
         return 'str : class B'

     def __repr__(self):
         return 'repr : class B'


b=B()
print('%s'%b)
print('%r'%b)

%s和%r
%s和%r

 

__del__

析構方法,當對象在內存中被釋放時,自動觸發執行。

注:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。

class Foo:

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

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

#輸出結果
執行我啦
------->
簡單示范

 

item系列

__getitem__\__setitem__\__delitem__

class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        print('del obj[key]時,我執行')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        print('del obj.key時,我執行')
        self.__dict__.pop(item)

f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)
View Code

 

__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)
View Code
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方法,object.__new__()
#在執行init

# __new__    構造方法 創建一個對象
# __init__   初始化方法

class Foo:
    def __new__(cls, *args, **kwargs):
        print('執行我啦')
        obj = object.__new__(cls)
        print(obj)
        return obj
    def __init__(self):
        print('222222222',self)

Foo()

# 先執行new方法,object.new()
# 再執行init

# Foo()  --> python解釋器接收到你的python代碼
# python解釋器替你去做了很多操作
# 包括 主動幫助你 調用 new方法 去創造一個對象 —— 開辟內存空間 —— python語言封裝了開辟內存的工作
# object的new方法里 —— 幫你創造了對象
# 調用init用到的self參數 就是new幫你創造的對象
View Code
什么叫單例模式
# 單例模式 : 某一類 只有一個實例

class Person:
    __isinstance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__isinstance :
            obj = object.__new__(cls)
            cls.__isinstance = obj
        return cls.__isinstance
    def __init__(self,name):
        self.name = name

alex = Person('alex')
alex.age = 18
egon = Person('egon')
print(egon.age)
print(id(alex))
print(id(egon))
print(alex.name)  #egon指向同一個內存地址,后覆蓋前面的
print(egon.name)  #egon

# __new__生孩子
# 類 : 生一個小孩__new__ 給這個小孩穿衣服 __init__
# 單例模式下的類 : 只有一個小孩,內存空間還是原來的內存空間
單例模式

 

 

__call__

對象后面加括號,觸發執行。

注:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()

class Foo:

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

        print('__call__')


obj = Foo() # 執行 __init__
obj()       # 執行 __call__
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

 

__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))
View Code

 

__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)
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
紙牌游戲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))

一道面試題
面試題

 

class Person:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        return 'a object of Person named %s'%self.name
    # def __hash__(self):   #
    #     return 1231212
    # def __len__(self):
    #     return 10
a = Person('alex')
b = Person('egon')
# print(len(a))
# print(hash(a))
print(a)
# print(b)
# 類中的內置方法 很多都和 內置函數相關

# l = list([1,2,3])   # 實例化
# print(l)   # 之所以可以打印出結果,是因為def __str__(self): 定義了,需要定義str

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



面向對象進階 面向對象進階 面向對象進階 面向對象進階 面向對象進階 面向對象進階 面向對象進階 面向對象——進階 面向對象進階二 面向對象進階
 
粤ICP备14056181号  © 2014-2020 ITdaan.com