Jadual Kandungan
Permintaan dalam rangka kerja web
ThreadLocal
contextvars
c.Token
contextvars.Context
小结
Rumah pembangunan bahagian belakang Tutorial Python Cara Python menggunakan contextvars untuk mengurus pembolehubah konteks

Cara Python menggunakan contextvars untuk mengurus pembolehubah konteks

Aug 01, 2022 pm 02:52 PM
python

Artikel ini membawakan anda pengetahuan yang berkaitan tentang Python yang memperkenalkan modul dalam 3.7: contextvars Ia adalah mudah untuk melihat daripada nama yang merujuk kepada pembolehubah konteks di bawah Biarkan saya memberitahu anda secara terperinci untuk menggunakan contextvars untuk mengurus pembolehubah konteks saya harap ia akan membantu anda.

Cara Python menggunakan contextvars untuk mengurus pembolehubah konteks

[Cadangan berkaitan: Tutorial video Python3 ]

Python memperkenalkan modul dalam 3.7: contextvars, daripada nama Ianya mudah untuk melihat bahawa ia merujuk kepada pembolehubah konteks (Pembolehubah Konteks), jadi sebelum memperkenalkan contextvars kita perlu memahami dahulu apakah konteks (Konteks).

Konteks ialah objek yang mengandungi maklumat yang berkaitan Contohnya: "Sebagai contoh, dalam anime 13 episod, anda mengklik terus ke episod kelapan dan melihat heroin menangis di hadapan wira." Saya percaya anda tidak tahu mengapa heroin itu menangis pada masa ini, kerana anda tidak menonton kandungan episod sebelumnya dan kehilangan maklumat kontekstual yang berkaitan.

Jadi Konteks bukanlah perkara ajaib, fungsinya adalah untuk membawa beberapa maklumat tertentu.

Permintaan dalam rangka kerja web

Mari kita ambil fastapi dan sanic sebagai contoh untuk melihat cara mereka menghuraikan permintaan apabila permintaan itu masuk.

# fastapi
from fastapi import FastAPI, Request
import uvicorn

app = FastAPI()


@app.get("/index")
async def index(request: Request):
    name = request.query_params.get("name")
    return {"name": name}


uvicorn.run("__main__:app", host="127.0.0.1", port=5555)

# -------------------------------------------------------

# sanic
from sanic import Sanic
from sanic.request import Request
from sanic import response

app = Sanic("sanic")


@app.get("/index")
async def index(request: Request):
    name = request.args.get("name")
    return response.json({"name": name})


app.run(host="127.0.0.1", port=6666)
Salin selepas log masuk

Hantar permintaan untuk menguji dan lihat sama ada keputusannya betul.

Anda dapat melihat bahawa semua permintaan berjaya, dan untuk fastapi dan sanic, fungsi permintaan dan pandangan mereka disatukan. Iaitu, apabila permintaan datang, ia akan dirangkumkan ke dalam objek Permintaan dan kemudian dihantar ke fungsi pandangan.

Tetapi ini tidak berlaku untuk kelalang Mari kita lihat cara kelalang menerima parameter permintaan.

from flask import Flask, request

app = Flask("flask")


@app.route("/index")
def index():
    name = request.args.get("name")
    return {"name": name}


app.run(host="127.0.0.1", port=7777)
Salin selepas log masuk

Kami melihat bahawa untuk kelalang, ia adalah melalui permintaan import Jika ia tidak diperlukan, sudah tentu, saya tidak membandingkan kaedah mana yang lebih baik di sini, terutamanya untuk memimpin tema kami hari ini. Pertama sekali, untuk flask, jika saya mentakrifkan fungsi paparan yang lain, maka parameter permintaan masih diperoleh dengan cara yang sama, tetapi kemudian masalah timbul Jika fungsi pandangan yang berbeza menggunakan permintaan yang sama secara dalaman, tidakkah akan ada konflik?

Jelas sekali berdasarkan pengalaman kami dalam menggunakan kelalang, jawapannya adalah tidak, dan sebabnya ialah ThreadLocal.

ThreadLocal

