主頁 > 後端開發 > Metaclass

Metaclass

2020-09-20 02:20:03 後端開發

目錄

  • 1、一切皆物件
    • 一、 類也是物件
    • 二、type和object
    • 三、元類、類、實體
  • 2、metaclass
    • 一、type--“造物的上帝”
    • 二、metaclass屬性
  • 3、應用
    • 一、實作ORM
    • 二、單例
      • 1)、__new__方法實作單例
      • 2)、元類實作單例
    • 三、動態加載
  • 4、總結
  • 參考:

1、一切皆物件

一、 類也是物件

在大多數編程語言中,類就是一組用來描述如何生成一個物件的代碼段,在Python中這一點仍然成立,但是,Python中的類還遠不止如此,類同樣也是一種物件,只要你使用關鍵字class,Python解釋器在執行的時候就會創建一個物件,下面的代碼段:

class MyClass(object):
    pass

將在記憶體中創建一個物件,名字就是MyClass,這個物件(類)自身擁有創建物件(類實體)的能力,而這就是為什么它是一個類的原因,但是,它的本質仍然是一個物件,于是你可以對它做如下的操作:

你可以將它賦值給一個變數, 你可以拷貝它, 你可以為它增加屬性, 你可以將它作為函式引數進行傳遞,

在 python 中有兩種物件:

  • 型別(類,新的版本中類和型別是一樣的)物件:可以被實體化和繼承
  • 非型別(實體)物件:不可以被實體和繼承

python 中一切皆為物件:

在python里,int整形是物件,整數2也是物件,你定義的函式啊,類啊都是物件,你定義的變數也是物件,總之,你在python里能用到的都可以稱之為物件,

二、type和object

明白了python中一切皆物件之后,再了解一下python中物件之間的兩種關系

面向物件體系中的兩種關系:

  • 父子關系:通常描述為“子類是一種父類”
  • 型別實體關系:這種關系存在于兩個物件中,其中一個物件(實體)是另一個物件(型別)的具體實作,

python中萬物皆物件,一個python物件可能擁有兩個屬性,__class____bases____class__ 表示這個物件是誰創建的,__bases__ 表示一個類的父類是誰們,__class__和type()函式效果一樣,

class MyClass:
    pass

MyClass.__class__
#Out: type

MyClass.__bases__
#Out: (object,)

int.__class__
#Out: type

int.__bases__
#Out: (object,)

object.__class__  #object是type的實體,object創建自type
#Out: type

object.__bases__  #object沒有超類,它本身是所以物件的超類
#Out: ()

type.__class__    #type創建自本身
#Out: type

type.__bases__    #type繼承自object,即object是type的超類
#Out: (object,)  
  • type為物件的頂點,所有物件都創建自type,
  • object為類繼承的頂點,所有類都繼承自object,

三、元類、類、實體

  • object是所有類的超類,而且type也是繼承自object;所有物件創建自type,而且object也是type的實體,
  • “type是object的型別,同時,object又是type的超類”,那到底是先有object還是先有type呢?這就像“先有雞還是先有蛋問題”,
  • object和type是python中的兩個源物件,事實上,它們是互相依賴對方來定義,所以它們不能分開而論,
  • 通過這兩個源物件可以繁育出一堆物件:list、tuple、dict等,元類就是這些類的類,這些類是元類的實體,
l1=list()
l1.__class__      #l是list的實體

#Out: list
list.__class__   #list是type的實體

#Out: type
l1.__bases__      #實體沒有超類

#AttributeError: 'list' object has no attribute '__bases__'
list.__bases__   

#Out: (object,)
l2=[1,2,3]        #l1是利用"型別名()"的方式創建實體,l2是利用python內置型別創造實體,比l1的創建速度要快

2、metaclass

一、type--“造物的上帝”

就像str是用來創建字串物件的類,int是用來創建整數物件的類,而type就是創建類物件的類,

