py---------面向对象进阶
一、isinstance?和?issubclass
isinstance(obj,cls)檢查obj是否是類cls的對象,是則返回True
class Foo(object):passobj = Foo() print(isinstance(obj,Foo))?issubclass(sub,super)檢查sub類是否是supper 類的派生類
class Foo(object):passclass Bar(Foo):passprint(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]) -> valueGet 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'texist; 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=nameself.age=agedef 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'@staticmethoddef bar():return 'bar'print getattr(Foo, 'staticField') print getattr(Foo, 'func') print getattr(Foo, 'bar') 類也是對象 #!/usr/bin/env python # -*- coding:utf-8 -*-import sysdef 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.pyindex.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 =namedef 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=nameself.addr=addrself.type=typedef __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_specif 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=namedef __getitem__(self, item):print(self.__dict__[item])def __setitem__(self, key, value):self.__dict__[key]=valuedef __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 = 1print('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._instanceone = 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 objdef __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 = Nonedef __new__(cls, *args, **kwargs):if not cls.__isinstance :obj = object.__new__(cls)cls.__isinstance = objreturn cls.__isinstancedef __init__(self,name):self.name = namealex = 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):passdef __call__(self, *args, **kwargs):print('__call__')obj = Foo() # 執行 __init__ obj() # 執行 __call__ View Code__len__
class A:def __init__(self):self.a = 1self.b = 2def __len__(self):return len(self.__dict__) a = A() print(len(a)) View Code__hash__
class A:def __init__(self):self.a = 1self.b = 2def __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 = 1self.b = 2def __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.ranksfor 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.ranksfor 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] = valuedeck = 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 = nameself.age = ageself.sex = sexdef __hash__(self):return hash(self.name+self.sex)def __eq__(self, other):if self.name == other.name and self.sex == other.sex:return Truep_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 = namedef __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詳解python實現線程安全的單例模式
單例模式是一種常見的設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。
比如,服務器的配置信息寫在一個文件中online.conf中,客戶端通過一個 Config 的類來讀取配置文件的內容。如果在程序運行期間,有很多地方都需要使用配置文件的內容,那么每個調用配置文件的地方都會創建 Config的實例,這就導致系統中存在多個Config 的實例對象,在配置文件內容很多的情況下,我們就浪費了大量的內存做了同樣的事。事實上,對于Config類我們在程序運行期間時只需要一個實例對象即可,這時單例模式就是最好的選擇。
def Singleton(cls):instances = {}def get_instance(*args, **kw):if cls not in instances:instances[cls] = cls(*args, **kw)return instances[cls]return get_instance?
代碼也很簡單,將類傳入單例修飾器中,如果該類還未生成實例(instances中不存在該類),那么就生成一個新的實例返回,并記錄在instances中。如果已經instances中已經存在該類,那么直接返回實例instances[cls]。
那么這段代碼是完美的嗎?答案是否定的,這段代碼不是線程安全的。要實現線程安全需要配合鎖的使用,只有占有鎖的線程才能繼續訪問單例實例,看來我們需要再寫一個修飾器來實現線程安全了,以下是完整的代碼實現和簡單的多線程測試用例。
#!/usr/bin/python # -*- coding: utf-8 -*- import threadingdef synchronized(func):func.__lock__ = threading.Lock()def synced_func(*args, **kws):with func.__lock__:return func(*args, **kws)return synced_funcdef Singleton(cls):instances = {}@synchronizeddef get_instance(*args, **kw):if cls not in instances:instances[cls] = cls(*args, **kw)return instances[cls]return get_instancedef worker():single_test = test()print "id----> %s" % id(single_test)@Singleton class test():a = 1 if __name__ == "__main__":task_list = []for one in range(30):t = threading.Thread(target=worker)task_list.append(t)for one in task_list:one.start()for one in task_list:one.join()?
轉載于:https://www.cnblogs.com/edeny/p/9073341.html
總結
以上是生活随笔為你收集整理的py---------面向对象进阶的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++调用WMI类查询获取操作系统名(实
- 下一篇: 绕过token