ThreadLocal, dari namanya boleh disimpulkan bahawa ia pasti berkaitan dengan thread. Betul, ia digunakan secara khusus untuk mencipta pembolehubah tempatan, dan pembolehubah tempatan yang dibuat terikat pada benang.

import threading

# 创建一个 local 对象
local = threading.local()

def get():
    name = threading.current_thread().name
    # 获取绑定在 local 上的 value
    value = local.value
    print(f"线程: {name}, value: {value}")

def set_():
    name = threading.current_thread().name
    # 为不同的线程设置不同的值
    if name == "one":
        local.value = "ONE"
    elif name == "two":
        local.value = "TWO"
    # 执行 get 函数
    get()

t1 = threading.Thread(target=set_, name="one")
t2 = threading.Thread(target=set_, name="two")
t1.start()
t2.start()
"""
线程 one, value: ONE
线程 two, value: TWO
"""
Salin selepas log masuk

Anda dapat melihat bahawa kedua-dua utas tidak mempunyai pengaruh antara satu sama lain, kerana setiap utas mempunyai id uniknya sendiri Apabila mengikat nilai, ia akan terikat pada urutan semasa juga diperolehi daripada benang semasa. Anda boleh menganggap ThreadLocal sebagai kamus:

{
    "one": {"value": "ONE"},
    "two": {"value": "TWO"}
}
Salin selepas log masuk

Lebih tepat, kuncinya mestilah id utas Demi intuisi, kami menggunakan nama utas itu, tetapi secara ringkasnya, hanya pengikatan yang akan diperolehi apabila mendapatkannya Nilai pembolehubah pada benang ini.

Kelalang juga direka bentuk dengan cara ini secara dalaman, kecuali ia tidak menggunakan threading.local secara langsung, tetapi melaksanakan kelas Local Selain daripada menyokong thread, ia juga menyokong greenlet coroutines. Bagaimana pula? Pertama sekali, kita tahu bahawa terdapat "konteks permintaan" dan "konteks aplikasi" di dalam kelalang, yang dikekalkan melalui tindanan (dua tindanan berbeza).

# flask/globals.py
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
Salin selepas log masuk

Setiap permintaan akan terikat pada Konteks semasa dan akan dimusnahkan selepas permintaan selesai Proses ini diselesaikan oleh rangka kerja, dan pembangun hanya perlu menggunakan permintaan secara langsung. Oleh itu, butiran khusus proses permintaan boleh dilihat dalam kod sumber Di sini kita memberi tumpuan kepada satu objek: werkzeug.local.Local, iaitu kelas Tempatan yang disebutkan di atas. Mari lihat sebahagian daripada kod sumber secara langsung:

# werkzeug/local.py

class Local(object):
    __slots__ = ("__storage__", "__ident_func__")

    def __init__(self):
        # 内部有两个成员:__storage__ 是一个字典,值就存在这里面
        # __ident_func__ 只需要知道它是用来获取线程 id 的即可
        object.__setattr__(self, "__storage__", {})
        object.__setattr__(self, "__ident_func__", get_ident)

    def __call__(self, proxy):
        """Create a proxy for a name."""
        return LocalProxy(self, proxy)

    def __release_local__(self):
        self.__storage__.pop(self.__ident_func__(), None)

    def __getattr__(self, name):
        try:
            # 根据线程 id 得到 value(一个字典)
            # 然后再根据 name 获取对应的值
            # 所以只会获取绑定在当前线程上的值
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            # 将线程 id 作为 key,然后将值设置在对应的字典中
            # 所以只会将值设置在当前的线程中
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}

    def __delattr__(self, name):
        # 删除逻辑也很简单
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)
Salin selepas log masuk

Jadi kita lihat bahawa logik dalaman kelalang sebenarnya sangat mudah, dan pengasingan antara benang dicapai melalui ThreadLocal. Setiap permintaan akan terikat kepada Konteksnya sendiri, dan apabila memperoleh nilai, ia juga akan diperoleh daripada Konteks masing-masing, kerana ia digunakan untuk menyimpan maklumat yang berkaitan (yang penting, ia juga mencapai pengasingan).

Sejajar dengan itu, pada ketika ini anda telah memahami konteksnya, tetapi inilah masalahnya sama ada ia adalah threading.local atau Local yang dilaksanakan oleh flask itu sendiri, semuanya adalah untuk benang. Apakah yang perlu saya lakukan jika saya menggunakan coroutine yang ditakrifkan oleh async def? Bagaimana untuk mencapai pengasingan konteks setiap coroutine? Jadi akhirnya protagonis kami diperkenalkan: contextvars.

contextvars

Modul ini menyediakan satu set antara muka yang boleh digunakan untuk mengurus, menetapkan dan mengakses keadaan Konteks setempat dalam coroutine.

import asyncio
import contextvars

c = contextvars.ContextVar("只是一个标识, 用于调试")

async def get():
    # 获取值
    return c.get() + "~~~"

async def set_(val):
    # 设置值
    c.set(val)
    print(await get())

async def main():
    coro1 = set_("协程1")
    coro2 = set_("协程2")
    await asyncio.gather(coro1, coro2)


asyncio.run(main())
"""
协程1~~~
协程2~~~
"""
Salin selepas log masuk

ContextVar menyediakan dua kaedah, dapatkan dan tetapkan, untuk mendapatkan dan menetapkan nilai. Kami melihat bahawa kesannya adalah serupa dengan ThreadingLocal Data diasingkan antara coroutine dan tidak akan dipengaruhi oleh satu sama lain.

但我们再仔细观察一下,我们是在 set_ 函数中设置的值,然后在 get 函数中获取值。可 await get() 相当于是开启了一个新的协程,那么意味着设置值和获取值不是在同一个协程当中。但即便如此,我们依旧可以获取到希望的结果。因为 Python 的协程是无栈协程,通过 await 可以实现级联调用。

我们不妨再套一层:

import asyncio
import contextvars

c = contextvars.ContextVar("只是一个标识, 用于调试")

async def get1():
    return await get2()

async def get2():
    return c.get() + "~~~"

async def set_(val):
    # 设置值
    c.set(val)
    print(await get1())
    print(await get2())

async def main():
    coro1 = set_("协程1")
    coro2 = set_("协程2")
    await asyncio.gather(coro1, coro2)


asyncio.run(main())
"""
协程1~~~
协程1~~~
协程2~~~
协程2~~~
"""
Salin selepas log masuk

我们看到不管是 await get1() 还是 await get2(),得到的都是 set_ 中设置的结果,说明它是可以嵌套的。

并且在这个过程当中,可以重新设置值。

import asyncio
import contextvars

c = contextvars.ContextVar("只是一个标识, 用于调试")

async def get1():
    c.set("重新设置")
    return await get2()

async def get2():
    return c.get() + "~~~"

async def set_(val):
    # 设置值
    c.set(val)
    print("------------")
    print(await get2())
    print(await get1())
    print(await get2())
    print("------------")

async def main():
    coro1 = set_("协程1")
    coro2 = set_("协程2")
    await asyncio.gather(coro1, coro2)


asyncio.run(main())
"""
------------
协程1~~~
重新设置~~~
重新设置~~~
------------
------------
协程2~~~
重新设置~~~
重新设置~~~
------------
"""
Salin selepas log masuk

先 await get2() 得到的就是 set_ 函数中设置的值,这是符合预期的。但是我们在 get1 中将值重新设置了,那么之后不管是 await get1() 还是直接 await get2(),得到的都是新设置的值。

这也说明了,一个协程内部 await 另一个协程,另一个协程内部 await 另另一个协程,不管套娃(await)多少次,它们获取的值都是一样的。并且在任意一个协程内部都可以重新设置值,然后获取会得到最后一次设置的值。再举个栗子:

import asyncio
import contextvars

c = contextvars.ContextVar("只是一个标识, 用于调试")

async def get1():
    return await get2()

async def get2():
    val = c.get() + "~~~"
    c.set("重新设置啦")
    return val

async def set_(val):
    # 设置值
    c.set(val)
    print(await get1())
    print(c.get())

async def main():
    coro = set_("古明地觉")
    await coro

asyncio.run(main())
"""
古明地觉~~~
重新设置啦
"""
Salin selepas log masuk

await get1() 的时候会执行 await get2(),然后在里面拿到 c.set 设置的值,打印 "古明地觉~~~"。但是在 get2 里面,又将值重新设置了,所以第二个 print 打印的就是新设置的值。\

如果在 get 之前没有先 set,那么会抛出一个 LookupError,所以 ContextVar 支持默认值:

import asyncio
import contextvars

c = contextvars.ContextVar("只是一个标识, 用于调试",
                           default="哼哼")

async def set_(val):
    print(c.get())
    c.set(val)
    print(c.get())

async def main():
    coro = set_("古明地觉")
    await coro

asyncio.run(main())
"""
哼哼
古明地觉
"""
Salin selepas log masuk

除了在 ContextVar 中指定默认值之外,也可以在 get 中指定:

import asyncio
import contextvars

c = contextvars.ContextVar("只是一个标识, 用于调试",
                           default="哼哼")

async def set_(val):
    print(c.get("古明地恋"))
    c.set(val)
    print(c.get())

async def main():
    coro = set_("古明地觉")
    await coro

asyncio.run(main())
"""
古明地恋
古明地觉
"""
Salin selepas log masuk

所以结论如下,如果在 c.set 之前使用 c.get:

  • 当 ContextVar 和 get 中都没有指定默认值,会抛出 LookupError;
  • 只要有一方设置了,那么会得到默认值;
  • 如果都设置了,那么以 get 为准;

如果 c.get 之前执行了 c.set,那么无论 ContextVar 和 get 有没有指定默认值,获取到的都是 c.set 设置的值。

所以总的来说还是比较好理解的,并且 ContextVar 除了可以作用在协程上面,它也可以用在线程上面。没错,它可以替代 threading.local,我们来试一下:

import threading
import contextvars

c = contextvars.ContextVar("context_var")

def get():
    name = threading.current_thread().name
    value = c.get()
    print(f"线程 {name}, value: {value}")

def set_():
    name = threading.current_thread().name
    if name == "one":
        c.set("ONE")
    elif name == "two":
        c.set("TWO")
    get()

t1 = threading.Thread(target=set_, name="one")
t2 = threading.Thread(target=set_, name="two")
t1.start()
t2.start()
"""
线程 one, value: ONE
线程 two, value: TWO
"""
Salin selepas log masuk

和 threading.local 的表现是一样的,但是更建议使用 ContextVars。不过前者可以绑定任意多个值,而后者只能绑定一个值(可以通过传递字典的方式解决这一点)。

c.Token

当我们调用 c.set 的时候,其实会返回一个 Token 对象:

import contextvars

c = contextvars.ContextVar("context_var")
token = c.set("val")
print(token)
"""
<Token var=<ContextVar name=&#39;context_var&#39; at 0x00..> at 0x00...>
"""
Salin selepas log masuk

Token 对象有一个 var 属性,它是只读的,会返回指向此 token 的 ContextVar 对象。

import contextvars

c = contextvars.ContextVar("context_var")
token = c.set("val")

print(token.var is c)  # True
print(token.var.get())  # val

print(
    token.var.set("val2").var.set("val3").var is c
)  # True
print(c.get())  # val3
Salin selepas log masuk

Token 对象还有一个 old_value 属性,它会返回上一次 set 设置的值,如果是第一次 set,那么会返回一个

import contextvars

c = contextvars.ContextVar("context_var")
token = c.set("val")

# 该 token 是第一次 c.set 所返回的
# 在此之前没有 set,所以 old_value 是 <Token.MISSING>
print(token.old_value)  # <Token.MISSING>

token = c.set("val2")
print(c.get())  # val2
# 返回上一次 set 的值
print(token.old_value)  # val
Salin selepas log masuk

那么这个 Token 对象有什么作用呢?从目前来看貌似没太大用处啊,其实它最大的用处就是和 reset 搭配使用,可以对状态进行重置。

import contextvars
#### 
c = contextvars.ContextVar("context_var")
token = c.set("val")
# 显然是可以获取的
print(c.get())  # val

# 将其重置为 token 之前的状态
# 但这个 token 是第一次 set 返回的
# 那么之前就相当于没有 set 了
c.reset(token)
try:
    c.get()  # 此时就会报错
except LookupError:
    print("报错啦")  # 报错啦