類本身不過是一個名為 type 類的實體,在 Python的型別世界里,type這個類就是造物的上帝,

用戶自定義類,只不過是type類的__call__運算子的多載,當我們定義一個類的陳述句結束時,

真正發生的情況,是 Python 呼叫 type 的__call__運算子,簡單來說,當你定義一個類時,寫成下面時:

class MyClass:
  data = https://www.cnblogs.com/fengqiang626/p/1

Python 真正執行的是下面這段代碼:

class = type(classname, superclasses, attributedict)

這里等號右邊的type(classname, superclasses, attributedict),就是 type 的__call__運算子多載,它會進一步呼叫:

type.__new__(typeclass, classname, superclasses, attributedict)

type.__init__(class, classname, superclasses, attributedict)

當然,這一切都可以通過代碼驗證,比如下面這段代碼示例:

class MyClass:
    data = https://www.cnblogs.com/fengqiang626/p/1

instance = MyClass()

MyClass, instance
#Out: (__main__.MyClass, <__main__.MyClass at 0x4eac358>)

MyClass = type('MyClass', (), {'data': 1})
instance = MyClass()

MyClass, instance
#Out: (__main__.MyClass, <__main__.MyClass at 0x4f915c0>)

instance.data
#Out: 1

由此可見,正常的 MyClass 定義,和手工去呼叫 type運算子的結果是一樣的,

二、metaclass屬性

metaclass 是 type 的子類,通過替換 type的__call__運算子多載機制,“超越變形”正常的類,

其實,理解了以上幾點,我們就會明白,正是 Python 的類創建機制,給了 metaclass 大展身手的機會,

一旦你把一個型別 MyClass 的 metaclass 設定成 MyMeta,MyClass 就不再由原生的 type創建,而是會呼叫 MyMeta 的__call__運算子多載,

class = type(classname, superclasses, attributedict) 

# 變為了
class = MyMeta(classname, superclasses, attributedict)
class MyMeta(type):
    def __new__(cls, *args, **kwargs):
        print('===>MyMeta.__new__')
        print(cls.__name__)
        return super().__new__(cls, *args, **kwargs)

    def __init__(self, classname, superclasses, attributedict):
        super().__init__(classname, superclasses, attributedict)
        print('===>MyMeta.__init__')
        print(self.__name__)
        print(attributedict)
        print(self.tag)

    def __call__(self, *args, **kwargs):
        print('===>MyMeta.__call__')
        obj = self.__new__(self, *args, **kwargs)
        self.__init__(self, *args, **kwargs)
        return obj


class Foo(object, metaclass=MyMeta):
    tag = '!Foo'

    def __new__(cls, *args, **kwargs):
        print('===>Foo.__new__')
        return super().__new__(cls)

    def __init__(self, name):
        print('===>Foo.__init__')
        self.name = name

print('test start')
foo = Foo('test')
print('test end')


#輸出
#===>MyMeta.__new__
#MyMeta
#===>MyMeta.__init__
#Foo
#{'tag': '!Foo', '__module__': '__main__', '__init__': <function Foo.__init__ at 0x00000000010F7950>, '__new__': <function Foo.__new__ at 0x00000000010F78C8>, '__qualname__': 'Foo'}
#!Foo
#test start
#===>MyMeta.__call__
#===>Foo.__new__
#===>Foo.__init__
#test end

在創建Foo類的時候,python做了如下操作,

  1. Foo中有metaclass這個屬性嗎?如果是,Python會在記憶體中通過metaclass創建一個名字為Foo的類物件(我說的是類物件,請緊跟我的思路),
  2. 如果Python沒有找到metaclass,它會繼續在父類中尋找metaclass屬性,并嘗試做和前面同樣的操作,
  3. 如果Python在任何父類中都找不到metaclass,它就會在模塊層次中去尋找metaclass,并嘗試做同樣的操作,
  4. 如果還是找不到metaclass,Python就會用內置的type來創建這個類物件,

現在的問題就是,你可以在metaclass中放置些什么代碼呢?
答案就是:可以創建一個類的東西,那么什么可以用來創建一個類呢?type,或者任何使用到type或者子類化type的東西都可以,用類實作可以(比如上面這個例子),用函式實作也可以,但是metaclass必須回傳一個類,

def MyMetaFunction(classname, superclasses, attributedict):
    attributedict['year'] = 2019
    return type(classname, superclasses, attributedict)



class Foo(object, metaclass=MyMetaFunction):

    tag = '!Foo'

    def __new__(cls, *args, **kwargs):
        print('===>Foo.__new__')
        return super().__new__(cls)

    def __init__(self, name):
        print('===>Foo.__init__')
        self.name = name

print('test start')
foo = Foo('test')
print('name:%s,tag:%s,year:%s' % (foo.name, foo.tag, foo.year))
print('test end')

#輸出
#test start
#===>Foo.__new__
#===>Foo.__init__
#name:test,tag:!Foo,year:2019
#test end

把上面的例子運行完之后就會明白很多了,正常情況下我們在父類中是不能對子類的屬性進行操作,但是元類可以,換種方式理解:元類、裝飾器、類裝飾器都可以歸為元編程(參考自 python-cook-book 中的一句話),

3、應用

一、實作ORM

我們通過創建一個類似Django中的ORM來熟悉一下元類的使用,通過元類用來創建API是非常好的選擇,使用元類的撰寫很復雜但使用者可以非常簡潔的呼叫API

#一、首先定義Field類,它負責保存資料庫表的欄位名和欄位型別
class Field(object):

    def __init__(self, name, column_type):
        self.name = name
        self.colmun_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)')


class IntegerField(Field):

    def __init__(self, name):
        super().__init__(name, 'bigint')

#二、定義元類,控制Model物件的創建
class ModelMetaClass(type):

    def __new__(cls, name, bases, attrs):

        if name == 'Model':
            return super().__new__(cls, name, bases, attrs)
        mappings = dict()

        for k,v in attrs.items():
            #保持類屬性和列的映射關系到mappings字典
            if isinstance(v,Field):
                print('Found mapping:%s==>%s' % (k, v))
                mappings[k] = v
                
        for k in mappings.keys(): #將類屬性移除,是定義的類欄位不污染User類屬性,只在實體中可以訪問這些key
            attrs.pop(k)
        attrs['__table__'] = name.lower()  #假設表名為類名的小寫,創建類時添加一個__table__屬性
        attrs['__mappings__'] = mappings #保持屬性和列的關系映射,創建類時添加一個__mappings__屬性
        return super().__new__(cls, name, bases, attrs)

#三、Model基類
class Model(dict, metaclass=ModelMetaClass):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError("'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        
        for k,v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self,k,None))
            
        sql = 'insert into %s (%s) values (%s)' % (self.__table__,','.join(fields),','.join(params))
        print('SQL:%s' % sql)
        print('ARGS:%s' % str(args))

#我們想創建類似Django的ORM,只要定義欄位就可以實作對資料庫表和欄位的操作
#最后、我們使用定義好的ORM介面,使用起來非常簡單
class User(Model):

    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

user = User(id=1,name='Job',email='[email protected]',password='pw')
user.save()


#輸出
#Found mapping:password==><StringField:password>
#Found mapping:id==><IntegerField:id>
#Found mapping:email==><StringField:email>
#Found mapping:name==><StringField:username>
#SQL:insert into user (email,id,password,username) values (?,?,?,?)
#ARGS:['[email protected]', 1, 'pw', 'Job']

二、單例

依照Python官方檔案的說法,__new__方法主要是當你繼承一些不可變的class時(比如int, str, tuple), 提供給你一個自定義這些類的實體化程序的途徑,還有就是實作自定義的metaclass,

簡單來說,單例模式的原理就是通過在類屬性中添加一個單例判定位ins_flag,通過這個flag判斷是否已經被實體化過了,如果被實體化過了就回傳該實體,

1)、__new__方法實作單例

class Singleton:

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):     #_instance是類(Singleton)物件的一個屬性
            cls._instance= super().__new__(cls, *args, **kwargs)
        return cls._instance #類的__new__方法之后,必須生成本類的實體(注意是“本類”的實體)才能自動呼叫本類的__init__方法進行初始化,否則不會自動呼叫__init__

class SubSingleton(Singleton):
    pass

s1 = Singleton()
s2 = Singleton()
print(s1 is s2)

ss1 = SubSingleton()
ss2 = SubSingleton()
print(ss1 is ss2)

#輸出
#True
#True

因為重寫__new__方法,所以繼承至Singleton的類,在不重寫__new__的情況下都將是單例模式, _instance(單下劃線開頭)屬性換成__instance(雙下劃線開頭)會得到不一樣的結果,將無法實作單例模式,如果__instance(雙下劃線開頭)屬性就變成了私有的(其實變成了_Singleton__instance),

2)、元類實作單例

class SingletonMeta(type):

    def __init__(self,*args,**kwargs):
        self.__instance = None    #這是一個私有屬性來保存屬性,而不會污染Singleton類(其實還是會污染,只是無法直接通過__instance屬性訪問)
        super().__init__(*args,**kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super().__call__(*args, **kwargs)
        return self.__instance

class Singleton(metaclass=SingletonMeta): #在代碼執行到這里的時候,元類中的__new__方法和__init__方法其實已經被執行了,而不是在Singleton實體化的時候執行,且僅會執行一次,
    pass

class SubSingleton(metaclass=SingletonMeta):
    pass
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)

ss1 = SubSingleton()
ss2 = SubSingleton()
print(ss1 is ss2)

#輸出
#True
#True
  • 我們知道元類(SingletonMeta)生成的實體是一個類(Singleton),而這里我們僅僅需要對這個實體(Singleton)增加一個屬性(__instance)來判斷和保存生成的單例,想想也知道為一個類添加一個屬性當然是在__init__中實作了,
  • 關于__call__方法的呼叫,因為Singleton是SingletonMeta的一個實體,所以Singleton()這樣的方式就呼叫了SingletonMeta的__call__方法,

三、動態加載

YAML是一個家喻戶曉的 Python 工具,可以方便地序列化 / 逆序列化結構資料,YAMLObject 的一個超越變形能力,就是它的任意子類支持序列化和反序列化(serialization & deserialization),比如說下面這段代碼(https://pyyaml.org/wiki/PyYAMLDocumentation):

class Monster(yaml.YAMLObject):

  yaml_tag = u'!Monster'
  def __init__(self, name, hp, ac, attacks):
    self.name = name
    self.hp = hp
    self.ac = ac
    self.attacks = attacks

  def __repr__(self):
    return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
       self.__class__.__name__, self.name, self.hp, self.ac,     
       self.attacks)


yaml.load("""
--- !Monster
name: Cave spider
hp: [2,6]    # 2d6
ac: 16
attacks: [BITE, HURT]
""")

Monster(name='Cave spider', hp=[2, 6], ac=16, attacks=['BITE', 'HURT'])

print yaml.dump(Monster(
    name='Cave lizard', hp=[3,6], ac=16, attacks=['BITE','HURT']))
# 輸出

!Monster

ac: 16

attacks: [BITE, HURT]

hp: [3, 6]
name: Cave lizard

這里 YAMLObject 的特異功能體現在哪里呢?

你看,呼叫統一的 yaml.load(),就能把任意一個 yaml 序列載入成一個 Python Object;而呼叫統一的 yaml.dump(),就能把一個 YAMLObject 子類序列化,對于 load() 和 dump() 的使用者來說,他們完全不需要提前知道任何型別資訊,這讓超動態配置編程成了可能,聽大神說在他的實戰經驗中,許多大型專案都需要應用這種超動態配置的理念,

