Python類及多線程


模塊  import 

導入模塊是python最常用的一種便捷用法,python有各式各樣的開源模塊供使用,也可以自定義一個模塊使用

import  XXXXXXXXXX   as  x 

from  XXXXXXXXXX  import  X

 

面向對象  把數據和對數據操作用一種叫做對象的東西包裹起來,類:吧共同屬性抽象出來,對象:實例化中設置各自屬性;

class  Pople():   定義一個類 首字母大寫 然后寫這個類的構造函數

  def __init__(self,name,sex):

    self.__name = name   將name定義為一個不可改變的變量  不能通過外部調用函數變量改變其值,需要類里內部函數做變更

    self.sex = sex

  def eat():

    pass

class Zhangsan(Pople):

  def __init__(self,name,sex,age,new)      或者使用super來初始化 

    self.name = name   super().__init__(name)  將子類中的值放到父類中去初始化,

    self.age = age

 

也可以不寫類的構造函數,使用set 和get方法   類在初始化的時候  還不確定參數的情況下可以使用set get
class Persion:

def set_name(self,name):
self.name = name

def get_name(self):
return self.name

if __name__=='__main__':
zhangsan=Persion()
zhangsan.set_name('lalalla')
print(zhangsan.get_name())

類的繼承

繼承父類時,可以不寫init方法(默認會使用父類的init);

重寫init會使用實例自身寫的init

重寫init時想要在父類的基礎上重寫的話可以使用  super(defName,self).__init__( )

class Father(object):
def __init__(self, name):
self.name = name
print("name: %s" % (self.name))

def getName(self):
return 'Father ' + self.name

class Son(Father):
def __init__(self, name):
super(Son, self).__init__(name) #super在使用的是 注意父類要繼承Object python3中是沒有這個問題的
     #Father.__init__(sele,name) #也可以這么用
print("hi")
self.name = name

def getName(self):
return 'Son ' + self.name

name: runoob #先調用父類的init
hi 
Son runoob

 

多態:重寫父類的方法

類具有繼承關系,並且子類類型可以向上轉型看做父類類型,如果我們從 Person 派生出 Student和Teacher ,並都寫了一個 whoAmI() 方法:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def whoAmI(self):
return 'I am a Person, my name is %s' % self.name

class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def whoAmI(self):
return 'I am a Student, my name is %s' % self.name

class Teacher(Person):
def __init__(self, name, gender, course):
super(Teacher, self).__init__(name, gender)
self.course = course
def whoAmI(self):
return 'I am a Teacher, my name is %s' % self.name
在一個函數中,如果我們接收一個變量 x,則無論該 x 是 Person、Student還是 Teacher,都可以正確打印出結果:

def who_am_i(x):
print x.whoAmI()

p = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
t = Teacher('Alice', 'Female', 'English')

who_am_i(p)
who_am_i(s)
who_am_i(t)
運行結果:

I am a Person, my name is Tim
I am a Student, my name is Bob
I am a Teacher, my name is Alice
這種行為稱為多態。也就是說,方法調用將作用在 x 的實際類型上。s 是Student類型,它實際上擁有自己的 whoAmI()方法以及從 Person繼承的 whoAmI方法,
但調用 s.whoAmI()總是先查找它自身的定義,如果沒有定義,則順着繼承鏈向上查找,直到在某個父類中找到為止。
由於Python是動態語言,所以,傳遞給函數 who_am_i(x)的參數 x 不一定是 Person 或 Person 的子類型。任何數據類型的實例都可以,只要它有一個whoAmI()的方法即可

靜態方法:

使用裝飾器@staticmethod。

靜態方法是類中的函數,不需要實例。靜態方法主要是用來存放邏輯性的代碼,邏輯上屬於類,但是和類本身沒有關系,也就是說在靜態方法中,不會涉及到類中的屬性和方法的操作。可以理解為,靜態方法是個獨立的、單純的函數,它僅僅托管於某個類的名稱空間中,便於使用和維護。

 import time

class TimeTest(object):
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second

@staticmethod
def showTime():
return time.strftime("%H:%M:%S", time.localtime())


print(TimeTest.showTime())
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime)

使用了靜態方法(函數),然而方法體中並沒使用(也不能使用)類或實例的屬性(或方法)。若要獲得當前時間的字符串時,並不一定需要實例化對象,此時對於靜態方法而言,所在類更像是一種名稱空間。

其實,我們也可以在類外面寫一個同樣的函數來做這些事,但是這樣做就打亂了邏輯關系,也會導致以后代碼維護困難。

 
        

類方法

使用裝飾器@classmethod。