# 但是我们可以指定默认值
print(c.get("默认值"))  # 默认值
Salin selepas log masuk

contextvars.Context

它负责保存 ContextVars 对象和设置的值之间的映射,但是我们不会直接通过 contextvars.Context 来创建,而是通过 contentvars.copy_context 函数来创建。

import contextvars

c1 = contextvars.ContextVar("context_var1")
c1.set("val1")
c2 = contextvars.ContextVar("context_var2")
c2.set("val2")

# 此时得到的是所有 ContextVar 对象和设置的值之间的映射
# 它实现了 collections.abc.Mapping 接口
# 因此我们可以像操作字典一样操作它
context = contextvars.copy_context()
# key 就是对应的 ContextVar 对象,value 就是设置的值
print(context[c1])  # val1
print(context[c2])  # val2
for ctx, value in context.items():
    print(ctx.get(), ctx.name, value)
    """
    val1 context_var1 val1
    val2 context_var2 val2
    """

print(len(context))  # 2
Salin selepas log masuk

除此之外,context 还有一个 run 方法:

import contextvars

c1 = contextvars.ContextVar("context_var1")
c1.set("val1")
c2 = contextvars.ContextVar("context_var2")
c2.set("val2")

context = contextvars.copy_context()

def change(val1, val2):
    c1.set(val1)
    c2.set(val2)
    print(c1.get(), context[c1])
    print(c2.get(), context[c2])

# 在 change 函数内部,重新设置值
# 然后里面打印的也是新设置的值
context.run(change, "VAL1", "VAL2")
"""
VAL1 VAL1
VAL2 VAL2
"""

print(c1.get(), context[c1])
print(c2.get(), context[c2])
"""
val1 VAL1
val2 VAL2
"""
Salin selepas log masuk

我们看到 run 方法接收一个 callable,如果在里面修改了 ContextVar 实例设置的值,那么对于 ContextVar 而言只会在函数内部生效,一旦出了函数,那么还是原来的值。但是对于 Context 而言,它是会受到影响的,即便出了函数,也是新设置的值,因为它直接把内部的字典给修改了。

小结

以上就是 contextvars 模块的用法,在多个协程之间传递数据是非常方便的,并且也是并发安全的。如果你用过 Go 的话,你应该会发现和 Go 在 1.7 版本引入的 context 模块比较相似,当然 Go 的 context 模块功能要更强大一些,除了可以传递数据之外,对多个 goroutine 的级联管理也提供了非常清蒸的解决方案。

总之对于 contextvars 而言,它传递的数据应该是多个协程之间需要共享的数据,像 cookie, session, token 之类的,比如上游接收了一个 token,然后不断地向下透传。但是不要把本应该作为函数参数的数据,也通过 contextvars 来传递,这样就有点本末倒置了。

【相关推荐:Python3视频教程

Atas ialah kandungan terperinci Cara Python menggunakan contextvars untuk mengurus pembolehubah konteks. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
2 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Repo: Cara menghidupkan semula rakan sepasukan
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Cara mendapatkan biji gergasi
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bolehkah penterjemah Python dipadam dalam sistem Linux? Bolehkah penterjemah Python dipadam dalam sistem Linux? Apr 02, 2025 am 07:00 AM

Mengenai masalah menghapuskan penterjemah python yang dilengkapi dengan sistem Linux, banyak pengagihan Linux akan memasang semula penterjemah python apabila dipasang, dan ia tidak menggunakan pengurus pakej ...

Bagaimana menyelesaikan masalah pengesanan jenis pylance penghias tersuai di Python? Bagaimana menyelesaikan masalah pengesanan jenis pylance penghias tersuai di Python? Apr 02, 2025 am 06:42 AM

Penyelesaian Masalah Pengesanan Jenis Pylance Apabila menggunakan penghias tersuai dalam pengaturcaraan python, penghias adalah alat yang berkuasa yang boleh digunakan untuk menambah baris ...

Apa yang perlu saya lakukan jika modul '__builtin__' tidak dijumpai apabila memuatkan fail acar di Python 3.6? Apa yang perlu saya lakukan jika modul '__builtin__' tidak dijumpai apabila memuatkan fail acar di Python 3.6? Apr 02, 2025 am 07:12 AM

