1. 程式人生 > >python學習筆記(12):高階面向物件

python學習筆記(12):高階面向物件

一、__slots__和property

  1.__slots__魔術函式動態的新增方法和屬性

  2.直接暴露屬性的侷限性

  3.使用get/set方法

  4.利用@property簡化get/set方法

  5.利用@property實現只讀屬性

  6.裝飾器與property實現

 # import traceback
# from types import MethodType
#
# class MyClass(object):
#     # pass
#     #在做新的類的時候,限制動態新增的屬性,這個時候需要用到__slots__魔術變數,系統內為了實現某些特定功能的
#     __slots__ 
= ['name','set_name'] # 這個地方,能新增的屬性和方法就會受到限制,只能新增name或者set_name這兩個名詞的屬性或者方法 # def set_name(self,name): # self.name = name # cls = MyClass() #例項化類 # cls.name='Tom' #動態的新增屬性 # cls.set_name=MethodType(set_name,cls) #動態的新增方法 將set_name作用於cls上面 # cls.set_name('Jerry') # print(cls.name) # try: # cls.age
=30 #動態新增屬性 ,這個地方要注意,age不在__slots__規定的陣列中,所以會報錯 # except AttributeError: # traceback.print_exc() #打印出異常資訊 AttributeError: 'MyClass' object has no attribute 'age' # # class ExtMyClass(MyClass): #繼承自MyClass # pass # ext_cls = ExtMyClass() # ext_cls.age=30 # print(ext_cls.age)

  2.property

import traceback
class Student:
    @property   # 這個地方用裝飾器進行修飾的時候,實際上是生成了一個新的物件,名字叫做score,這個相當於set函式
    def score(self):
        return self._score
    @score.setter
    def score(self,value):
        if not isinstance(value,int):   #進行value的型別檢查,如果不是int型的值,就會報錯not int
            raise ValueError('not int')

        elif (value<0) or (value>100):   #如果value只不是在這個區間之間的話,就會報錯值不在0~100之間,這個地方相當於get函式
            raise ValueError('not between 0 ~ 100')
        self._score=value

    @property   #注意,這裡沒有set方法,所以只能讀取,不能寫
    def double_score(self):
        return self._score*2
s= Student()
s.score=75
print(s.score)
print(s.double_score)
try:
    s.double_score=150
except AttributeError:
    traceback.print_exc()

try:
    s.score='abc'
except ValueError:
    traceback.print_exc()
try:
    s.score=101
except ValueError:
    traceback.print_exc()

  3.列舉類

from enum import Enum

Month = Enum('Month',('Jan','Feb','Mar','Apr'))

for name,member in Month.__members__.items():
    print(name,'=>',member,',',member.value)

jan = Month.Jan
print(jan)

二、元類

  1.執行時動態建立 vs 編譯時定義

def init(self,name):  #自定義建構函式,
    self.name=name
def say_hello(self):   #自定義成員函式
    print('hello, %s!' %self.name)

Hello = type('Hello',(object, ),dict(__init__ = init,hello=say_hello))  #(object, )是一個基類的列表

"""
    這個地方的程式碼等價於下面的這些程式碼:
         class Hello:
            def __init__(.......)
            def hello(..........)
"""
h = Hello('Tom')
h.hello()

 

 

  2.使用type建立新型別

  3.metaclass(元類)

    (1)metaclass -> class -> instance

    (2)繼承和動態繫結可以解決問題嗎?

    (3)__new__函式

class ListMetaclass(type):
    def __new__(cls,name,bases,attrs):
        # print(cls)   #打印出傳進來的類時什麼
        # print(name)   #打印出傳進來的name是什麼
        # print(bases)   #打印出傳入進來的基類是什麼   基類是list類
        attrs['add'] = lambda self,value:self.append(value)
        return type.__new__(cls,name,bases,attrs)
class MyList(list,metaclass=ListMetaclass):  #從list類繼承下來,就是一個數組,但是額外的增加add方法,實際等價於append
    pass
mli = MyList()
mli.add(1)
mli.add(2)
mli.add(3)
print(mli) 

三、ORM框架例項(重點的重點)