原則上,類方法是將類本身作為對象進行操作的方法。假設有個方法,且這個方法在邏輯上采用類本身作為對象來調用更合理,那么這個方法就可以定義為類方法。

另外,如果需要繼承,也可以定義為類方法。

 
        
class ClassTest(object):
__num = 0

@classmethod
def addNum(cls):
cls.__num += 1

@classmethod
def getNum(cls):
return cls.__num

# 這里我用到魔術方法__new__,主要是為了在創建實例的時候調用累加方法。
def __new__(self):
ClassTest.addNum()
return super(ClassTest, self).__new__(self)


class Student(ClassTest):
def __init__(self):
self.name = ''

a = Student()
b = Student()
print(ClassTest.getNum())
 

Property 方法   一個方法被定義為property的時候,調用方法會和實例方法不一樣,可以把一個類中的方法當成屬性調用.

 

下划線和雙下划線的作用:

變量名如果是以__雙下划線開頭的就變成了一個私有變量

變量名以_開頭的,這樣的變量可以被外部訪問,但是按照預定俗稱的規定,一般不要隨意改動

變量名以__xxx__開頭的,一般是系統自定義的變量,不建議占用.

 

裝飾器:@ 裝飾器本質上是一個 Python 函數或類,它可以讓其他函數或類在不需要做任何代碼修改的前提下增加額外功能,裝飾器的返回值也是一個函數/類對象。它經常用於有切面需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景,裝飾器是解決這類問題的絕佳設計。有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼到裝飾器中並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。

  https://www.runoob.com/w3cnote/python-func-decorators.html

 

import logging
def use_logging(func):

def wrapper():
logging.warn("%s is running" %func.__name__)
return func()
return wrapper

@use_logging
def foo():
print("i am foo")

foo()

輸出:
i am foo
WARNING:root:foo is running

 

 

自定義包:目錄下有 init 才能被外部引用

 

with的自定義

with中包含了 __enter__ 和  __exit__  方法

class  Testwith():

  def __enter__(self):

    print('enter')

  def__exit__(self,exc_type,exc_val,exc_tb):

    if exc_tb is None:

      print(‘exit normal’)

    else:

      print(‘exit with  exception’)

with  Testwith():   執行之前會先執行enter里面的邏輯  執行完之后會去執行exit的邏輯   如果有異常  可以通過exc捕獲

  print(‘test’)

  raise NameError(‘Exception’)

多線程編程 

最多線程是有兩個原因決定的,內存容量和軟件限制,雖然線程是輕量級進程,但是創建線程也是要消耗內存的,初始狀態下消耗大小就是內存棧了,每創建一個線程為其分配一個線程棧,還有一種限制是系統的配置參數限制,比如在linux上每進程創建線程是1024個,在local_lim.h中定義,可以使用ulimt -a查看線程棧大小

不使用多線程的情況

def  myThread (arg1,arg2):

  print(‘%s %s’ %(arg1,arg2))

for  i  in  range(1,6,1):

  t1 = myThread(i , i+1)

使用多線程的情況:

import  threading

from threading import  current_thread

def  myThread(arg1,arg2):

  print(current_thread().getName(),'start') #顯示當前線程的狀態

  print('%s,%s' %(arg1,arg2))

  time.sleep(1)

  print(current_thread().getName(),'stop')

for  i   in  range(1,6,1):

  t1 = threading.Thread(target=myThread,args=(i, i+1))

  t1.start()

t1.join()    不調用jion方法,執行完子線程之前就會先把主線程執行完畢,

print(current_thread().getName(),'end')

 

多線程經典案例:生產者和消費者  創建一個隊列。,使用線程進行生產數據到隊列和消費隊列中的數據

from threading import current_thread,Thread

import time

import random

from queue import Queue

queue = Queue(5)  創建一個長度為5的隊列

class  ProducerThread(Thread):

  def  run(self):

    name = current_thread().getName()  獲取線程名稱

    nums = range(100)

    global queue

    while Ture:

      num = random.chose(nums)

      queue.put(num)   往隊列里寫入數據

      t = random.randint(1,3)

      time.sleep(t)

class  ConsumerThread(Thread):

   def run (self):

    name = current_thread().getName()

    globle queue

    while True:

      num = queue.get()

      queue.task_done()

      t = random.andomint(1,5)

      time.sleep(t)

p1 = ProducerThread(name = 'p1')

p1.run()    單獨運行run方法,會把主進程當成一個線程來看,執行的代碼空間在MainThread主線程中,

p1.start()   執行start方法,python會創建一個新線程,叫 Thread-1 然后再去調用run()來運行

c1 = ConsumerThread(nem = 'c1')

c1.start()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM