主頁 > 後端開發 > Django筆記三十之log日志記錄詳解

Django筆記三十之log日志記錄詳解

2023-04-26 07:28:53 後端開發

本文首發于公眾號:Hunter后端
原文鏈接:Django筆記三十之log日志的記錄詳解

這一節介紹在 Django 系統里使用 logging 記錄日志

以下是一個簡單的 logging 模塊示例,可以先預覽一下,接下來會詳細介紹各個模塊的具體功能:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(message)s',
        }
    },
    'handlers': {
        'file_1': {
            'level': 'INFO',
            'filename': '/Users/hunter/python/log_path/file_1.log',
            'formatter': 'verbose',
            'class': 'logging.FileHandler',
        },
        'file_2': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': '/Users/hunter/python/log_path/file_2.log',
            'formatter': 'verbose',
        },
        'custom_file': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': '/Users/hunter/python/log_path/custome_file.log',
            'formatter': 'verbose',
        }
    },
    'loggers': {
        '': {
            'handlers': ['file_1'],
            'level': 'INFO',
            'propagate': False,
        },
        'django': { 
            'handlers': ['file_2'],
            'level': 'INFO',
            'propagate': True,
        },
        'custom': {
            'handlers': ['custom_file'],
            'level': 'INFO',
            'propagate': False,
        }
    }
}

以下是本篇筆記全部內容:

  1. 模塊總覽
  2. Loggers
  3. Handlers
  4. Filters
  5. Formatters
  6. 日志記錄方式
  7. logger 引數決議
  8. handler 引數決議
    1. RotatingFileHandler 配置
    2. TimedRotatingFileHandler 配置
    3. HttpHandler 基本配置
    4. SMTPHandler 基本配置
    5. AdminEmailHandler 基本配置
  9. formatter 引數決議
  10. 指定 logger 輸出
  11. 日志配置示例

1、模塊總覽

在 Django 系統中,日志的記錄也可以在 setting.py 中配置,key 為 logging,然后下面有幾個主要的模塊:

loggers、handlers、filters、formatters

系統接收到日志資訊后,進入 logger,然后根據指定的 handler 串列發送到 handler 中

根據 handler 的處理方式,將資訊寫入檔案、發送郵件或者其他方式

這些資訊可以經過 filter 進行進一步的過濾,根據 formatter 的資訊組織形式通過 handler 的處理方式進行處理

2、Loggers

Loggers 是學習日志系統的一個切入點,每個 logger 都是一個命名的桶,處理的資訊可以作為日志寫入到 logger 里

每一個 logger 都可以被配置一個日志等級,日志等級描述了 logger 記錄的資訊的嚴重程度,python 定義了如下幾種日志等級:

  • DEBUG:低的、基于除錯目的的系統資訊
  • INFO:一般系統訊息
  • WARNING:發生了小問題的資訊
  • ERROR:發生了大問題的資訊
  • CRITICAL:發生了嚴重的問題的資訊

每個被寫入 logger 的訊息都被稱為是一個 Log Record(日志記錄),

每個日志記錄在被發送到 logger 的時候都有一個日志等級來表示資訊的嚴重程度
比如:

logger.info("xxx")

這些日志記錄應該包含一些有用的、包含了問題產生原因的資訊

當一條訊息被發送到 logger,訊息的等級會和 logger 的日志等級做一個比較,只有當訊息的等級大于或等于 logger 的記錄等級時,訊息才會被當前 logger 進行更多的處理

如果這條訊息被 logger 接收,那么它會被發送到 Handlers

3、Handlers

我們可以理解 handler 是一個處理器,用來決定每天發送到 logger 的資訊應該怎么處理,也就是日志的記錄形式

比如說寫入一個檔案,發送郵件等

跟 Logger 一樣,handler也有一個日志等級,只有當發送到 handler 的日志等級大于等于 handler 的日志記錄時,handler 才會處理資訊

一個 Logger 可以有多個 handler 處理器,每個 handler 都可以有自己的日志等級,因此可以根據資訊的重要程度來決定不同的輸出

比如你可以用一個 handler 把 ERROR 和 CRITICAL 等級的資訊轉發到服務頁面,另一個 handler 記錄所有的資訊到一個檔案,用作后續的分析

4、Filters

過濾器常被用來提供額外的控制,處理從 logger 到 handler 的日志記錄

理論上來說,任何日志訊息只要滿足了日志等級的要求,都會被發送到 handler 處理,如果加了一個 filter 過濾器,你可以在日志處理上添加額外的標準

比如說你可以添加一個過濾器,只允許某個特定來源的 ERROR 等級的資訊被處理

filter 也可以用來修改訊息的嚴重等級,比如一些特定的條件被滿足的情況下,你可以將ERROR等級的日志降級為 WARNING

在本篇筆記中,將不介紹 filter 的使用方法,因為能簡單就簡單一點,暫時不用那么多配置

5、Formatters

格式化,一個日志記錄需要被渲染成一個文本,formatter 提供了一些格式器的屬性,格式化器由一些 LogRecord 的屬性值組成,你也可以自己定義一個屬性

6、日志記錄方式

當你配置了 loggers,handlers,filters 和 formatters 之后,你可以先獲取一個 logger 的實體,然后通過 logger 來記錄日志

以下是使用示例:

import logging

logger = logging.getLogger(__name__)

def my_view(request):
    logger.info("this is a log")

這個在呼叫 my_view 的時候,系統就會記錄一條日志

如果是其他等級的日志記錄,則會是:

logger.debug()
logger.info()
logger.warning()
logger.error()
logger.critical()

以下是對日志的記錄流程匯總一下:

  • 當有一條日志資訊需要被記錄,然后會被發送到對應的 logger
  • 然后 logger 根據指定的 handler 被發送到對應的 handler 處理器
  • 在 handler 中會根據日志的等級或者定義的 filter 進行一定的過濾
  • 最終將符合條件的日志資訊根據 formatter 的格式定義,將最終形成的日志資訊,進行 console 操作、記錄到檔案、或者發送郵件等操作

在筆記開篇的 logging 示例中,日志的配置在這個 dict 里撰寫的順序和訊息處理的順序是相反的

這里沒有設定 filter 的操作,所以訊息的處理就是從 logger 到 handler 再到 formatter

我們手動在介面里寫入一個日志訊息,分別在 urls.py 和 views.py 里如下定義:

# blog/urls.py
from django.urls.conf import path
from blog.views import time_view


urlpatterns = [
    path("curr_time", time_view),
]
# blog/views.py
import datetime
from django.http import HttpResponse

import logging

logger = logging.getLogger(__name__)

def time_view(request):
    now = datetime.datetime.now()
    html = "<h1>now: %s</h1>" % now
    logger.info("this is a log !")
    return HttpResponse(html)

啟動系統后,在瀏覽器中訪問 http://localhost:9898/blog/curr_time,可以看到定義的日志目錄下已經寫入了資料:file_1.log 和 file_2.log

打開這兩個日志檔案,可以看到 loggers 下空字串指定的 logger 對應的處理器寫入的 file_1.log 寫入的內容如下:

INFO this is a log ! xxxx
INFO "GET /blog/curr_time HTTP/1.1" 200 40 xxxx

其中包含介面訪問資訊和我們在介面里自定義的 'this is a log !' 資訊

在 file_2.log 中,則只有介面的訪問資訊:

INFO  200 40 xxxx

在實體化 logger 的時候,如果不指定 logger 的名稱,那么則會默認寫入我們定義的空字串下的 logger

不指定 logger 名稱的意思即為,getLogger 的時候不指定 logger 的引數:

logger = logging.getLogger(__name__)

7、logger 引數決議

在這里 loggers 里設定兩個 key,一個為空字串,一個是 django,

我們可以理解 key 為 django' 這個 logger 是一個固定的值,會接收到所有來自系統的日志資訊,比如一些介面的請求資訊,但是不包括用戶自定的 logger 輸出,

空字串這里的 logger,可以接收到用戶自定義的 logger 輸出,也可以接收到一些介面的請求資訊,但是這個需要 propagate 的配置

在 loggers 的配置里面:

    'loggers': {
        '': {
            'handlers': ['file_1'],
            'level': 'INFO',
            'propagate': False,
        },
        'django': {
            'handlers': ['file_2'],
            'level': 'INFO',
            'propagate': True,
        }
    }

有如下幾個引數:
handlers 是指定訊息處理器的,value 是一個串列,可以指定多個處理器,比如說一條訊息,你可以同時指定寫入檔案和發送郵件,或者寫入不同的檔案

level 引數表示日志的等級,這里設定的是 INFO 等級,如果接收到的訊息的等級小于 INFO,那么就會不處理,大于等于 INFO 才會被發送到 handler 處理器中處理

propagate 引數意義可以理解為是否傳遞傳遞,在這兩個 logger 里,如果 django 這個 logger 的 propagate 的值設為了 True,django 這個 logger 的訊息是可以向 空字串設定的 logger 傳遞的

換句話說,django 接收到的所有訊息都會給空字串的 logger 再發一遍,使用它的 logger 再進行一遍處理,
如果 propagate 設為了 False,那么空字串的 logger 僅能接收到用戶自定義的訊息

8、handler 引數決議

當一條訊息從 logger 被發送到 handler,handlers 引數也可以定義多個,通過不同的 key 來區分

在每個 handler 下我們這里設定了四個值:

level 設定了 handler 處理的日志等級,只有當發送過來的日志的等級大于等于該等級時,這個 handler 才會處理

class 設定了日志處理的方式,這里我們的值為 logging.FileHandler,表示是檔案處理方式

此外還有比如 StreamHandler 輸出到 Stream 列印到標準輸出,還有 HttpHandler 通過HTTP 協議向服務器發送 log, 還有 SMTPHandler 會通過 email 發送log

filename 指定輸出的日志地址,前面我們的 class 定義為向檔案輸出,那么這里的 filename 就定義了輸出的檔案的地址

formatter 則是指定下一級日志文本的輸出格式處理的 formatter

日志檔案處理策略

對于日志檔案,如果系統一直運行,那么則會存在一個問題,那就是日志檔案越來越大,這個對于系統的存盤和我們查找日志都是不合適的

因此接下來我們新增幾個引數用來制定日志檔案的處理策略

maxBytes,這個定義了一個日志檔案最大的位元組數,如果寫滿了就會新開一個檔案繼續寫而不是繼續在原有檔案繼續增加內容

如果我們需要設定一個檔案最大為5M,就可以設為 5 * 1024 * 1024

backupCount,最大的日志檔案數量,當檔案的個數超出了我們定義的,則會洗掉最早的日志檔案,只保留 backupCount 個日志檔案

但是使用上面這兩個引數的話,class 的值就得換成 logging.handlers.RotatingFileHandler

接下來介紹幾種 handler 的資訊處理方式

1.RotatingFileHandler 配置

rotate 的是定期調換位子,輪換的意思

RotatingFileHandler 的作用是根據檔案的大小決定是否寫入新檔案,以下是一個示例:

        'custom_file': {
            'level': 'INFO',
            'filename': '/home/hunter/python/log_path/custom.log',
            'class': 'logging.handlers.RotatingFileHandler',
            'formatter': 'verbose',
            'maxBytes': 5 * 1024 * 1024,
            'backupCount': 10
        }

這個示例表示是將日志寫入檔案,每個檔案最大容量為 5 * 1024 * 1024,即 5M,當日志寫入一個檔案滿了 5M 之后,將會新開一個檔案繼續寫入日志資訊,檔案夾下保留最新的 10 個檔案,

這里新增了兩個配置項

backupCount 表示最多保留日志檔案的個數

maxBytes 表示每個日志檔案最大的存盤容量

2.TimedRotatingFileHandler 配置

TimedRotatingFileHandler 表示是根據時間間隔來決定是否寫入新檔案,以下是示例:

        'time_file': {
            'level': 'INFO',
            'filename': '/home/hunter/python/log_path/custom.log',
            'class': 'logging.handlers.TimedRotatingFileHandler',  # 記錄時間
            'formatter': 'verbose',
            'backupCount': 3,
            'when': 'M',
            'interval': 3,
        }

當 handler 的 class 的值為這個的時候,表示的是根據時間來決定是否寫入新檔案,上一個是根據檔案的容量大小來定的

這里新增了兩個配置項,

一個是 when,表示的時間間隔的單位,S為秒,M為分鐘,H為小時,D或者 MIDNIGHT為天,W0-W6為從周一到周日某個周幾開始間隔一周

另一個是 interval,間隔時間的倍數

日志換新檔案繼續寫入的時間為 when * interval

3.HttpHandler 基本配置

這個配置表示是如果來了需要處理的日志訊息就呼叫一個 HTTP 介面,這里我們可以只做一個示例:

        'http_handler': {
            'level': 'INFO',
            'class': 'logging.handlers.HTTPHandler',
            'formatter': 'verbose',
            'host': '192.168.1.8:9898',
            'url': '/test_url',
            'method': 'POST',
        },

這個地方,多了幾個配置項

host 表示需要呼叫介面的 ip 和 埠

url 表示呼叫的介面路徑

method 表示呼叫的方法

4.SMTPHandler 基本配置

這個配置用于發送郵件,如果日志訊息發送到這個配置的 handler,系統會根據郵件的配置系統發送郵件給指定的郵箱

