面向對象進階

来源:http://www.cnblogs.com/Jeffding/archive/2017/09/06/7478566.html
-Advertisement-
Play Games

isinstance和issubclass isinstance()判斷一個對象是不是這個類的對象,傳兩個參數(對象,類) issubclass()判斷一個類是不是另一類的子類,傳兩個參數(子類,父類) class Foo: pass class Son(Foo): pass s = Son() # ...


 

isinstance和issubclass

  isinstance()判斷一個對象是不是這個類的對象,傳兩個參數(對象,類)

  issubclass()判斷一個類是不是另一類的子類,傳兩個參數(子類,父類)

class Foo:
    pass

class Son(Foo):
    pass

s = Son()
#判斷一個對象是不是這個類的對象,傳兩個參數(對象,類)
print(isinstance(s,Son))
print(isinstance(s,Foo))
#type更精準
print(type(s) is Son)
print(type(s) is Foo)

#判斷一個類是不是另一類的子類,傳兩個參數(子類,父類)
print(issubclass(Son,Foo))
print(issubclass(Son,object))
print(issubclass(Foo,object))
print(issubclass(int,object))
test

反射

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

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

  四個可以實現反射的函數:hasattr,getattr,setattr,delattr。

  hasattr判斷object,類中有沒有一個name字元串對應的方法或屬性,返回bool。

class People:
    country='China'
    def __init__(self,name):
        self.name=name
    # def walk(self):
    #     print('%s is walking' %self.name)
p=People('egon')
#hasattr是否有這個屬性
print('name' in p.__dict__)#True
print(hasattr(p,'name'))#True
print(hasattr(p,'name1213'))#False
hasattr

  getattr,通過資費穿的方式直接操作。

res=getattr(p,'country') #拿到返回值相當於res=p.country
print(res)#China

f=getattr(p,'walk') #t=p.walk
print(f)#<bound method People.walk of <__main__.People object at 0x000000000221DE10>>

f1=getattr(People,'walk')
print(f1)#<function People.walk at 0x000000000221BA60>

f()#egon is walking
f1(p)#egon is walking
getattr
print(getattr(p,'xxxxxxxx','這個屬性確實不存在'))
p.sex='male'
print(p.sex)#male
print(p.__dict__)#{'name': 'egon', 'sex': 'male'}

setattr(p,'age',18)
print(p.__dict__)#{'age': 18, 'name': 'egon', 'sex': 'male'}
print(p.age)#18
print(getattr(p,'age'))#18
setattr
# print(p.__dict__)
# del p.name
# print(p.__dict__)

print(p.__dict__)#{'name': 'egon', 'sex': 'male', 'age': 18}
delattr(p,'name')
print(p.__dict__)#{'sex': 'male', 'age': 18}
delattr
#反射當前模塊的屬性也就是模塊級別的反射
import sys
x=1111
class Foo:
    pass
def s1():
    print('s1')

def s2():
    print('s2')


# print(__name__)

this_module = sys.modules[__name__]#獲取當前模塊的對象
print(this_module)#拿到當前的模塊了

print(hasattr(this_module, 's1'))#模塊有沒有這個屬性
print(getattr(this_module, 's2'))
print(this_module.s2)#下麵兩者等價於上面
print(this_module.s1)
模塊級別的反射
import sys
def add():
    print('add')

def change():
    print('change')

def search():
    print('search')


def delete():
    print('delete')

this_module=sys.modules[__name__]
while True:
    cmd=input('>>:').strip()
    if not cmd:continue
    if hasattr(this_module,cmd):
        func=getattr(this_module,cmd)
        func()
    # if cmd in func_dic: #hasattr()
    #     func=func_dic.get(cmd) #func=getattr()
    #     func()



#
func_dic={
    'add':add,
    'change':change,
    'search':search,
    'delete':delete
}


while True:
    cmd=input('>>:').strip()
    if not cmd:continue
    if cmd in func_dic: #hasattr()
        func=func_dic.get(cmd) #func=getattr()
        func()
早前就一直使用的函數反射

  總的來說反射其實就是在找他們的名稱空間是否有這些名稱,也就是是否有我們需要的屬性,然後返回相關的值。

class Foo:
    x=1
    def __init__(self,name):
        self.name=name
    def walk(self):
        print('walking......')
