what's the python之面向對象(進階)

面向對象的知識點補充(進階版)

classmethod和staticmethod:這兩個函數的用途就是能夠不用實例化對象就能夠調用方法python

class Classmethod_Demo():
    role = 'dog'

    @classmethod
    def func(cls):
        print(cls.role)

Classmethod_Demo.func()


class Staticmethod_Demo():
    role = 'dog'

    @staticmethod
    def func():
        print("當普通方法用")

Staticmethod_Demo.func()

 

isinstance和issubclass

  isinstance是用來檢查實例化的對象是不是由想檢查的類實例化出來的,返回的是布爾值。isinstance(obj,t)程序員

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

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

b=Fruit('banana')
print(isinstance(b,Fruit))#True
print(isinstance(b,Vegetable))#False

  issubclass是用來檢查一個類是不是想檢查的類的子類,返回的是布爾值。issubclass(cls,classinfo)面試

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

class Fruit(Plant):
    def __init__(self,name):
        self.name=name

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

print(issubclass(Fruit,Plant))#True
print(issubclass(Fruit,Vegetable))#False

 

 

反射

python面向對象中的反射:經過字符串的形式操做對象相關的屬性。python中的一切事物都是對象(均可以使用反射)app

四個能夠實現自省的函數:hasattr,getattr,setattr,delattr(後面兩個不經常使用,平時不推薦使用)dom

上述四個函數適用於類和對象(一切皆對象,類自己也是一個對象)函數

下面用代碼來提現每一個函數的做用:ui

class Sport:
    def __init__(self,name,place):
        self.name=name
        self.place=place
    def play(self):
        print('i like %s'%self.name)
    def where(self):
        print('we play at %s'%self.place)

bas=Sport('basketball','ground')
#hasattr#查看屬性,返回布爾值
print(hasattr(bas,'name'))#檢測是否有屬性,輸出布爾值

#getattr#獲得屬性,能夠調用方法
print(getattr(bas,'where'))#檢測是否有屬性,輸出的是方法的內存地址
n=getattr(bas,'where')
print(n)#檢測是否有屬性,與上面一個print裏的內容如出一轍,輸出的是方法的內存地址
func=getattr(bas,'where')
func()#調用方法,輸出爲we play at ground
# print(getattr(bas,'price'))#不存在即報錯
print(getattr(bas,'price','不存在啊'))#設置默認值即不報錯,輸出默認值

#setattr能夠更改屬性,不推薦使用
setattr(bas,'price',100)#新設置一個屬性
print(bas.price)
setattr(bas,'show_name',lambda self:self.name+' good')
print(bas.show_name(bas))#basketball good

#delattr#刪除屬性,不推薦使用
delattr(bas,'place')
# delattr(bas,'name111')#不存在,則報錯
print(bas.__dict__)

 

類也是對象,天然也能夠使用上述函數:this

class Foo(object):
 
    staticField = "old boy"
 
    def __init__(self):
        self.name = 'alex'
 
    def func(self):
        return 'func'
 
    @staticmethod
    def bar():
        return 'bar'
 
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

 

也能夠用來反射當前模塊成員:spa

#!/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')

 

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

#文件一
#!/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')()

 

 

 

如下內容供進階瞭解

__str__、__repr__、__format__、__del__、__call__、__len__、__hash__、__eq__、__item__系列

改變對象的字符串顯示__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))#from repr:  School(oldboy1,北京)
print('from str: ',str(s1))#from str:  (oldboy1,北京)
print(s1)#(oldboy1,北京)

'''
str函數或者print函數--->obj.__str__()
repr或者交互式解釋器--->obj.__repr__()
若是__str__沒有被定義,那麼就會使用__repr__來代替輸出
注意:這倆方法的返回值必須是字符串,不然拋出異常
'''
print(format(s1,'nat'))#oldboy1-北京-私立
print(format(s1,'tna'))#私立:oldboy1:北京
print(format(s1,'tan'))#私立/北京/oldboy1
print(format(s1,'asfdasdffd'))#oldboy1-北京-私立

 

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

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

b=B()
print('%s'%b)#repr : class B
print('%r'%b)#str : class B

 

__del__

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

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

class Foo:
    def __del__(self):
        print('執行我啦')
f1=Foo()
del f1
print('------->')

#輸出結果
執行我啦
------->

 

__call__

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

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

class Foo:
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo() # 執行 __init__
obj()       # 執行 __call__

 

__len__

至關於內置的len()方法,純粹檢查長度

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

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))#2  其實電泳len方法的時候就是python在內部實現了__len__

 

__hash__

查看是否能夠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))#其實調用hash方法的時候就是內部實現了__hash__

 

__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)#True

 

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

 

 

最後給兩道大題壓壓驚

 1、曾經的一道面試題:

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'))#將84個egon傳入列表中

print(p_lst)
print(set(p_lst))#set是集合,具備去重功能,其實質就是在內部實現了__hash__和__eq__方法

2、紙牌遊戲題:

from collections import namedtuple
Cards=namedtuple('Cards',['ranks','suit'])
class FranchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')
    suits = ['紅心','方板','梅花','黑桃']

    def __init__(self):
        self._cards = [Cards(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])#Cards(ranks='2', suit='紅心')Cards(ranks='2', suit='紅心')
from random import choice#隨機取值,choice依賴於內置的__getitem__
print(choice(deck))#Cards(ranks='J', suit='黑桃')
print(choice(deck))#Cards(ranks='2', suit='紅心')

from random import shuffle#洗牌,shuffle依賴於__getitem__和__setitem__
shuffle(deck)
print(deck[:5])#[Cards(ranks='Q', suit='方板'), Cards(ranks='2', suit='黑桃'), Cards(ranks='5', suit='梅花'), Cards(ranks='4', suit='方板'), Cards(ranks='2', suit='梅花')]
相關文章
相關標籤/搜索