比方說,在一個智能語音助手的大型專案中,我們有 1 萬個語音對話場景,每一個場景都是不同團隊開發的,作為智能語音助手的核心團隊成員,我不可能去了解每個子場景的實作細節,

在動態配置實驗不同場景時,經常是今天我要實驗場景 A 和 B 的配置,明天實驗 B 和 C 的配置,光組態檔就有幾萬行量級,作業量不可謂不小,而應用這樣的動態配置理念,我就可以讓引擎根據我的文本組態檔,動態加載所需要的 Python 類,

對于 YAML 的使用者,這一點也很方便,你只要簡單地繼承 yaml.YAMLObject,就能讓你的 Python Object 具有序列化和逆序列化能力,是不是相比普通 Python 類,有一點“變態”,有一點“超越”?

YAML 的這種動態序列化 / 逆序列化功能正是用metaclass 實作的,

我們這里只看 YAMLObject 的 load() 功能,簡單來說,我們需要一個全域的注冊器,讓 YAML 知道,序列化文本中的 !Monster 需要載入成 Monster 這個 Python 型別,

一個很自然的想法就是,那我們建立一個全域變數叫 registry,把所有需要逆序列化的 YAMLObject,都注冊進去,比如下面這樣:

registry = {}

def add_constructor(target_class):
    registry[target_class.yaml_tag] = target_class

然后,在 Monster 類定義后面加上下面這行代碼:

add_constructor(Monster)

但這樣的缺點也很明顯,對于 YAML 的使用者來說,每一個 YAML 的可逆序列化的類 Foo 定義后,都需要加上一句話,add_constructor(Foo),這無疑給開發者增加了麻煩,也更容易出錯,畢竟開發者很容易忘了這一點,

那么,更優的實作方式是什么樣呢?如果你看過 YAML 的原始碼,就會發現,正是 metaclass 解決了這個問題,

# Python 2/3 相同部分

class YAMLObjectMetaclass(type):

    def __init__(cls, name, bases, kwds):
        super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)

        if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
            cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
    # 省略其余定義


# Python 3
class YAMLObject(metaclass=YAMLObjectMetaclass):
    yaml_loader = Loader
    # 省略其余定義


# Python 2
class YAMLObject(object):
    __metaclass__ = YAMLObjectMetaclass

    yaml_loader = Loader
    # 省略其余定義

你可以發現,YAMLObject 把 metaclass 都宣告成了YAMLObjectMetaclass,利用 YAMLObjectMetaclass 的__init__方法,為所有 YAMLObject 子類偷偷執行add_constructor(),在 YAMLObjectMetaclass 中,下面這行代碼就是魔法發生的地方:

cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml) 

YAML 應用 metaclass,攔截了所有 YAMLObject 子類的定義,也就說說,在你定義任何 YAMLObject 子類時,Python 會強行插入運行下面這段代碼,把我們之前想要的add_constructor(Foo)給自動加上,

cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)

所以 YAML 的使用者,無需自己去手寫add_constructor(Foo) ,怎么樣,是不是其實并不復雜?

4、總結

正常情況下我們在父類中是不能對子類的屬性進行操作,但是元類可以,這就使得程式代碼的維護變得困難,metaclass 是 Python 的黑魔法之一,在掌握它之前不要輕易嘗試,感覺上python的規范原則很松,但這也使得python更靈活,對代碼的撰寫理應由程式員自己負責,自己寫的代碼還是得自己負責啊,

元類、裝飾器、類裝飾器都可以歸為元編程,它們之間有一些相似點,還是在實際的應用中選擇比較,使用合適的工具進行編程吧,

參考:

https://www.cnblogs.com/tkqasn/p/6524879.html

https://time.geekbang.org/column/article/101288

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/85041.html

標籤:Python

上一篇:136只出現一次的數字

下一篇:python的串列生成式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more