<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 對象 [TOC] ## 訪問控制(私有屬性和私有方法) ```python # 私有屬性(變量) class Student(object): def __init__(self, name, score): self.__name = name # 屬性的名稱前加上兩個下劃線__,外部就不能訪問 self.__score = score def _show_info(self): print(self.__name) print(self.__score) def print_score(self): print('%s: %s' % (self.__name, self.__score)) bart = Student('Bart Simpson', 59) bart.__name # AttributeError: 'Student' object has no attribute '__name' bart.print_score() # Bart Simpson: 59 bart.__name = 'New Name' # 設置__name變量! bart.__name # 'New Name' # 注意: 看上去好像設置私有變量成功,但實際上這個__name變量和class內部的__name變量不是一個變量!內部的__name變量已經被Python解釋器自動改成了_Student__name,而外部代碼給bart新增了一個__name變量 bart.__show_info() # 私有方法不能訪問:AttributeError: 'Student' object has no attribute '__show_info' ``` 1. 變量名類似__xxx__的,也就是以雙下劃線開頭,并且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接訪問的,不是private變量 2. 只以一個下劃線開頭的實例變量名,比如_name,這樣的實例變量外部是可以訪問的,但是,按照約定俗成的規定,當你看到這樣的變量時,意思就是,“雖然我可以被訪問,但是,請把我視為私有變量,不要隨意訪問”。 ## 類的方法 ```python class Foo: name = 'who' count = 0 # __init__也屬于實例方法,實例方法必須依托于實例 def __init__(self, name): self.name = name # 每實例一次,調用一次, 這里可以統計該類調用的次數 self.__class__.count += 1 print(self.__class__.count) # 類實例方法:第一個參數強制為類實例對象,一般用self代替 # 類實力為對象后可以直接訪問的方法 # 可以通過這個類實例對象(self)訪問對象屬性 # 可以通過類實例對象(self)的__class__屬性訪問類屬性 def hi(self , str): print(self.__class__.name) # who print(str , self.name) # hello zxg # 類方法:cls即為類自身 @classmethod def class_method(cls): print(cls.count) # 靜態方法 # 不能傳遞和類或實例相關的參數,如cls或self,但可以傳遞其他參數 @staticmethod def static_method(nickname): print(nickname) if __name__ == '__main__': foo01 = Foo('zxg') # foo01.hi('hello') # Foo.hi('hello') # 報錯:實例方法不能通過類直接用,必須依托于實例,當然可以把foo01的對象作為第一參數傳進去 foo01.class_method() # 可以通過實例調用 Foo.class_method() # 也可以直接通過類來調用 # foo01.static_method('zxg') # Foo.static_method('zxg') # print(foo01) # print(Foo) ``` 1. 邏輯上,類方法應當只被類調用,實例方法實例調用,靜態方法兩者都能調用 2. 主要區別在于參數傳遞上的區別,實例方法悄悄傳遞的是self引用作為參數,而類方法悄悄傳遞的是cls引用作為參數。而靜態方法不會任何隱式傳遞 ## 使用__slots__限制實例的屬性 ```python class Student(object): __slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱 # 使用__slots__要注意,__slots__定義的屬性僅對當前類實例起作用,對繼承的子類是不起作用的: class GraduateStudent(Student): pass bart = Student() # 對象實例不需要用new ``` ## 類和類方法的裝飾器 ### 類方法中的裝飾器 ```python # 原來的class class Student(object): def get_score(self): return self._score def set_score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value class Student(object): @property def score(self): return self._score @score.setter def score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value s = Student() s.score = 'haha' # OK,實際轉化為s.set_score(60) s.score # OK,實際轉化為s.get_score() # 只定義getter方法,不定義setter方法就是一個只讀屬性 class Student(object): @property def birth(self): return self._birth @birth.setter def birth(self, value): self._birth = value @property def age(self): return 2018 - self._birth zxg = Student() zxg.birth = 1988 zxg.age # 30 Student.sex = 1 zxg.sex = 1 # python一切皆對象,類也屬于對象,可以動態為類添加屬性,該屬性會體現在實例后的對象里面 ``` ### 類裝飾器 #### 函數裝飾類 ##### 裝飾器無參數 ```python #給每個類打印一句話 def Decorator(obj): print("定義了一個裝飾器函數") return obj # 相當于執行 Decorator(School) @Decorator class School(): pass def godme(fun): def __godme(self,message): print('before') fun(self,message) print('after') return __godme class Person: def show(self,message): print(message) @godme def say(self,message): print(message) person = Person() # 相當于 godme(person.say('happy')) # 調用順序 godme() -> __godme()-> person.say() # 輸出順序 before -> happy -> after person.say('happy') ``` ##### 裝飾器有參數 ```python #給每個類添加一個可變的數據屬性 def Decorator(**kwargs): def add(obj): # <class '__main__.School'> print(obj) "添加數據屬性" print('調用外部函數的**kwargs',kwargs) for key,val in kwargs.items(): # 添加數據屬性 setattr(obj,key,val) return obj print("外部傳入的參數為:",kwargs) return add # 執行順序: # 1.運行Decorator函數,先打印外部的傳入的參數,返回add函數名; # 2.再執行School = add(School) # Decorator(addr = "浙江省杭州市",name ="浙江大學")(School) @Decorator(addr = "浙江省杭州市",name ="浙江大學") class School(): def __init__(self,price): self.price =price ``` #### 類裝飾函數或方法 ##### 無參數 ```python class tracer: def __init__(self,func): print('__init__ is called' ) self.calls = 0 self.func = func def __call__(self,*args): self.calls += 1 print(args) print('call %s to %s' %(self.calls, self.func.__name__)) self.func(*args) @tracer def spam(a, b, c): print(a + b + c) ''' 1. 相當于 tracer(spam(1,2,3)) 2. 調用順序:__init__(spam) -> __call__() -> spam(a, b, c) ''' spam(1,2,3) ``` ##### 有參數 ```python class tracer: def __init__(self, *args): self.calls = 0 self.args = args print(args) def __call__(self, func): self.func = func def realfunc(*args): self.calls += 1 print('call %s to %s' %(self.calls, self.func.__name__)) self.func(*args) return realfunc # 相當于tracer("xxxx")(spam) # 調用順序 __init__("xxxx") -> __call__(spam) -> realfunc(a, b, c) -> spam(a, b, c) @tracer("xxxx") def spam(a, b, c): print(a + b + c) spam(1,2,3) ``` ## 繼承 ```python class Parent: def myMethod(self): print ('調用父類方法') class Child(Parent): def myMethod(self): # super().myMethod(); # Python3,如果super在類里面的話,可以省略里面的參數 print ('調用子類方法') c = Child() # 子類實例 c.myMethod() # 子類調用重寫方法 super(Child,c).myMethod() #用子類對象調用父類已被覆蓋的方法 ``` ## 多重繼承 在設計類的繼承關系時,通常,主線都是單一繼承下來的,如果需要“混入”額外的功能,通過多重繼承就可以實現。 ```python class Dog(Mammal, RunnableMixIn, CarnivorousMixIn): pass ``` ## 定制類(魔術方法) 類似PHP中的魔術方法 ```python # __str__ # 打印實例時調用 # __repr__ # console直接敲命令時調用 # object python的頂級父類 class Student(object): def __init__(self, name): self.name = name # print打印時觸發 def __str__(self): return 'Student object (name: %s)' % self.name # 控制臺輸出時觸發 __repr__ = __str__ # 在Python console直接敲命令時調用__repr__方法,又因為__repr__方法跟__str__的內容一樣 zxg = Student('zxg') print(zxg) # Student object (name: zxg) # __iter__ 實現迭代 # __getitem__ list化之后取第幾個元素及切片 class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化兩個計數器a,b def __iter__(self): return self # 實例本身就是迭代對象,故返回自己 # 循環時觸發 def __next__(self): self.a, self.b = self.b, self.a + self.b # 計算下一個值 if self.a > 100: # 退出循環的條件 raise StopIteration() return self.a # 返回下一個值 # list化之后切片觸發 def __getitem__(self, n): print(n) if isinstance(n, int): # n是索引 a, b = 1, 1 for x in range(n): a, b = b, a + b return a if isinstance(n, slice): # n是切片 start = n.start stop = n.stop if start is None: start = 0 a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L f = Fib() f[5] # 5 f[:5] # slice(1, 5, None) for n in f: print(n) # __setitem__() # 設置元素時觸發 # __delitem__() # 刪除元素時觸發 # 通過以上的幾個魔術方法,可以把自己定義的類表現出list,dict,tuple的特性 # __getattr__ 獲取不存在的元素時調用 class Chain(object): def __init__(self, path=''): self._path = path def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) def __str__(self): return self._path __repr__ = __str__ Chain().status.user.list # /status/user/list 實現鏈式操作 # __call__ # 對實例直接調用 class Student(object): def __init__(self, name): self.name = name # 對實例直接調用的時候,調用的就是這個方法 def __call__(self): print('My name is %s.' % self.name) s = Student('Michael') s() # 直接可以調用 # __new__ 當你繼承一些不可變的class時(比如int, str, tuple), 提供給你一個自定義這些類的實例化過程的途徑。還有就是實現自定義的metaclass。 ``` ## 待處理 __del__ __enter__ __exit__ ## 使用枚舉類 ```python from enum import Enum Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) print(Month) # <enum 'Month'> for name, member in Month.__members__.items(): # Sep => Month.Sep , 9 print(name, '=>', member, ',', member.value) ``` ## __new__ 和 __init__ > **實際上在我們實例化對象時,python默認執行了__new__操作,先創建類實例,然后返回給__init__初始化實例** ```python # python新類允許用戶重載__new__和__init__方法。__new__創建類實例,__init__初始化一個已被創建的實例; class newStyleClass(object): # __new__在頂級父類object是一個靜態方法 # cls代表當前類 def __new__(cls): print("__new__ is called") return super(newStyleClass, cls).__new__(cls) # self def __init__(self): print("__init__ is called") print("self is: ", self) newStyleClass() # 我們發現__new__函數先被調用,接著__init__函數在__new__函數返回一個實例的時候被調用,并且這個實例作為self參數被傳入了__init__函數 # 若__new__()沒有正確返回當前類cls的實例,那__init__()將不會被調用,即使是父類的實例也不行。 obj = 12 # obj can be an object from any class, even object.__new__(object) class returnExistedObj(object): def __new__(cls): print("__new__ is called") return obj # __init__不被調用 # return super(returnExistedObj,cls).__new__(cls) def __init__(self): print("__init__ is called") print("self is: ", self) returnExistedObj() ``` ## 使用元類 ### 通過type函數臨時創建類 Python函數和類的定義,不是編譯時定義的,而是運行時動態創建的;所以可以在運行時臨時動態的創建類 `type`傳入三個參數: 1. class的名稱; 1. 繼承的父類集合,注意Python支持多重繼承,如果只有一個父類,別忘了tuple的單元素寫法; 1. class的方法名稱與函數綁定,這里我們把函數fn綁定到方法名hello上。這里的dict的參數是**kws; ```python def fn(self, name='world'): # 先定義函數 print('Hello, %s.' % name) Hello = type('Hello', (object,), dict(hello=fn)) # 創建Hello class o = Hello() o.hello() ``` ### metaclass 除了使用type()動態創建類以外,要控制類的創建行為,還可以使用metaclass。先定義metaclass,就可以創建類,最后創建實例。 metaclass是Python面向對象里最難理解,也是最難使用的魔術代碼。正常情況下,你不會碰到需要使用metaclass的情況 ```python # metaclass是類的模板(類的類),所以必須從`type`類型派生: # metaclass的類名總是以Metaclass結尾 class ListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) return type.__new__(cls, name, bases, attrs) # 有了ListMetaclass,我們在定義類的時候還要指示使用ListMetaclass來定制類,傳入關鍵字參數metaclass # 當我們傳入關鍵字參數metaclass時,魔術就生效了,它指示Python解釋器在創建MyList時,要通過ListMetaclass.__new__()來創建,在此,我們可以修改類的定義,比如,加上新的方法,然后,返回修改后的定義。 class MyList(list, metaclass=ListMetaclass): pass L = MyList() L.add(1) print(L) ``` **元類的作用** 1. 攔截類的創建; 2. 修改類; 3. 返回修改之后的類; ```python # 看下面這個例子 # type其實也是個元類 class UpperAttrMetaclass(type): def __new__(cls, clsname, bases, dct): uppercase_attr = {} for name, val in dct.items(): if not name.startswith('__'): uppercase_attr[name.upper()] = val else: uppercase_attr[name] = val return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr) # 我們知道在python中一切皆對象 # 那么下面我們的s其實就是一個類對象,它的__name__其實和Foo的__name__是一樣的 # 看下面的方法是不是和type創建類有點像? s = UpperAttrMetaclass('Foo',(object,),{'bar':'bip'}) print(hasattr(s,'bar')) # False print(hasattr(s,'BAR')) # True print(s.BAR) # bip class Foo(object,metaclass=UpperAttrMetaclass): bar='bip' print(hasattr(Foo,'bar')) print(hasattr(Foo,'BAR')) print(Foo.BAR) # 最后它們輸出的結果其實是一模一樣的,這就說明了類其實和我們普通的實例對象差不多,只不過普通實例是通過類創建,而類是通過元類創建 # 而__new__就是用來創建實例的,不論是普通的實例,還是類實例,總之就是個實例 ``` **意義** 實現面向對象高級編程,體現其“開閉原則”:把擴展打開,把修改關閉。 比如: 編寫一個ORM框架,所有的類都只能動態定義,因為只有使用者才能根據表的結構定義出對應的類來。 ```python class Field(object): def __init__(self, name, column_type): self.name = name # 字段名 self.column_type = column_type # 字段類型 def __str__(self): return '<%s: %s>' % (self.__class__.__name__, self.name) class StringField(Field): def __init__(self, name): # super().__init__(name, 'varchar(100)') # Python3里面的super可以省略StringField, self super(StringField, self).__init__(name, 'varchar(100)') # 字段名和字段類型 class IntegerField(Field): def __init__(self, name): super(IntegerField, self).__init__(name, 'bigint') # 字段名和字段類型 class ModelMetaclass(type): def __new__(cls, name, bases, attrs): # cls: 正在被生成的對象, name: 生成該對象的類名, bases: 父類集合, attrs: 屬性方法集合 if name == 'Model': # 若類名為Model, 則是對Model的修改,這里是原樣返回 return type.__new__(cls, name, bases, attrs) print('Found model: %s' % name) # 輸出類的名字 mappings = dict() # 初始化user類的屬性方法字典 for key, value in attrs.items(): if isinstance(value, Field): print('Found mappings: %s ==> %s' % (key, value)) # 輸出屬性類型和屬性名 mappings[key] = value # 將屬性類型(key)和屬性名(value)加入到字典 for key in mappings.keys(): attrs.pop(key) # 類屬性中刪除該Field屬性, 否則容易造成運行時錯誤(實例的屬性會遮蓋類的同名屬性) attrs['__mappings__'] = mappings # 將屬性方法字典加入到屬性方法集合中 attrs['__table__'] = name # 表名(此處假設類名即為表名) return type.__new__(cls, name, bases, attrs) class Model(dict, metaclass=ModelMetaclass): # 使用ModelMetaclass來創建類 def __init__(self, **kw): # **kw命名關鍵詞參數 print(kw) super(Model, self).__init__(**kw) def __getattr__(self, key): # 獲得values try: return self[key] except KeyError: raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value): # 設置屬性/方法名 self[key] = value def save(self): # 將屬性保存到數據庫(此處僅為生成相應的SQL語句) fields = [] params = [] args = [] for k, v in self.__mappings__.items(): fields.append(v.name) # 將字段名加入到fields中 params.append('?') # 向params中添加xxx個問號 args.append(getattr(self, k, None)) # 將values加入args中 sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params)) # 生成SQL語句, join方法是將list中的內容以前面的符號作為分隔連在一起 print('SQL: %s' % sql) print('ARGS: %s' % args) class User(Model): # 定義類的屬性到列的映射: id = IntegerField('id') name = StringField('username') email = StringField('email') password = StringField('password') # 創建一個實例: u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') # 保存到數據庫: u.save() # 過程是 ''' 從上到下執行: Model => ModelMetaclass => User(以及里面的屬性IntegerField,StringField等) => ModelMetaclass => Model.save ''' ``` ### `__metaclass__` python2繼承元類的語法 ```python # python3 class Model(dict, metaclass=ModelMetaclass): pass # python2 class Model(dict): __metaclass__ = ModelMetaclass pass ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看