f=Foo('egon')
Foo.__dict__={'x':1,'walk':....}

'x' in Foo.__dict__ #hasattr(Foo,'x')
Foo.__dict__['x'] #getattr(Foo,'x')

print(Foo.x) #'x' in Foo.__dict__
反射就是找名稱空間

可插拔機制

  在現實生產環境經常會遇到兩名程式員共同完成一個項目的情況,比如一個人寫server端另一個人寫client端,但是server的這個程式員某些功能還沒寫完就請假了,client的程式員需要用到他還未完成的功能,

使用反射機制可以實現可插拔機制。反射的好處就是,可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能。

class FtpClient:
    'ftp客戶端,但是還麽有實現具體的功能'
    def __init__(self,addr):
        print('正在連接伺服器[%s]' %addr)
        self.addr=addr
    def test(self):
        print('test')

    def get(self):
        print('get------->')
ftpclient
import ftpclient
#
# print(ftpclient)
# print(ftpclient.FtpClient)
# obj=ftpclient.FtpClient('192.168.1.3')
#
# print(obj)
# obj.test()他還沒寫test所以會出錯



#
f1=ftpclient.FtpClient('192.168.1.1')
if hasattr(f1,'get'):#對方實現我就用
    func=getattr(f1,'get')
    func()
else:
    print('其他邏輯')
ftpserver

字元串導入模塊

#不推薦
m=input("請輸入你要導入的模塊:")

m1=__import__(m)
print(m1)
print(m1.time())
__import__
#推薦使用方法
import importlib
t=importlib.import_module('time')
print(t.time())
導入模塊

__setattr__,__getattr__,__delattr__

  __setattr__為對象設置修改屬性時觸發運行。

class Foo:
    def __init__(self,x):
        self.name=x
    #
    def __setattr__(self, key, value):
        # self.key=value#字元串類型不能使用這個方式要使用反射
        # setattr(self,key_str,value) #self.key_attribute=value相當於再次觸發了 __setattr__產生遞歸
        self.__dict__[key]=value#設置時加入dict

f1=Foo('egon') #f1.name='egon'

f1.age=18#設置時觸發 __setattr__
__setattr__

  __delattr__刪除對象屬性時觸發。

    def __delattr__(self, item):
        print('delattr:%s' %item)
        print(type(item))
        # delattr(self,item)
        # del self.item
        self.__dict__.pop(item)
print(f1.__dict__)
del f1.age
print(f1.__dict__)
print(f1.age)
__delattr__

  __getattr__只有當查找屬性不存在時才會觸發,存在就直接返回了。

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

    #屬性不存在的情況下才會觸發
    def __getattr__(self, item):
        print('getattr-->%s %s' %(item,type(item)))


f=Foo('egon')
print(f.name)#返回x

print(f.xxxxxxx)#調用__getattr__
__getattr__

定製自己的數據類型

  我們之前學習的列表,字典等都是數據類型,我們可以通過繼承派生出自己的數據類型。

class List(list):
    pass
l=List([1,2,3])
print(l)
l.append(4)
print(l)
list

  當然我們定製不僅僅是繼承,還要派生自己的屬性。

class List(list):
    def append(self, p_object):
        # print('--->',p_object)
        if not isinstance(p_object,int):#只讓append數字
            raise TypeError('must be int')
        # self.append(p_object)遞歸
        super().append(p_object)
    def insert(self, index, p_object):
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        # self.append(p_object)
        super().insert(index,p_object)

l=List([1,2,3])
# print(l)
# l.append(4)
# print(l)

# l.append('5')
print(l)
# l.insert(0,-1)
l.insert(0,'-1123123213')
print(l)
list++

  註:__annotations__可以看到你要求的類型。

def test(x:int,y:int)->int:
    return x+y
print(test.__annotations__)
#{'x': <class 'int'>, 'return': <class 'int'>, 'y': <class 'int'>}
print(test(1,2))
__annotations__

  不能用繼承,來實現open函數(不是類)的功能,授權的方式實現定製自己的數據類型。

import time


class Open:
    def __init__(self,filepath,m='r',encode='utf-8'):
        self.x=open(filepath,mode=m,encoding=encode)#正常打開文件的操作保存給open類的私有屬性

        self.filepath=filepath
        self.mode=m
        self.encoding=encode

    def write(self,line):
        print('f自己的write',line)
        t=time.strftime('%Y-%m-%d %X')
        self.x.write('%s %s' %(t,line))#self.x就是文件句柄

    def __getattr__(self, item):#授權,找不到屬性就找他
        # print('=------>',item,type(item))
        return getattr(self.x,item)