以下是一個使用示例:

        'email': {
            'level': 'WARNING',
            'class': 'logging.handlers.SMTPHandler',
            'mailhost': ('smtp.163.com', 25),
            'fromaddr': '[email protected]',
            'toaddrs': '[email protected]',
            'subject': '系統出錯啦!!!',
            'credentials': ('[email protected]', 'JBD******'),
            'timeout': 20
        },

在這個配置中,多的配置項的介紹如下:

mailhost 是系統發送郵件的郵箱的主機和埠,這里我們配置的是 163 郵箱

fromaddr 是從哪個郵箱發出來,我們可以創建一個163郵箱然后指定該值

toaddrs 是發送到哪個郵箱,即日志訊息的郵件接收地址

subject 是我們發送郵件的標題,而郵件的正文內容即為我們在 logger.warning("報錯資訊") 中輸入的資訊

credentials 是163郵箱的驗證資訊,兩個值,前一個值與 fromaddr 保持一致,后面的是一串驗證碼,是163郵箱開啟 SMTP 服務之后163郵箱系統頁面給我們的一串授權密碼,這個可以自己去了解一下

這樣配置好之后,在 logger 的 handler 串列指定這個 handler,然后通過 logger.warning("報錯資訊") 即可觸發這個郵件發送的功能

5.AdminEmailHandler 基本配置

這個配置也是用于日志發送郵件,但是是復用 Django 的默認郵箱的功能

在 logging 中的配置是:

        'mail_admins': {
            'level': 'WARNING',
            'class': 'django.utils.log.AdminEmailHandler',
            'include_html': True,
        },

但是這個還需要一些額外的在 settings.py 中的郵箱配置,相當于是復用 Django 系統的功能

以下是 settings.py 中郵箱的配置項:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'   # 163 郵箱的配置地址
EMAIL_PORT = 465  # SMTP 埠
EMAIL_HOST_USER = '[email protected]'   #這個是用來發送郵件的郵箱,與最后一個填寫的郵箱地址一致
EMAIL_HOST_PASSWORD = 'JBDM******'  #這里就是前面提到的授權密碼
EMAIL_USE_SSL = True
EMAIL_FROM = SERVER_EMAIL = '[email protected]' # 這個是發送郵件的地址,與上面的 163郵箱相同即可
ADMINS = [
    ['Hunter', '[email protected]'],
]  # 郵件接收地址

上面的引數都配置好之后也可以日志觸發郵件了,

9、formatter 引數決議

formatter 的引數就簡單一點,通過不同的 key 來區分不同的 formatter,其下設定一個 format 引數即可對資訊進行格式化處理

    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(message)s',
        }
    },

在示例中只設定了 levelname 和 message 兩個引數,levelname 即為該日志訊息的等級,message為訊息內容

對于請求介面的 message 資訊,回傳的內容是固定的,比如前面的示例:

"GET /blog/curr_time HTTP/1.1" 200 40

前面是介面的請求方式、介面路徑和HTTP協議,然后是介面回傳的狀態碼,這里是 200,后面跟著的 40 這個數字則是介面回傳的字符長度

如果是用戶在系統里手動寫入的 message,則是定義的什么內容,輸出的就是什么內容

對于 format 的定義的引數還有很多,以下是幾個常用的匯總:

引數名稱 引數用法 含義
levelname %(levelname)s 日志等級
message %(message)s 訊息內容
asctime %(asctime)s 時間,格式為'2022-01-01 00:00:00,000'
pathname %(pathname)s 日志輸出所在檔案的全路徑
filename %(filename)s 日志輸出所在的檔案名
module %(module)s 日志輸出所在的模塊,可以理解成不帶后綴的檔案名
name %(name)s 呼叫日志使用的名稱,logging.getLogger(name)時為從模塊到函式,比如 blog.views
funcName %(funcName)s 日志輸出的函式名稱
lineno %(lineno)d 日志輸出所在的檔案的行數
process %(process)d 行程id
processName %(processName)s 行程名稱
thread %(thread)d 執行緒id
threadName %(threadName)s 執行緒名稱

10、指定 logger 輸出

之前我們設定的用戶手動輸入的日志被傳送給了 key 為空字串下的 logger,如果我們想把某一些日志資訊專門輸出到某個檔案怎么處理呢?

在獲取 logger 的時候就需要根據 logger 的 key 來指定對應的 logger,比如我們新建一個名為 custom 的 logger 和 對應的 handler,然后輸出的地方指定即可,如下:

        'custom': {
            'handlers': ['custom_file'],
            'level': 'INFO',
            'propagate': False,
        }