Memuatkan Fail Pickle di Python 3.6 Kesalahan Laporan Alam Sekitar: ModulenotFoundError: Nomodulenamed ...

Adakah debian rentetan serasi dengan pelbagai pelayar Adakah debian rentetan serasi dengan pelbagai pelayar Apr 02, 2025 am 08:30 AM

"Debianstrings" bukan istilah standard, dan makna khususnya masih belum jelas. Artikel ini tidak dapat mengulas secara langsung mengenai keserasian penyemak imbasnya. Walau bagaimanapun, jika "debianstrings" merujuk kepada aplikasi web yang dijalankan pada sistem Debian, keserasian penyemak imbasnya bergantung kepada seni bina teknikal aplikasi itu sendiri. Sebilangan besar aplikasi web moden komited untuk keserasian penyemak imbas. Ini bergantung kepada standard web berikut dan menggunakan teknologi front-end yang serasi (seperti HTML, CSS, JavaScript) dan teknologi back-end (seperti PHP, Python, Node.js, dll.). Untuk memastikan bahawa aplikasi itu serasi dengan pelbagai pelayar, pemaju sering perlu menjalankan ujian silang dan menggunakan responsif

Adakah pengubahsuaian XML memerlukan pengaturcaraan? Adakah pengubahsuaian XML memerlukan pengaturcaraan? Apr 02, 2025 pm 06:51 PM

Mengubah kandungan XML memerlukan pengaturcaraan, kerana ia memerlukan penemuan tepat nod sasaran untuk menambah, memadam, mengubah suai dan menyemak. Bahasa pengaturcaraan mempunyai perpustakaan yang sepadan untuk memproses XML dan menyediakan API untuk melaksanakan operasi yang selamat, cekap dan terkawal seperti pangkalan data operasi.

Adakah kelajuan penukaran cepat apabila menukar XML ke PDF pada telefon bimbit? Adakah kelajuan penukaran cepat apabila menukar XML ke PDF pada telefon bimbit? Apr 02, 2025 pm 10:09 PM

Kelajuan XML mudah alih ke PDF bergantung kepada faktor -faktor berikut: kerumitan struktur XML. Kaedah Penukaran Konfigurasi Perkakasan Mudah Alih (Perpustakaan, Algoritma) Kaedah Pengoptimuman Kualiti Kod (Pilih perpustakaan yang cekap, mengoptimumkan algoritma, data cache, dan menggunakan pelbagai threading). Secara keseluruhannya, tidak ada jawapan mutlak dan ia perlu dioptimumkan mengikut keadaan tertentu.

Cara mengubahsuai kandungan komen dalam XML Cara mengubahsuai kandungan komen dalam XML Apr 02, 2025 pm 06:15 PM

Untuk fail XML kecil, anda boleh menggantikan kandungan anotasi secara langsung dengan editor teks; Untuk fail besar, adalah disyorkan untuk menggunakan parser XML untuk mengubahnya untuk memastikan kecekapan dan ketepatan. Berhati -hati apabila memadam komen XML, menyimpan komen biasanya membantu pemahaman dan penyelenggaraan kod. Petua Lanjutan menyediakan kod sampel Python untuk mengubahsuai komen menggunakan parser XML, tetapi pelaksanaan khusus perlu diselaraskan mengikut perpustakaan XML yang digunakan. Beri perhatian kepada isu pengekodan semasa mengubah suai fail XML. Adalah disyorkan untuk menggunakan pengekodan UTF-8 dan menentukan format pengekodan.

Adakah terdapat aplikasi mudah alih yang boleh menukar XML ke PDF? Adakah terdapat aplikasi mudah alih yang boleh menukar XML ke PDF? Apr 02, 2025 pm 08:54 PM

Permohonan yang menukarkan XML terus ke PDF tidak dapat dijumpai kerana mereka adalah dua format yang berbeza. XML digunakan untuk menyimpan data, manakala PDF digunakan untuk memaparkan dokumen. Untuk melengkapkan transformasi, anda boleh menggunakan bahasa pengaturcaraan dan perpustakaan seperti Python dan ReportLab untuk menghuraikan data XML dan menghasilkan dokumen PDF.

See all articles