#
# f=Open('b.txt','w')
# # print(f)
# f.write('111111\n')
# f.write('111111\n')
# f.write('111111\n')


f=Open('b.txt','r+')
# print(f.write)
print(f.read)


res=f.read() #self.x.read()
print(res)

print('=-=====>',f.read())
f.seek(0)
print(f.read())
# f.flush()
# f.close()
自製open類

  item系列,把對象操作屬性模擬成字典的格式。用.方法調用的就是__attr__系列,用[key]方式就是調用__item__系列。

class Foo:
    def __init__(self,name):
        self.name=name
    def __setattr__(self, key, value):#與他的區別就在於item是調用的k,v的格式
        print('setattr===>')
    def __getitem__(self, item):
        # print('getitem',item)
        return self.__dict__[item]
    def __setitem__(self, key, value):
        print('setitem-----<')
        self.__dict__[key]=value
    def __delitem__(self, key):
        self.__dict__.pop(key)
        # self.__dict__.pop(key)
    # def __delattr__(self, item):
    #     print('del obj.key時,我執行')
    #     self.__dict__.pop(item)

f=Foo('egon')#調用__setattr__
# f.name='egonlin'
f['name']='egonlinhai'#調用__setitem__
# print(f.name)
# f.name='egonlin'
# f['age']=18
# print(f.__dict__)
#
del f['age'] #del f.age
print(f.__dict__)

print(f['name'])#__getitem__
item系列

  __str__列印時觸發,__repr__與前者差不多,前者輸出更友好。

  __format__自定製格式化字元串

  __slots__

class People:
    __slots__=['x','y','z']#對象不會再創建名稱空間,對象都用類的名稱空間

p=People()
# print(People.__dict__)沒dict
p.x=1
p.y=2
p.z=3
p.a=4#__slots__使類只開闢x,y,z空間,對象名稱不能加入
print(p.x,p.y,p.z,p.a)
# print(p.__dict__)

p1=People()
p1.x=10
p1.y=20
p1.z=30
print(p1.x,p1.y,p1.z)
print(p1.__dict__)
__slots__

  __iter__,__next__

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

    def __iter__(self):
        return self

    def __next__(self):
        if self.start > 10:
            raise StopIteration
        n=self.start
        self.start+=1
        return n
f=Foo(0)
print(next(f)) #f.__next__()
for i in f: # res=f.__iter__() #next(res)
    print(i)
View Code
class Range:
    '123'
    def __init__(self,start,end):
        self.start=start
        self.end=end

    def __iter__(self):
        return self

    def __next__(self):
        if self.start == self.end:
            raise StopIteration
        n=self.start
        self.start+=1
        return n

for i in Range(0,3):
    print(i)
自製range

  __doc__,__moudle__,__class__

class Foo:
    '我是描述信息'
    pass

class Bar(Foo):
    pass
print(Bar.__doc__) #None該屬性無法繼承給子類

b=Bar()
print(b.__class__)#<class '__main__.Bar'>
print(b.__module__)#__main__
print(Foo.__module__)#__main__
print(Foo.__class__) #<class 'type'>
View Code

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

f=open('a.txt') #做了兩件事,在用戶空間拿到一個f變數,在操作系統內核空間打開一個文件
del f #只回收用戶空間的f,操作系統的文件還處於打開狀態

#所以我們應該在del f之前保證f.close()執行,即便是沒有del,程式執行完畢也會自動del清理資源,於是文件操作的正確用法應該是
f=open('a.txt')
讀寫...
f.close()#清理的時候就調用析構方法
很多情況下大家都容易忽略f.close,這就用到了with上下文管理
import time
class Open:
    def __init__(self,filepath,mode='r',encode='utf-8'):
        self.f=open(filepath,mode=mode,encoding=encode)

    def write(self):
        pass

    def __getattr__(self, item):
        return getattr(self.f,item)

    def __del__(self):
        print('----->del')
        self.f.close()

f=Open('a.txt','w')
f1=f
del f