指定 logger 輸出:

import datetime
from django.http import HttpResponse

import logging

custom_logger = logging.getLogger("custom")  # 對應 logging 配置中的 key 為 custom 的 logger 


def time_view(request):
    now = datetime.datetime.now()
    html = "<h1>now: %s</h1>" % now
    custom_logger.info("this is a custom log")
    return HttpResponse(html)

這樣在對應的地方就可以實作專門的日志輸出到專門的檔案了,

11、日志配置示例

接下來我們實作這樣一個日志配置的功能:

  1. 實作用戶所有普通的手動輸出都寫入一個 manual.log 檔案
  2. 所有介面的請求資料都輸入到一個 request.log 檔案
  3. 設定一個單獨的日志輸出,可以輸出到指定檔案
  4. 所有 INFO 級別的日志都輸出到檔案,高于 INFO 的都發送郵件通知指定聯系人
  5. 對于日志檔案要求每個檔案最大容量為 50M,且檔案夾下每個型別的日志最多只有10個
  6. 日志的資訊結構為:日志等級-時間-日志輸出所在檔案名-日志輸出所在函式名-日志輸出所在檔案的行數-訊息內容

以下是實作上面這個功能的 logging 配置:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(filename)s %(funcName)s %(lineno)d %(message)s',
        }
    },
    'handlers': {
        'manual_file': {
            'level': 'INFO',
            'filename': '/Users/hunter/python/log_path/manual.log',
            'formatter': 'verbose',
            'class': 'logging.handlers.RotatingFileHandler',
            'maxBytes': 5 * 1024 * 1024,
            'backupCount': 10
        },
        'request_file': {
            'level': 'INFO',
            'filename': '/Users/hunter/python/log_path/request.log',
            'class': 'logging.handlers.RotatingFileHandler',
            'formatter': 'verbose',
            'maxBytes': 5 * 1024 * 1024,
            'backupCount': 10
        },
        'custom_file': {
            'level': 'INFO',
            'filename': '/Users/hunter/python/log_path/custom.log',
            'class': 'logging.handlers.RotatingFileHandler',
            'formatter': 'verbose',
            'maxBytes': 5 * 1024 * 1024,
            'backupCount': 10
        },
        'email': {
            'level': 'WARNING',
            'class': 'logging.handlers.SMTPHandler',
            'mailhost': ('smtp.163.com', 25),
            'fromaddr': '[email protected]',
            'toaddrs': '[email protected]',
            'subject': '系統出錯啦!!!',
            'credentials': ('[email protected]', 'JBD*******'),
            'timeout': 20
        },
    },
    'loggers': {
        '': {
            'handlers': ['manual_file', 'email'],
            'level': 'INFO',
            'propagate': False,
        },
        'django': {
            'handlers': ['request_file'],
            'level': 'INFO',
            'propagate': True,
        },
        'custom': {
            'handlers': ['custom_file'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

然后我們定義一個介面內容:

import datetime
from django.http import HttpResponse, JsonResponse

import logging

logger = logging.getLogger(__name__)
custom_logger = logging.getLogger("custom")


def time_view(request):
    now = datetime.datetime.now()
    html = "<h1>now: %s</h1>abc\nabc" % now
    logger.info("this is a log !")
    custom_logger.info("this is a custom log")
    logger.warning("報錯啦!!!")
    return HttpResponse(html)

呼叫這個介面即可發現實作了我們想要的功能啦!

如果想獲取更多后端相關文章,可掃碼關注閱讀:

image

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

標籤:Python

上一篇:ray-分布式計算框架-集群與異步Job管理

下一篇:返回列表

標籤雲
其他(158071) Python(38105) JavaScript(25391) Java(18001) C(15217) 區塊鏈(8260) C#(7972) AI(7469) 爪哇(7425) MySQL(7144) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5870) 数组(5741) R(5409) Linux(5329) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4561) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2431) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1960) Web開發(1951) HtmlCss(1926) python-3.x(1918) 弹簧靴(1913) C++(1911) xml(1889) PostgreSQL(1874) .NETCore(1855) 谷歌表格(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
最新发布
  • Django筆記三十之log日志記錄詳解

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記三十之log日志的記錄詳解 這一節介紹在 Django 系統里使用 logging 記錄日志 以下是一個簡單的 logging 模塊示例,可以先預覽一下,接下來會詳細介紹各個模塊的具體功能: LOGGING = { 'version': ......

    uj5u.com 2023-04-26 07:28:53 more
  • ray-分布式計算框架-集群與異步Job管理

    0. ray 簡介 ray是開源分布式計算框架,為并行處理提供計算層,用于擴展AI與Python應用程式,是ML作業負載統一工具包 Ray AI Runtime ML應用程式庫集 Ray Core 通用分布式計算庫 Task -- Ray允許任意Python函式在單獨的Python worker上運 ......

    uj5u.com 2023-04-26 07:28:44 more
  • 【NLP教程】用python呼叫百度AI開放平臺進行情感傾向分析

    一、背景 Hi,大家!我是 @馬哥python說 ,一名10年程式猿。 今天我來演示一下:通過百度AI開放平臺,利用python呼叫百度介面進行中文情感傾向分析,并得出情感極性分為積極、消極還是中性以及置信度結果。 二、操作步驟 首先,打開百度AI首頁:百度AI開放平臺-全球領先的人工智能服務平臺 ......

    uj5u.com 2023-04-26 07:28:22 more
  • Python中文分詞庫——jieba的用法

    1.介紹 jieba是優秀的中文分詞第三方庫。由于中文文本之間每個漢字都是連續書寫的,我們需要通過特定的手段來獲得其中的每個單詞,這種手段就叫分詞。而jieba是Python計算生態中非常優秀的中文分詞第三方庫,需要通過安裝來使用它。 jieba庫提供了三種分詞模式,但實際上要達到分詞效果只要掌握一 ......

    uj5u.com 2023-04-26 07:27:56 more
  • [Python自動化]使用Python Pexpect模塊實作自動化互動腳本使用心

    使用Python Pexpect模塊實作自動化互動腳本使用心得 參考檔案:https://pexpect.readthedocs.io/en/stable/ 前言 在最近的作業中,需要使用DockerFile構建鏡像。在構建鏡像的程序中,有一些執行的命令是需要互動的。例如安裝tzdata(apt i ......

    uj5u.com 2023-04-26 07:27:52 more
  • Django 如何使用 Celery 完成異步任務或定時任務

    以前版本的 Celery 需要一個單獨的庫(django-celery)才能與 Django 一起作業, 但從 Celery 3.1 開始,情況便不再如此,我們可以直接通過 Celery 庫來完成在 Django 中的任務。 安裝 Redis 服務端 以 Docker 安裝為例,安裝一個密碼為 my ......

    uj5u.com 2023-04-26 07:27:48 more
  • 簡述PHP中trait的使用和同時引入多個trait時同名方法沖突的處理

    PHP的類是單一繼承模式,也就是每個類只能繼承一個父類(基類)。 但有時需要引入更多通用(共用)的方法,同時這些方法又不適合集成到基類。 那么這時,就需要使用其他方法來引入這些方法。其中trait,就是方法之一。 trait是PHP5.4之后出現的一種代碼復用方法,形式和Class非常相似,同時可以 ......

    uj5u.com 2023-04-26 07:21:26 more
  • 這可能是最全面的MySQL面試八股文了

    什么是MySQL MySQL是一個關系型資料庫,它采用表的形式來存盤資料。你可以理解成是Excel表格,既然是表的形式存盤資料,就有表結構(行和列)。行代表每一行資料,列代表該行中的每個值。列上的值是有資料型別的,比如:整數、字串、日期等等。 資料庫的三大范式 第一范式1NF 確保資料庫表欄位的原 ......

    uj5u.com 2023-04-25 09:31:53 more
  • 【Jmeter】按比例分配Api壓測

    先看 【Jmeter】基礎介紹-詳細 【Jmeter】Request1輸出作為Request2輸入-后置處理器 繼續聊提出的第二個問題,即 2.需要按比例分配API請求并發,以模擬真實的API壓力場景 做壓測的時候,一般的需求都是多個API同時壓,不然也看不出真正的tps是多少啊。 比如雖然介面a的 ......

    uj5u.com 2023-04-25 09:30:35 more
  • 這可能是最全面的MySQL面試八股文了

    什么是MySQL MySQL是一個關系型資料庫,它采用表的形式來存盤資料。你可以理解成是Excel表格,既然是表的形式存盤資料,就有表結構(行和列)。行代表每一行資料,列代表該行中的每個值。列上的值是有資料型別的,比如:整數、字串、日期等等。 資料庫的三大范式 第一范式1NF 確保資料庫表欄位的原 ......

    uj5u.com 2023-04-25 09:29:15 more