print('=========>')
f.close

  __enter__和__exit__

  with open('a.txt') as f:叫做上下文管理協議,即with語句,為了讓一個對象相容with語句,必須在這個對象的類中聲明__enter__和__exit__方法。

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

    def __enter__(self):
        print('出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變數')
        # return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代碼塊執行完畢時執行我啊')


with Open('a.txt') as f:
    print('=====>執行代碼塊')
    # print(f,f.name)
上下文管理協議

  __exit__()中的三個參數分別代表異常類型,異常值和追溯信息,with語句中代碼塊出現異常,則with後的代碼都無法執行。

  如果__exit()返回值為True,那麼異常會被清空,就好像啥都沒發生一樣,with後的語句正常執行

class Foo:
    def __enter__(self):
        print('=======================》enter')
        return 111111111111111

    def __exit__(self, exc_type, exc_val, exc_tb):#with代碼塊已執行完就會觸發__exit__
        print('exit')
        print('exc_type',exc_type)
        print('exc_val',exc_val)
        print('exc_tb',exc_tb)
        return True


# with Foo(): #觸發res=Foo().__enter__()拿到返回值
#     pass

with Foo() as obj: #res=Foo().__enter__() #obj=res
    print('with foo的自代碼塊',obj)#obj就是__enter__的返回值
    raise NameError('名字沒有定義')
    print('************************************')#他是不會執行的拋異常已經觸發__exit__了

print('1111111111111111111111111111111111111111')#返回ture異常解決,否則拋異常不執行了
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這個事情就是一個坑,耽誤了兩周時間,之前並沒有做過ActiveX這玩意,現在客戶需求如此,只能說是在網上看著教程做了。 事情是這樣的,有一臺海康威視的攝像頭,客戶需要一個ActiveX控制項嵌入到網頁中,通過點擊按鈕開始錄製和結束錄製來進行視頻的錄製和保存,關於海康攝像頭的二次開發在此就不多說了,可以 ...
  • C#跨線程調用控制項 在C#應用程式開發中,我們經常需要把UI線程和工作線程分開編程,為了防止界面停止響應。同時,我們也需要在工作線程中去更新UI界面的控制項,在CLR的線程安全中並不允許我們直接在工作線程操作UI界面。因此,介紹以下三種方式進行跨線程操作UI。 第一種方法:使用delegate和inv ...
  • 我們希望WCF客戶端調用採用透明代理方式,不用添加服務引用,也不用Invoke的方式,通過ChannelFactory<>動態產生通道,實現服務介面進行調用,並且支持async/await,當然也不用在Config中配置serviceModel。 服務端代碼: 代理類 動態創建服務對象,Channe ...
  • 以前對WinForm窗體顯示和窗體間傳值瞭解不是很清楚最近做了一些WinForm開發,把用到的相關知識整理如下 A.WinForm中窗體顯示顯示窗體可以有以下2種方法:Form.ShowDialog方法 (窗體顯示為模式窗體)Form.Show方法 (窗體顯示為無模式窗體) 2者具體區別如下:1.在 ...
  • 1 using System;//引入命名空間 2 namespace HelloWorldApplication //命名空間 3 { 4 class HelloWorld //類名 5 { 6 static void Main(string[] args) //主函數 7 { 8 /* 我的第一... ...
  • 靜態方法和非靜態方法的區別: 1.靜態方法不需要類實例化就可以調用,反之非靜態方法需要實例化後才能調用; 2.靜態方法只能訪問靜態成員和方法,非靜態方法都可以訪問; 3.靜態方法不能標記為override,導致派生類不能重寫,但是可以訪問; 4.靜態成員是在第一次使用時進行初始化。非靜態的成員是在創 ...
  • 1、簡述編譯型與解釋型語言的區別,且分別列出你知道的哪些語言屬於編譯型,哪些屬於解釋型? 編譯型是一次性將源碼翻譯成電腦可以讀懂的二進位,缺點是全部運行完才知道有問題的地方,要重新修改源碼,然後重新編譯,跨平臺性差如C、C++、Delphi等 解釋型是一句句的翻譯源碼,運行速度慢,但是源碼有問題可以 ...
  • 概述 for v in d.values(): for k,v in d.items(): for a in 'adfa': #判斷對象是否可迭代 from collections import Iterable isinstance('abc',Iterable) #添加下標 for x,y in ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...