ctypes
— Ett bibliotek med främmande funktioner för Python¶
Källkod: Lib/ctypes
ctypes
är ett bibliotek med främmande funktioner för Python. Det tillhandahåller C-kompatibla datatyper och gör det möjligt att anropa funktioner i DLL:er eller delade bibliotek. Det kan användas för att paketera dessa bibliotek i ren Python.
ctypes handledning¶
Observera: I kodproverna i den här handledningen används doctest
för att säkerställa att de faktiskt fungerar. Eftersom vissa kodprover beter sig olika under Linux, Windows eller macOS innehåller de doctest-direktiv i kommentarerna.
Observera: I vissa kodexempel hänvisas till typen ctypes c_int
. På plattformar där sizeof(long) == sizeof(int)
är det ett alias till c_long
. Så du bör inte bli förvirrad om c_long
skrivs ut när du förväntar dig c_int
— de är faktiskt samma typ.
Ladda dynamiska länkbibliotek¶
ctypes
exporterar objekten cdll, och i Windows windll och oledll, för laddning av dynamiska länkbibliotek.
Du laddar bibliotek genom att komma åt dem som attribut till dessa objekt. cdll laddar bibliotek som exporterar funktioner med hjälp av standardkonventionen cdecl
, medan windll-bibliotek anropar funktioner med hjälp av konventionen stdcall
. oledll använder också anropskonventionen stdcall
och antar att funktionerna returnerar en Windows HRESULT
-felkod. Felkoden används för att automatiskt skapa ett OSError
-undantag när funktionsanropet misslyckas.
Ändrad i version 3.3: Windows-fel gav tidigare upphov till WindowsError
, som nu är ett alias för OSError
.
Här är några exempel för Windows. Observera att msvcrt
är MS standard C-bibliotek som innehåller de flesta standard C-funktioner och använder cdecl
anropskonventionen:
>>> from ctypes import *
>>> print(windll.kernel32)
<WinDLL 'kernel32', handle ... at ...>
>>> print(cdll.msvcrt)
<CDLL 'msvcrt', handle ... at ...>
>>> libc = cdll.msvcrt
>>>
Windows lägger till det vanliga filsuffixet .dll
automatiskt.
Anteckning
Om du använder standard C-biblioteket via cdll.msvcrt
kommer du att använda en föråldrad version av biblioteket som kan vara inkompatibel med den som används av Python. Där det är möjligt, använd Pythons inbyggda funktionalitet, eller importera och använd modulen msvcrt
.
Under Linux måste filnamnet inklusive tillägget anges för att ladda ett bibliotek, så attributåtkomst kan inte användas för att ladda bibliotek. Antingen bör metoden LoadLibrary()
i dll-laddarna användas, eller så bör du ladda biblioteket genom att skapa en instans av CDLL genom att anropa konstruktören:
>>> cdll.LoadLibrary("libc.so.6")
<CDLL 'libc.so.6', handle ... at ...>
>>> libc = CDLL("libc.so.6")
>>> libc
<CDLL 'libc.so.6', handle ... at ...>
>>>
Åtkomst till funktioner från inlästa dll-filer¶
Funktioner är åtkomliga som attribut till dll-objekt:
>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 239, in __getattr__
func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>
Observera att Win32-systemdLL:er som kernel32
och user32
ofta exporterar både ANSI- och UNICODE-versioner av en funktion. UNICODE-versionen exporteras med W
som tillägg till namnet, medan ANSI-versionen exporteras med A
som tillägg till namnet. Win32-funktionen GetModuleHandle
, som returnerar ett modulhandtag för ett givet modulnamn, har följande C-prototyp, och ett makro används för att exponera en av dem som GetModuleHandle
beroende på om UNICODE är definierat eller inte:
/* ANSI-version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE-version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);
windll försöker inte välja en av dem med magi, du måste komma åt den version du behöver genom att ange GetModuleHandleA
eller GetModuleHandleW
uttryckligen, och sedan anropa den med bytes- respektive strängobjekt.
Ibland exporterar dll-filer funktioner med namn som inte är giltiga Python-identifierare, som "??2@YAPAXI@Z"
. I det här fallet måste du använda getattr()
för att hämta funktionen:
>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
<_FuncPtr object at 0x...>
>>>
I Windows exporterar vissa dll-filer funktioner inte efter namn utan efter ordinal. Dessa funktioner kan nås genom att indexera dll-objektet med ordinalnumret:
>>> cdll.kernel32[1]
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ctypes.py", line 310, in __getitem__
func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>
Anropsfunktioner¶
Du kan anropa dessa funktioner som alla andra Python-anropbara funktioner. I det här exemplet används funktionen rand()
, som inte tar några argument och returnerar ett pseudoslumpmässigt heltal:
>>> print(libc.rand())
1804289383
I Windows kan du anropa funktionen GetModuleHandleA()
, som returnerar ett win32-modulhandtag (genom att ange None
som enda argument kan du anropa den med en NULL
-pekare):
>>> print(hex(windll.kernel32.GetModuleHandleA(None)))
0x1d000000
>>>
ValueError
uppstår när du anropar en stdcall
-funktion med anropskonventionen cdecl
, eller vice versa:
>>> cdll.kernel32.GetModuleHandleA(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
>>>
>>> windll.msvcrt.printf(b"spam")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
>>>
För att ta reda på den korrekta anropskonventionen måste du titta i C-headerfilen eller dokumentationen för den funktion du vill anropa.
I Windows använder ctypes
win32-strukturerad undantagshantering för att förhindra krascher på grund av generella skyddsfel när funktioner anropas med ogiltiga argumentvärden:
>>> windll.kernel32.GetModuleHandleA(32)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000020
>>>
Det finns dock tillräckligt många sätt att krascha Python med ctypes
, så du bör vara försiktig ändå. Modulen faulthandler
kan vara till hjälp vid felsökning av krascher (t.ex. från segmenteringsfel som orsakas av felaktiga anrop till C-biblioteket).
None
, heltal, bytesobjekt och (unicode) strängar är de enda Python-objekt som direkt kan användas som parametrar i dessa funktionsanrop. None
skickas som en C NULL
pekare, bytesobjekt och strängar skickas som pekare till minnesblocket som innehåller deras data (char* eller wchar_t*). Python heltal skickas som plattformens standard C int-typ, deras värde maskeras för att passa in i C-typen.
Innan vi går vidare med att anropa funktioner med andra parametertyper måste vi lära oss mer om datatyperna ctypes
.
Grundläggande datatyper¶
ctypes
definierar ett antal primitiva C-kompatibla datatyper:
ctypes typ |
C-typ |
Python-typ |
---|---|---|
_Bool |
bool (1) |
|
char |
1-teckens byte-objekt |
|
|
1-teckens sträng |
|
char |
int |
|
unsigned char |
int |
|
short |
int |
|
unsigned short |
int |
|
int |
int |
|
|
int |
|
|
int |
|
|
int |
|
|
int |
|
unsigned int |
int |
|
|
int |
|
|
int |
|
|
int |
|
|
int |
|
long |
int |
|
unsigned long |
int |
|
__int64 eller long long |
int |
|
unsigned __int64 eller unsigned long long |
int |
|
|
int |
|
|
int |
|
|
int |
|
float |
flyt |
|
double |
flyt |
|
long double |
flyt |
|
char* (NUL-terminerad) |
bytes objekt eller |
|
wchar_t* (NUL-terminerad) |
sträng eller |
|
void* |
int eller |
Konstruktören accepterar alla objekt med ett sanningsvärde.
Dessutom, om IEC 60559-kompatibel komplex aritmetik (bilaga G) stöds i både C och libffi
, är följande komplexa typer tillgängliga:
ctypes typ |
C-typ |
Python-typ |
---|---|---|
float complex |
komplex |
|
double complex |
komplex |
|
long double complex |
komplex |
Alla dessa typer kan skapas genom att anropa dem med en valfri initialiserare av rätt typ och värde:
>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p(140018365411392)
>>> c_ushort(-3)
c_ushort(65533)
>>>
Eftersom dessa typer är mutabla kan deras värde också ändras i efterhand:
>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99
>>>
Genom att tilldela ett nytt värde till instanser av pekartyperna c_char_p
, c_wchar_p
och c_void_p
ändras den minnesplats de pekar på, inte innehållet i minnesblocket (naturligtvis inte, eftersom Pythons strängobjekt är oföränderliga):
>>> s = "Hello, World"
>>> c_s = c_wchar_p(s)
>>> print(c_s)
c_wchar_p(139966785747344)
>>> print(c_s.value)
Hello World
>>> c_s.value = "Hi, there"
>>> print(c_s) # the memory location has changed
c_wchar_p(139966783348904)
>>> print(c_s.value)
Hi, there
>>> print(s) # first object is unchanged
Hello, World
>>>
Du bör dock vara försiktig så att du inte skickar dem till funktioner som förväntar sig pekare till föränderligt minne. Om du behöver föränderliga minnesblock har ctypes en create_string_buffer()
-funktion som skapar dessa på olika sätt. Det aktuella innehållet i minnesblocket kan nås (eller ändras) med egenskapen raw
; om du vill komma åt det som en NUL-avslutad sträng, använd egenskapen value
:
>>> from ctypes import *
>>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes
>>> print(sizeof(p), repr(p.raw))
3 b'\x00\x00\x00'
>>> p = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated string
>>> print(sizeof(p), repr(p.raw))
6 b'Hello\x00'
>>> print(repr(p.value))
b'Hello'
>>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
>>> print(sizeof(p), repr(p.raw))
10 b'Hello\x00\x00\x00\x00\x00'
>>> p.value = b"Hi"
>>> print(sizeof(p), repr(p.raw))
10 b'Hi\x00lo\x00\x00\x00\x00\x00'
>>>
Funktionen create_string_buffer()
ersätter den gamla funktionen c_buffer()
(som fortfarande är tillgänglig som alias). För att skapa ett föränderligt minnesblock som innehåller unicode-tecken av C-typen wchar_t
, använd funktionen create_unicode_buffer()
.
Anropsfunktioner, fortsättning¶
Observera att printf skriver ut till den riktiga standardutdatakanalen, inte till sys.stdout
, så dessa exempel fungerar bara vid konsolprompten, inte från IDLE eller PythonWin:
>>> printf = libc.printf
>>> printf(b"Hello, %s\n", b"World!")
Hello, World!
14
>>> printf(b"Hello, %S\n", "World!")
Hello, World!
14
>>> printf(b"%d bottles of beer\n", 42)
42 bottles of beer
19
>>> printf(b"%f bottles of beer\n", 42.5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 2: TypeError: Don't know how to convert parameter 2
>>>
Som tidigare nämnts måste alla Python-typer utom heltal, strängar och bytesobjekt förpackas i sin motsvarande ctypes
-typ, så att de kan konverteras till den nödvändiga C-datatypen:
>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
An int 1234, a double 3.140000
31
>>>
Anrop av variadiska funktioner¶
På många plattformar är det exakt samma sak att anropa variadiska funktioner via ctypes som att anropa funktioner med ett fast antal parametrar. På vissa plattformar, och i synnerhet ARM64 för Apple-plattformar, är anropskonventionen för variadiska funktioner annorlunda än för vanliga funktioner.
På dessa plattformar är det nödvändigt att ange attributet argtypes
för de vanliga, icke-variadiska, funktionsargumenten:
libc.printf.argtypes = [ctypes.c_char_p]
Eftersom angivandet av attributet inte hindrar portabilitet rekommenderas att alltid ange argtypes
för alla variadiska funktioner.
Anropa funktioner med dina egna anpassade datatyper¶
Du kan också anpassa ctypes
argumentkonvertering så att instanser av dina egna klasser kan användas som funktionsargument. ctypes
letar efter ett _as_parameter_
-attribut och använder detta som funktionsargument. Attributet måste vara ett heltal, en sträng, bytes, en ctypes
-instans eller ett objekt med ett _as_parameter_
-attribut:
>>> class Bottles:
... def __init__(self, number):
... self._as_parameter_ = number
...
>>> bottles = Bottles(42)
>>> printf(b"%d bottles of beer\n", bottles)
42 bottles of beer
19
>>>
Om du inte vill lagra instansens data i instansvariabeln _as_parameter_
kan du definiera en property
som gör attributet tillgängligt på begäran.
Ange de nödvändiga argumenttyperna (funktionsprototyper)¶
Det är möjligt att ange vilka argumenttyper som krävs för funktioner som exporteras från DLL:er genom att ange attributet argtypes
.
argtypes
måste vara en sekvens av C-datatyper (funktionen printf()
är förmodligen inte ett bra exempel här, eftersom den tar ett variabelt antal och olika typer av parametrar beroende på formatsträngen, å andra sidan är det ganska praktiskt att experimentera med den här funktionen):
>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
>>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)
String 'Hi', Int 10, Double 2.200000
37
>>>
Genom att ange ett format skyddar man sig mot inkompatibla argumenttyper (precis som en prototyp för en C-funktion) och försöker konvertera argumenten till giltiga typer:
>>> printf(b"%d %d %d", 1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 2: TypeError: 'int' object cannot be interpreted as ctypes.c_char_p
>>> printf(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>
Om du har definierat dina egna klasser som du skickar till funktionsanrop, måste du implementera en from_param()
klassmetod för att de ska kunna använda dem i argtypes
sekvensen. Klassmetoden from_param()
tar emot Python-objektet som skickas till funktionsanropet, den bör göra en typkontroll eller vad som behövs för att se till att detta objekt är acceptabelt och sedan returnera själva objektet, dess _as_parameter_
-attribut eller vad du vill skicka som C-funktionsargument i det här fallet. Återigen bör resultatet vara ett heltal, en sträng, bytes, en ctypes
-instans eller ett objekt med ett _as_parameter_
-attribut.
Typer av avkastning¶
Som standard antas funktioner returnera C int-typen. Andra returtyper kan anges genom att ställa in attributet restype
för funktionsobjektet.
C-prototypen för time()
är time_t time(time_t *)
. Eftersom time_t
kan vara av en annan typ än standardreturtypen int, bör du ange attributet restype
:
>>> libc.time.restype = c_time_t
Argumenttyperna kan anges med hjälp av argtypes
:
>>> libc.time.argtypes = (POINTER(c_time_t),)
För att anropa funktionen med en NULL
-pekare som första argument, använd None
:
>>> print(libc.time(None))
1150640792
Här är ett mer avancerat exempel, det använder funktionen strchr()
, som förväntar sig en strängpekare och en char, och returnerar en pekare till en sträng:
>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))
8059983
>>> strchr.restype = c_char_p # c_char_p is a pointer to a string
>>> strchr(b"abcdef", ord("d"))
b'def'
>>> print(strchr(b"abcdef", ord("x")))
None
>>>
Om du vill undvika ord("x")
-anropen ovan kan du ställa in attributet argtypes
, och det andra argumentet konverteras från ett Python bytes-objekt med ett tecken till ett C char:
>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
b'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
ctypes.ArgumentError: argument 2: TypeError: one character bytes, bytearray or integer expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
b'def'
>>>
Du kan också använda ett anropbart Python-objekt (t.ex. en funktion eller en klass) som attributet restype
, om den utländska funktionen returnerar ett heltal. Det anropbara objektet kommer att anropas med det integer som C-funktionen returnerar, och resultatet av detta anrop kommer att användas som resultatet av ditt funktionsanrop. Detta är användbart för att kontrollera felaktiga returvärden och automatiskt skapa ett undantag:
>>> GetModuleHandle = windll.kernel32.GetModuleHandleA
>>> def ValidHandle(value):
... if value == 0:
... raise WinError()
... return value
...
>>>
>>> GetModuleHandle.restype = ValidHandle
>>> GetModuleHandle(None)
486539264
>>> GetModuleHandle("something silly")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in ValidHandle
OSError: [Errno 126] The specified module could not be found.
>>>
WinError
är en funktion som anropar Windows FormatMessage()
api för att få strängrepresentationen av en felkod, och returnerar ett undantag. WinError
tar en valfri felkodsparameter, om ingen används anropar den GetLastError()
för att hämta den.
Observera att en mycket kraftfullare felkontrollmekanism är tillgänglig via attributet errcheck
; se referenshandboken för mer information.
Passera pekare (eller: passera parametrar genom referens)¶
Ibland förväntar sig en C api-funktion en pekare till en datatyp som parameter, förmodligen för att skriva till motsvarande plats, eller om data är för stora för att skickas med värde. Detta kallas också att överföra parametrar genom referens.
ctypes
exporterar funktionen byref()
som används för att skicka parametrar som referenser. Samma effekt kan uppnås med funktionen pointer()
, även om pointer()
gör mycket mer arbete eftersom den konstruerar ett riktigt pekarobjekt, så det är snabbare att använda byref()
om du inte behöver pekarobjektet i Python själv:
>>> i = c_int()
>>> f = c_float()
>>> s = create_string_buffer(b'\000' * 32)
>>> print(i.value, f.value, repr(s.value))
0 0.0 b''
>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",
... byref(i), byref(f), s)
3
>>> print(i.value, f.value, repr(s.value))
1 3.1400001049 b'Hello'
>>>
Strukturer och fackföreningar¶
Strukturer och unioner måste härledas från basklasserna Structure
och Union
som definieras i modulen ctypes
. Varje underklass måste definiera ett attribut _fields_
. _fields_
måste vara en lista med 2-tuples, innehållande ett fältsnamn och en fältstyp.
Fälttypen måste vara en ctypes
-typ som c_int
, eller någon annan härledd ctypes
-typ: struktur, union, array, pekare.
Här följer ett enkelt exempel på en POINT-struktur, som innehåller två heltal med namnen x och y, och som också visar hur man initialiserar en struktur i konstruktorn:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = [("x", c_int),
... ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print(point.x, point.y)
10 20
>>> point = POINT(y=5)
>>> print(point.x, point.y)
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: too many initializers
>>>
Det går dock att bygga mycket mer komplicerade strukturer. En struktur kan i sig innehålla andra strukturer genom att använda en struktur som fälttyp.
Här är en RECT-struktur som innehåller två POINTs med namnen upperleft och lowerright:
>>> class RECT(Structure):
... _fields_ = [("upperleft", POINT),
... ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print(rc.upperleft.x, rc.upperleft.y)
0 5
>>> print(rc.lowerright.x, rc.lowerright.y)
0 0
>>>
Nästlade strukturer kan också initialiseras i konstruktorn på flera sätt:
>>> r = RECT(POINT(1, 2), POINT(3, 4))
>>> r = RECT((1, 2), (3, 4))
Field descriptors kan hämtas från class, de är användbara för felsökning eftersom de kan ge användbar information. Se CField
:
>>> POINT.x
<ctypes.CField 'x' type=c_int, ofs=0, size=4>
>>> POINT.y
<ctypes.CField 'y' type=c_int, ofs=4, size=4>
>>>
Varning
ctypes
har inte stöd för att skicka unioner eller strukturer med bitfält till funktioner med värde. Även om detta kan fungera på 32-bitars x86, garanteras det inte av biblioteket att det fungerar i det allmänna fallet. Unioner och strukturer med bitfält bör alltid skickas till funktioner med pekare.
Struktur/unionens layout, inriktning och byteordning¶
Som standard är Structure- och Union-fälten utformade på samma sätt som C-kompilatorn gör det. Det är möjligt att helt åsidosätta detta beteende genom att ange ett _layout_
-klassattribut i underklassdefinitionen; se attributdokumentationen för detaljer.
Det är möjligt att ange den maximala inriktningen för fälten genom att ställa in klassattributet _pack_
till ett positivt heltal. Detta matchar vad #pragma pack(n)
gör i MSVC.
Det är också möjligt att ange en minsta inriktning för hur själva subklassen ska packas på samma sätt som #pragma align(n)
fungerar i MSVC. Detta kan uppnås genom att ange ett _align_
klassattribut i underklassdefinitionen.
ctypes
använder den ursprungliga byteordningen för strukturer och unioner. Om du vill bygga strukturer med en annan byteordning kan du använda någon av basklasserna BigEndianStructure
, LittleEndianStructure
, BigEndianUnion
och LittleEndianUnion
. Dessa klasser kan inte innehålla pekarfält.
Bitfält i strukturer och fackföreningar¶
Det är möjligt att skapa strukturer och unioner som innehåller bitfält. Bitfält är endast möjliga för heltalsfält, bitbredden anges som det tredje objektet i _fields_
-tuplerna:
>>> class Int(Structure):
... _fields_ = [("first_16", c_int, 16),
... ("second_16", c_int, 16)]
...
>>> print(Int.first_16)
<ctypes.CField 'first_16' type=c_int, ofs=0, bit_size=16, bit_offset=0>
>>> print(Int.second_16)
<ctypes.CField 'second_16' type=c_int, ofs=0, bit_size=16, bit_offset=16>
Det är viktigt att notera att allokering av bitfält och layout i minnet inte definieras som en C-standard; implementeringen av dem är kompilatorspecifik. Som standard kommer Python att försöka matcha beteendet hos en ”native”-kompilator för den aktuella plattformen. Se attributet _layout_
för detaljer om standardbeteendet och hur man ändrar det.
Arrayer¶
Arrayer är sekvenser som innehåller ett fast antal instanser av samma typ.
Det rekommenderade sättet att skapa array-typer är genom att multiplicera en datatyp med ett positivt heltal:
TenPointsArrayType = PUNKT * 10
Här är ett exempel på en något artificiell datatyp, en struktur som bland annat innehåller 4 POINTs:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = ("x", c_int), ("y", c_int)
...
>>> class MyStruct(Structure):
... _fields_ = [("a", c_int),
... ("b", c_float),
... ("point_array", POINT * 4)]
>>>
>>> print(len(MyStruct().point_array))
4
>>>
Instanser skapas på vanligt sätt, genom att anropa class:
arr = TenPointsArrayType()
för pt i arr:
print(pt.x, pt.y)
Ovanstående kod skriver ut en serie 0 0
rader, eftersom matrisens innehåll är initialiserat till nollor.
Initialiserare av rätt typ kan också anges:
>>> from ctypes import *
>>> TenIntegers = c_int * 10
>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> print(ii)
<c_long_Array_10 object at 0x...>
>>> for i in ii: print(i, end=" ")
...
1 2 3 4 5 6 7 8 9 10
>>>
Pekare¶
Pekarinstanser skapas genom att anropa funktionen pointer()
på en ctypes
-typ:
>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>>
Pekarinstanser har ett contents
-attribut som returnerar det objekt som pekaren pekar på, i
-objektet ovan:
>>> pi.contents
c_long(42)
>>>
Observera att ctypes
inte har OOR (original object return), utan konstruerar ett nytt, likvärdigt objekt varje gång du hämtar ett attribut:
>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
>>>
Om du tilldelar en annan c_int
-instans till pekarens innehållsattribut skulle pekaren peka på den minnesplats där detta är lagrat:
>>> i = c_int(99)
>>> pi.contents = i
>>> pi.contents
c_long(99)
>>>
Pekarinstanser kan också indexeras med heltal:
>>> pi[0]
99
>>>
Genom att tilldela ett heltalsindex ändras det pekade till värdet:
>>> print(i)
c_long(99)
>>> pi[0] = 22
>>> print(i)
c_long(22)
>>>
Det är också möjligt att använda index som skiljer sig från 0, men du måste veta vad du gör, precis som i C: Du kan komma åt eller ändra godtyckliga minnesplatser. I allmänhet använder du bara den här funktionen om du får en pekare från en C-funktion och du vet att pekaren faktiskt pekar på en array i stället för på ett enda objekt.
Bakom kulisserna gör funktionen pointer()
mer än att bara skapa pekarinstanser, den måste först skapa pekar*typer*. Detta görs med funktionen POINTER()
, som accepterar vilken typ som helst av ctypes
och returnerar en ny typ:
>>> PI = POINTER(c_int)
>>> PI
<class 'ctypes.LP_c_long'>
>>> PI(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected c_long instead of int
>>> PI(c_int(42))
<ctypes.LP_c_long object at 0x...>
>>>
Anrop av pekartypen utan ett argument skapar en NULL
-pekare. NULL
pekare har ett False
boolean värde:
>>> null_ptr = POINTER(c_int)()
>>> print(bool(null_ptr))
False
>>>
ctypes
kontrollerar för NULL
vid dereferencing av pekare (men dereferencing av ogiltiga icke NULL
pekare skulle krascha Python):
>>> null_ptr[0]
Traceback (most recent call last):
....
ValueError: NULL pointer access
>>>
>>> null_ptr[0] = 1234
Traceback (most recent call last):
....
ValueError: NULL pointer access
>>>
Trådsäkerhet utan GIL¶
Från Python 3.13 och framåt kan GIL inaktiveras på free threaded-byggnationer. I ctypes är samtidiga läsningar och skrivningar till ett enda objekt säkra, men inte över flera objekt:
>>> number = c_int(42) >>> pointer_a = pointer(number) >>> pointer_b = pointer(number)
I ovanstående exempel är det bara säkert för ett objekt att läsa och skriva till adressen samtidigt om GIL är inaktiverat. Så, pointer_a
kan delas och skrivas till över flera trådar, men bara om pointer_b
inte också försöker göra detsamma. Om detta är ett problem kan du överväga att använda en threading.Lock
för att synkronisera åtkomst till minnet:
>>> import threading >>> lock = threading.Lock() >>> # Thread 1 >>> with lock: ... pointer_a.contents = 24 >>> # Thread 2 >>> with lock: ... pointer_b.contents = 42
Typkonverteringar¶
Vanligtvis gör ctypes en strikt typkontroll. Detta innebär att om du har POINTER(c_int)
i argtypes
-listan för en funktion eller som typ för ett medlemsfält i en strukturdefinition, accepteras endast instanser av exakt samma typ. Det finns några undantag från denna regel, där ctypes accepterar andra objekt. Du kan t.ex. skicka kompatibla array-instanser i stället för pekartyper. Så för POINTER(c_int)
accepterar ctypes en array av c_int:
>>> class Bar(Structure):
... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
... print(bar.values[i])
...
1
2
3
>>>
Dessutom, om ett funktionsargument uttryckligen deklareras vara en pekartyp (t.ex. POINTER(c_int)
) i argtypes
, kan ett objekt av pekartypen (c_int
i detta fall) skickas till funktionen. ctypes kommer att tillämpa den nödvändiga byref()
-konverteringen i detta fall automatiskt.
För att ställa in ett fält av typen POINTER till NULL
kan du tilldela None
:
>>> bar.values = None
>>>
Ibland har man instanser av inkompatibla typer. I C kan du casta en typ till en annan typ. ctypes
tillhandahåller en cast()
-funktion som kan användas på samma sätt. Strukturen Bar
som definieras ovan accepterar POINTER(c_int)
pekare eller c_int
matriser för sitt values
fält, men inte instanser av andra typer:
>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>
I dessa fall är funktionen cast()
praktisk.
Funktionen cast()
kan användas för att casta en ctypes-instans till en pekare på en annan ctypes-datatyp. cast()
tar två parametrar, ett ctypes-objekt som är eller kan konverteras till en pekare av något slag och en ctypes-pekartyp. Den returnerar en instans av det andra argumentet, som refererar till samma minnesblock som det första argumentet:
>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>
Så cast()
kan användas för att tilldela fältet values
i Bar
strukturen:
>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>
Ofullständiga typer¶
Ofullständiga typer är strukturer, unioner eller matriser vars medlemmar ännu inte har specificerats. I C specificeras de genom forward-deklarationer, som definieras senare:
struct cell; /* framåtdeklaration */
struct cell {
char *namn;
strukturcell *nästa;
};
Den raka översättningen till ctypes-kod skulle vara denna, men det fungerar inte:
>>> class cell(Structure):
... _fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in cell
NameError: name 'cell' is not defined
>>>
eftersom den nya class cell
inte är tillgänglig i själva klassuttalandet. I ctypes
kan vi definiera klassen cell
och ställa in attributet _fields_
senare, efter klassuttalandet:
>>> from ctypes import *
>>> class cell(Structure):
... pass
...
>>> cell._fields_ = [("name", c_char_p),
... ("next", POINTER(cell))]
>>>
Låt oss prova det. Vi skapar två instanser av cell
, och låter dem peka på varandra, och följer slutligen pekarkedjan några gånger:
>>> c1 = cell()
>>> c1.name = b"foo"
>>> c2 = cell()
>>> c2.name = b"bar"
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
... print(p.name, end=" ")
... p = p.next[0]
...
foo bar foo bar foo bar foo bar
>>>
Återkallelsefunktioner¶
ctypes
gör det möjligt att skapa C-kallbara funktionspoängare från Python-kallbara funktioner. Dessa kallas ibland för callback-funktioner.
Först måste du skapa en klass för återuppringningsfunktionen. Klassen känner till anropskonventionen, returtypen och antalet och typerna av argument som denna funktion kommer att ta emot.
Fabriksfunktionen CFUNCTYPE()
skapar typer för återuppringningsfunktioner med hjälp av anropskonventionen cdecl
. I Windows skapar fabriksfunktionen WINFUNCTYPE()
typer för återkallningsfunktioner med hjälp av anropskonventionen stdcall
.
Båda dessa fabriksfunktioner anropas med resultattypen som första argument, och callback-funktionernas förväntade argumenttyper som resterande argument.
Jag kommer här att presentera ett exempel som använder standard C-bibliotekets qsort()
-funktion, som används för att sortera objekt med hjälp av en callback-funktion. qsort()
kommer att användas för att sortera en array av heltal:
>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)
>>> qsort = libc.qsort
>>> qsort.restype = None
>>>
qsort()
måste anropas med en pekare till de data som skall sorteras, antalet objekt i dataarrayen, storleken på ett objekt och en pekare till jämförelsefunktionen, callback. Callbacken anropas sedan med två pekare till objekt och måste returnera ett negativt heltal om det första objektet är mindre än det andra, en nolla om de är lika stora och ett positivt heltal annars.
Så vår callback-funktion tar emot pekare till heltal och måste returnera ett heltal. Först skapar vi typ
för callback-funktionen:
>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
>>>
För att komma igång, här är en enkel callback som visar de värden den får skickade till sig:
>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return 0
...
>>> cmp_func = CMPFUNC(py_cmp_func)
>>>
Resultatet:
>>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 5 7
py_cmp_func 1 7
>>>
Nu kan vi faktiskt jämföra de två objekten och returnera ett användbart resultat:
>>> def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return a[0] - b[0]
...
>>>
>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>
Som vi lätt kan kontrollera är vår matris nu sorterad:
>>> for i in ia: print(i, end=" ")
...
1 5 7 33 99
>>>
Funktionsfabrikerna kan användas som dekoratorfabriker, så vi kan lika gärna skriva:
>>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
... def py_cmp_func(a, b):
... print("py_cmp_func", a[0], b[0])
... return a[0] - b[0]
...
>>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>
Anteckning
Se till att du behåller referenser till CFUNCTYPE()
-objekt så länge som de används från C-kod. ctypes
gör inte det, och om du inte gör det kan de bli garbage collected, vilket kraschar ditt program när en callback görs.
Observera också att om återuppringningsfunktionen anropas i en tråd som skapats utanför Pythons kontroll (t.ex. av den utländska kod som anropar återuppringningen), skapar ctypes en ny dummy Python-tråd vid varje anrop. Detta beteende är korrekt för de flesta ändamål, men det innebär att värden som lagras med threading.local
inte kommer att överleva mellan olika anrop, även när dessa anrop görs från samma C-tråd.
Tillgång till värden exporterade från dll-filer¶
Vissa delade bibliotek exporterar inte bara funktioner, utan även variabler. Ett exempel i själva Python-biblioteket är Py_Version
, Pythons versionsnummer för runtime kodat i ett enda konstant heltal.
ctypes
kan komma åt värden som detta med in_dll()
klassmetoderna för typen. pythonapi är en fördefinierad symbol som ger tillgång till Python C api:
>>> version = ctypes.c_int.in_dll(ctypes.pythonapi, "Py_Version")
>>> print(hex(version.value))
0x30c00a0
Ett utökat exempel som också demonstrerar användningen av pekare kommer åt PyImport_FrozenModules
-pekaren som exporteras av Python.
Citerar dokumenten för det värdet:
Denna pekare initialiseras så att den pekar på en array av
_frozen
-poster, som avslutas med en post vars alla medlemmar ärNULL
eller noll. När en fryst modul importeras söks den i den här tabellen. Tredjepartskod kan använda detta för att skapa en dynamiskt skapad samling av frysta moduler.
Så att manipulera denna pekare kan till och med visa sig vara användbart. För att begränsa exemplets storlek visar vi bara hur denna tabell kan läsas med ctypes
:
>>> from ctypes import *
>>>
>>> class struct_frozen(Structure):
... _fields_ = [("name", c_char_p),
... ("code", POINTER(c_ubyte)),
... ("size", c_int),
... ("get_code", POINTER(c_ubyte)), # Function pointer
... ]
...
>>>
Vi har definierat datatypen _frozen
, så vi kan hämta pekaren till tabellen:
>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "_PyImport_FrozenBootstrap")
>>>
Eftersom table
är en pointer
till arrayen av struct_frozen
-poster kan vi iterera över den, men vi måste se till att vår loop avslutas, eftersom pekare inte har någon storlek. Förr eller senare skulle det troligen krascha med en åtkomstfel eller något liknande, så det är bättre att bryta loopen när vi når NULL
-posten:
>>> for item in table:
... if item.name is None:
... break
... print(item.name.decode("ascii"), item.size)
...
_frozen_importlib 31764
_frozen_importlib_external 41499
zipimport 12345
>>>
Det faktum att standard Python har en fryst modul och ett fryst paket (indikerat av den negativa medlemmen size
) är inte särskilt känt, det används endast för testning. Prova till exempel med import __hello__
.
Överraskningar¶
Det finns vissa kanter i ctypes
där man kan förvänta sig något annat än vad som faktiskt händer.
Tänk på följande exempel:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = ("x", c_int), ("y", c_int)
...
>>> class RECT(Structure):
... _fields_ = ("a", POINT), ("b", POINT)
...
>>> p1 = POINT(1, 2)
>>> p2 = POINT(3, 4)
>>> rc = RECT(p1, p2)
>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
1 2 3 4
>>> # now swap the two points
>>> rc.a, rc.b = rc.b, rc.a
>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
3 4 3 4
>>>
Hm. Vi förväntade oss verkligen att det sista uttalandet skulle skriva ut 3 4 1 2
. Vad var det som hände? Här är stegen i raden rc.a, rc.b = rc.b, rc.a
ovan:
>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
>>>
Observera att temp0
och temp1
är objekt som fortfarande använder den interna bufferten i rc
-objektet ovan. Så när du kör rc.a = temp0
kopieras buffertinnehållet i temp0
till rc
buffert. Detta ändrar i sin tur innehållet i temp1
. Så den sista uppgiften rc.b = temp1
har inte den förväntade effekten.
Tänk på att när du hämtar underobjekt från Structure, Unions och Arrays kopieras inte underobjektet, utan istället hämtas ett omslagsobjekt som har åtkomst till rotobjektets underliggande buffert.
Ett annat exempel som kan bete sig annorlunda än vad man förväntar sig är detta:
>>> s = c_char_p()
>>> s.value = b"abc def ghi"
>>> s.value
b'abc def ghi'
>>> s.value is s.value
False
>>>
Anteckning
Objekt som instansieras från c_char_p
kan bara ha sitt värde inställt på bytes eller heltal.
Varför skrivs det ut False
? ctypes-instanser är objekt som innehåller ett minnesblock plus några descriptorer som åtkomst till innehållet i minnet. Att lagra ett Python-objekt i minnesblocket lagrar inte själva objektet, utan istället lagras objektets contents
. Åtkomst till innehållet skapar varje gång ett nytt Python-objekt!
Datatyper med variabel storlek¶
ctypes
ger visst stöd för arrayer och strukturer med variabel storlek.
Funktionen resize()
kan användas för att ändra storlek på minnesbufferten för ett befintligt ctypes-objekt. Funktionen tar objektet som första argument och den begärda storleken i byte som andra argument. Minnesblocket kan inte göras mindre än det naturliga minnesblock som anges av objektets typ, ett ValueError
uppstår om detta försöker:
>>> short_array = (c_short * 4)()
>>> print(sizeof(short_array))
8
>>> resize(short_array, 4)
Traceback (most recent call last):
...
ValueError: minimum size is 8
>>> resize(short_array, 32)
>>> sizeof(short_array)
32
>>> sizeof(type(short_array))
8
>>>
Detta är bra, men hur skulle man komma åt de ytterligare element som finns i denna array? Eftersom typen fortfarande bara känner till 4 element, får vi fel vid åtkomst till andra element:
>>> short_array[:]
[0, 0, 0, 0]
>>> short_array[7]
Traceback (most recent call last):
...
IndexError: invalid index
>>>
Ett annat sätt att använda datatyper med variabel storlek med ctypes
är att använda Pythons dynamiska natur och (om)definiera datatypen efter att den önskade storleken redan är känd, från fall till fall.
ctypes referens¶
Utländska funktioner¶
Som förklarades i föregående avsnitt kan utländska funktioner nås som attribut till inlästa delade bibliotek. De funktionsobjekt som skapas på detta sätt accepterar som standard valfritt antal argument, accepterar valfria ctypes-datainstanser som argument och returnerar den standardresultattyp som anges av biblioteksladdaren.
De är instanser av en privat lokal klass _FuncPtr
(inte exponerad i ctypes
) som ärver från den privata klassen _CFuncPtr
:
>>> import ctypes
>>> lib = ctypes.CDLL(None)
>>> issubclass(lib._FuncPtr, ctypes._CFuncPtr)
True
>>> lib._FuncPtr is ctypes._CFuncPtr
False
- class ctypes._CFuncPtr¶
Basklass för C-anropsbara utländska funktioner.
Instanser av utländska funktioner är också C-kompatibla datatyper; de representerar C-funktionspoängare.
Detta beteende kan anpassas genom att tilldela speciella attribut till det utländska funktionsobjektet.
- restype¶
Tilldela en ctypes-typ för att ange resultattypen för den främmande funktionen. Använd
None
för void, en funktion som inte returnerar någonting.Det är möjligt att tilldela ett anropbart Python-objekt som inte är en ctypes-typ, i det här fallet antas funktionen returnera en C int, och den anropbara kommer att anropas med detta heltal, vilket möjliggör ytterligare bearbetning eller felkontroll. Att använda detta är föråldrat, för mer flexibel efterbehandling eller felkontroll, använd en ctypes-datatyp som
restype
och tilldela en anropbar till attributeterrcheck
.
- argtypes¶
Tilldela en tupel av ctypes-typer för att ange de argumenttyper som funktionen accepterar. Funktioner som använder anropskonventionen
stdcall
kan bara anropas med samma antal argument som längden på denna tupel; funktioner som använder anropskonventionen C accepterar även ytterligare, ospecificerade argument.När en utländsk funktion anropas skickas varje faktiskt argument till klassmetoden
from_param()
för objekten i tupelnargtypes
, denna metod gör det möjligt att anpassa det faktiska argumentet till ett objekt som den utländska funktionen accepterar. Exempelvis kommer ettc_char_p
-objekt iargtypes
-tupeln att konvertera en sträng som skickas som argument till ett bytes-objekt med hjälp av ctypes konverteringsregler.Nytt: Det är nu möjligt att lägga in objekt i argtypes som inte är ctypes-typer, men varje objekt måste ha en
from_param()
-metod som returnerar ett värde som kan användas som argument (heltal, sträng, ctypes-instans). Detta gör det möjligt att definiera adaptrar som kan anpassa anpassade objekt som funktionsparametrar.
- errcheck¶
Tilldela en Python-funktion eller en annan anropbar funktion till detta attribut. Den anropsbara funktionen kommer att anropas med tre eller fler argument:
- callable(result, func, arguments)
result är vad den främmande funktionen returnerar, enligt vad som anges av attributet
restype
.func är själva det främmande funktionsobjektet, vilket gör det möjligt att återanvända samma anropsbara objekt för att kontrollera eller efterbehandla resultaten av flera funktioner.
arguments är en tupel som innehåller de parametrar som ursprungligen skickades till funktionsanropet, vilket gör det möjligt att specialisera beteendet på de argument som används.
Det objekt som den här funktionen returnerar kommer att returneras från det utländska funktionsanropet, men den kan också kontrollera resultatvärdet och skapa ett undantag om det utländska funktionsanropet misslyckades.
I Windows, när ett främmande funktionsanrop ger upphov till ett systemundantag (t.ex. på grund av en åtkomstöverträdelse), kommer det att fångas upp och ersättas med ett lämpligt Python-undantag. Dessutom kommer en granskningshändelse ctypes.set_exception
med argumentet code
att uppstå, vilket gör det möjligt för en granskningskrok att ersätta undantaget med sitt eget.
Vissa sätt att anropa utländska funktioner samt vissa av funktionerna i denna modul kan ge upphov till en granskningshändelse ctypes.call_function
med argumenten function pointer
och arguments
.
Prototyper av funktioner¶
Utländska funktioner kan också skapas genom instansiering av funktionsprototyper. Funktionsprototyper liknar funktionsprototyper i C; de beskriver en funktion (returtyp, argumenttyper, anropskonvention) utan att definiera en implementation. Fabriksfunktionerna måste anropas med önskad resultattyp och funktionens argumenttyper och kan användas som dekoratorfabriker och som sådana tillämpas på funktioner genom syntaxen @wrapper
. Se Återkallelsefunktioner för exempel.
- ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)¶
Den returnerade funktionsprototypen skapar funktioner som använder C:s standardkonvention för anrop. Funktionen kommer att frigöra GIL under anropet. Om use_errno är satt till true, kommer ctypes privata kopia av systemvariabeln
errno
att bytas ut mot det verkliga värdet förerrno
före och efter anropet; use_last_error gör samma sak för Windows felkod.
- ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)¶
Den returnerade funktionsprototypen skapar funktioner som använder anropskonventionen
stdcall
. Funktionen kommer att frigöra GIL under anropet. use_errno och use_last_error har samma betydelse som ovan.Tillgänglighet: Windows
- ctypes.PYFUNCTYPE(restype, *argtypes)¶
Den returnerade funktionsprototypen skapar funktioner som använder Pythons anropskonvention. Funktionen kommer inte att frigöra GIL under anropet.
Funktionsprototyper som skapas av dessa fabriksfunktioner kan instansieras på olika sätt, beroende på typen och antalet parametrar i anropet:
- prototype(address)
Returnerar en utländsk funktion på den angivna adressen som måste vara ett heltal.
- prototype(callable)
Skapa en anropsbar C-funktion (en callback-funktion) från en Python callable.
- prototype(func_spec[, paramflags])
Returnerar en utländsk funktion som exporteras av ett delat bibliotek. func_spec måste vara en 2-tupel
(name_or_ordinal, library)
. Det första elementet är namnet på den exporterade funktionen som en sträng, eller den exporterade funktionens ordinal som ett litet heltal. Det andra elementet är den delade biblioteksinstansen.
- prototype(vtbl_index, name[, paramflags[, iid]])
Returnerar en utländsk funktion som anropar en COM-metod. vtbl_index är index i den virtuella funktionstabellen, ett litet icke-negativt heltal. name är namnet på COM-metoden. iid är en valfri pekare till gränssnittsidentifieraren som används vid utökad felrapportering.
Om iid inte specificeras, genereras ett
OSError
om COM-metodanropet misslyckas. Om iid specificeras, genereras istället ettCOMError
.COM-metoder använder en speciell anropskonvention: De kräver en pekare till COM-gränssnittet som första argument, utöver de parametrar som anges i
argtypes
-tupeln.Tillgänglighet: Windows
Den valfria parametern paramflags skapar omslag för utländska funktioner med mycket mer funktionalitet än de funktioner som beskrivs ovan.
paramflags måste vara en tupel av samma längd som argtypes
.
Varje objekt i denna tupel innehåller ytterligare information om en parameter, det måste vara en tupel som innehåller ett, två eller tre objekt.
Den första posten är ett heltal som innehåller en kombination av riktningsflaggor för parametern:
- 1
Anger en inparameter till funktionen.
- 2
Parameter för utdata. Den utländska funktionen fyller i ett värde.
- 4
Inmatningsparameter som som standard är heltalet noll.
Den andra valfria posten är parameternamnet som en sträng. Om detta anges kan den utländska funktionen anropas med namngivna parametrar.
Den valfria tredje posten är standardvärdet för denna parameter.
Följande exempel visar hur man slår in Windows MessageBoxW
-funktionen så att den stöder standardparametrar och namngivna argument. C-deklarationen från Windows header-fil är denna:
WINUSERAPI int WINAPI
MessageBoxW(
HWND hWnd,
LPCWSTR lpText,
LPCWSTR lpCaption,
UINT uType);
Här är förpackningen med ctypes
:
>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCWSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)
Den utländska funktionen MessageBox
kan nu anropas på följande sätt:
>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")
Ett andra exempel demonstrerar utdataparametrar. Win32-funktionen GetWindowRect
hämtar dimensionerna för ett angivet fönster genom att kopiera dem till RECT
-strukturen som anroparen måste tillhandahålla. Här är C-deklarationen:
WINUSERAPI BOOL WINAPI
GetWindowRect(
HWND hWnd,
LPRECT lpRect);
Här är förpackningen med ctypes
:
>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
>>> from ctypes.wintypes import BOOL, HWND, RECT
>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
>>> paramflags = (1, "hwnd"), (2, "lprect")
>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
>>>
Funktioner med utparametrar returnerar automatiskt utparametervärdet om det finns ett enda, eller en tupel som innehåller utparametervärdena om det finns fler än ett, så funktionen GetWindowRect returnerar nu en RECT-instans när den anropas.
Utdataparametrar kan kombineras med errcheck
-protokollet för att göra ytterligare utdatabehandling och felkontroll. Win32 GetWindowRect
api-funktionen returnerar en BOOL
för att signalera framgång eller misslyckande, så den här funktionen kan göra felkontrollen och ger upphov till ett undantag när api-anropet misslyckades:
>>> def errcheck(result, func, args):
... if not result:
... raise WinError()
... return args
...
>>> GetWindowRect.errcheck = errcheck
>>>
Om funktionen errcheck
returnerar den argumenttupel som den tar emot oförändrad, fortsätter ctypes
med den normala bearbetning som den gör på utdataparametrarna. Om du vill returnera en tupel av fönsterkoordinater istället för en RECT
-instans, kan du hämta fälten i funktionen och returnera dem istället, den normala bearbetningen kommer inte längre att äga rum:
>>> def errcheck(result, func, args):
... if not result:
... raise WinError()
... rc = args[1]
... return rc.left, rc.top, rc.bottom, rc.right
...
>>> GetWindowRect.errcheck = errcheck
>>>
Verktygsfunktioner¶
- ctypes.addressof(obj)¶
Returnerar minnesbuffertens adress som heltal. obj måste vara en instans av en ctypes-typ.
Utlöser en auditing event
ctypes.addressof
med argumentetobj
.
- ctypes.alignment(obj_or_type)¶
Returnerar anpassningskraven för en ctypes-typ. obj_or_type måste vara en ctypes-typ eller -instans.
- ctypes.byref(obj[, offset])¶
Returnerar en lättviktspekare till obj, som måste vara en instans av en ctypes-typ. offset är som standard noll och måste vara ett heltal som läggs till det interna pekarvärdet.
byref(obj, offset)
motsvarar denna C-kod:(((char *)&obj) + offset)
Det returnerade objektet kan endast användas som en parameter i ett främmande funktionsanrop. Det fungerar på samma sätt som
pointer(obj)
, men konstruktionen är mycket snabbare.
- ctypes.CopyComPointer(src, dst)¶
Kopierar en COM-pekare från src till dst och returnerar det Windows-specifika
HRESULT
-värdet.Om src inte är
NULL
anropas dess metodAddRef
, vilket ökar referensantalet.Däremot kommer referensantalet för dst inte att decimeras innan det nya värdet tilldelas. Om inte dst är
NULL
är anroparen ansvarig för att decimera referensantalet genom att anropa dessRelease
-metod vid behov.Tillgänglighet: Windows
Tillagd i version 3.14.
- ctypes.cast(obj, type)¶
Denna funktion liknar cast-operatorn i C. Den returnerar en ny instans av type som pekar på samma minnesblock som obj. typ måste vara en pekartyp och obj måste vara ett objekt som kan tolkas som en pekare.
- ctypes.create_string_buffer(init, size=None)¶
- ctypes.create_string_buffer(size)
Denna funktion skapar en föränderlig teckenbuffert. Det returnerade objektet är en ctypes-array av
c_char
.Om size anges (och inte
None
) måste det vara enint
. Den anger storleken på den returnerade arrayen.Om init-argumentet anges måste det vara
bytes
. Det används för att initialisera arrayobjekten. Bytes som inte initieras på detta sätt sätts till noll (NUL).Om size inte anges (eller om den är
None
) görs bufferten ett element större än init, vilket innebär att en NUL-terminator läggs till.Om båda argumenten anges får size inte vara mindre än
len(init)
.Varning
Om size är lika med
len(init)
, läggs ingen NUL-terminator till. Behandla inte en sådan buffert som en C-sträng.Till exempel:
>>> bytes(create_string_buffer(2)) b'\x00\x00' >>> bytes(create_string_buffer(b'ab')) b'ab\x00' >>> bytes(create_string_buffer(b'ab', 2)) b'ab' >>> bytes(create_string_buffer(b'ab', 4)) b'ab\x00\x00' >>> bytes(create_string_buffer(b'abcdef', 2)) Traceback (most recent call last): ... ValueError: byte string too long
Utlöser en auditing event
ctypes.create_string_buffer
med argumenteninit
,size
.
- ctypes.create_unicode_buffer(init, size=None)¶
- ctypes.create_unicode_buffer(size)
Denna funktion skapar en mutabel unicode-teckenbuffert. Det returnerade objektet är en ctypes-array av
c_wchar
.Funktionen tar samma argument som
create_string_buffer()
förutom att init måste vara en sträng och size räknarc_wchar
.Utlöser en auditing event
ctypes.create_unicode_buffer
med argumenteninit
,size
.
- ctypes.DllCanUnloadNow()¶
Denna funktion är en hook som gör det möjligt att implementera COM-servrar i processen med ctypes. Den anropas från funktionen DllCanUnloadNow som exporteras av tilläggsdivisionen _ctypes.
Tillgänglighet: Windows
- ctypes.DllGetClassObject()¶
Denna funktion är en hook som gör det möjligt att implementera COM-servrar i processen med ctypes. Den anropas från funktionen DllGetClassObject som exporteras av dll-tillägget
_ctypes
.Tillgänglighet: Windows
- ctypes.util.find_library(name)¶
Försöker hitta ett bibliotek och returnerar ett sökvägsnamn. name är biblioteksnamnet utan något prefix som
lib
, suffix som.so
,.dylib
eller versionsnummer (detta är den form som används för posix-länkaralternativet-l
). Om inget bibliotek kan hittas returnerasNone
.Den exakta funktionaliteten är systemberoende.
- ctypes.util.find_msvcrt()¶
Returnerar filnamnet på det VC runtime-bibliotek som används av Python och av tilläggsmodulerna. Om namnet på biblioteket inte kan fastställas returneras
None
.Om du behöver frigöra minne, t.ex. minne som har allokerats av en tilläggsmodul med ett anrop till funktionen
free(void *)
, är det viktigt att du använder funktionen i samma bibliotek som allokerade minnet.Tillgänglighet: Windows
- ctypes.util.dllist()¶
Försök att tillhandahålla en lista med sökvägar till de delade bibliotek som laddats in i den aktuella processen. Dessa sökvägar är inte normaliserade eller bearbetade på något sätt. Funktionen kan ge upphov till
OSError
om de underliggande plattforms-API:erna misslyckas. Den exakta funktionaliteten är systemberoende.På de flesta plattformar representerar det första elementet i listan den aktuella körbara filen. Det kan vara en tom sträng.
Tillgänglighet: Windows, macOS, iOS, glibc, BSD libc, musl
Tillagd i version 3.14.
- ctypes.FormatError([code])¶
Returnerar en textuell beskrivning av felkoden code. Om ingen felkod anges används den senaste felkoden genom att anropa Windows API-funktionen
GetLastError()
.Tillgänglighet: Windows
- ctypes.GetLastError()¶
Returnerar den senaste felkoden som ställts in av Windows i den anropande tråden. Denna funktion anropar Windows-funktionen
GetLastError()
direkt, den returnerar inte den ctypes-privata kopian av felkoden.Tillgänglighet: Windows
- ctypes.get_errno()¶
Returnerar det aktuella värdet av den ctypes-privata kopian av systemvariabeln
errno
i den anropande tråden.Utlöser en auditing event
ctypes.get_errno
utan argument.
- ctypes.get_last_error()¶
Returnerar det aktuella värdet av den ctypes-privata kopian av systemvariabeln
LastError
i den anropande tråden.Tillgänglighet: Windows
Utlöser en auditing event
ctypes.get_last_error
utan argument.
- ctypes.memmove(dst, src, count)¶
Samma som standard C memmove biblioteksfunktionen: kopierar count bytes från src till dst. dst och src måste vara heltal eller ctypes-instanser som kan konverteras till pekare.
- ctypes.memset(dst, c, count)¶
Samma som standardfunktionen memset i C-biblioteket: fyller minnesblocket på adress dst med count byte av värdet c. dst måste vara ett heltal som anger en adress, eller en ctypes-instans.
- ctypes.POINTER(type, /)¶
Skapa eller returnera en ctypes-pekartyp. Pekartyperna cachas och återanvänds internt, så det är billigt att anropa denna funktion upprepade gånger. type måste vara en ctypes-typ.
Den resulterande pekartypen cachelagras i attributet
__pointer_type__
för type. Det är möjligt att ställa in detta attribut före det första anropet tillPOINTER
för att ställa in en anpassad pekartyp. Det är dock inte rekommenderat att göra detta: att manuellt skapa en lämplig pekartyp är svårt utan att förlita sig på implementationsdetaljer som kan ändras i framtida Python-versioner.
- ctypes.pointer(obj, /)¶
Skapa en ny pekarinstans som pekar på obj. Det returnerade objektet är av typen
POINTER(type(obj))
.Observera: Om du bara vill skicka en pekare till ett objekt till ett främmande funktionsanrop bör du använda
byref(obj)
som är mycket snabbare.
- ctypes.resize(obj, size)¶
Den här funktionen ändrar storleken på internminnesbufferten för obj, som måste vara en instans av en ctypes-typ. Det är inte möjligt att göra bufferten mindre än den ursprungliga storleken för objekttypen, som anges av
sizeof(type(obj))
, men det är möjligt att förstora bufferten.
- ctypes.set_errno(value)¶
Ställ in det aktuella värdet för den ctypes-privata kopian av systemvariabeln
errno
i den anropande tråden till värde och returnera det tidigare värdet.Utlöser en auditing event
ctypes.set_errno
med argumenteterrno
.
- ctypes.set_last_error(value)¶
Ställer in det aktuella värdet för den ctypes-privata kopian av systemvariabeln
LastError
i den anropande tråden till värde och returnerar det tidigare värdet.Tillgänglighet: Windows
Utlöser en auditing event
ctypes.set_last_error
med argumenteterror
.
- ctypes.sizeof(obj_or_type)¶
Returnerar storleken i byte på en minnesbuffert för en ctypes-typ eller instans. Gör samma sak som C-operatorn
sizeof
.
- ctypes.string_at(ptr, size=-1)¶
Returnerar byte-strängen på void *ptr. Om size anges används den som storlek, annars antas strängen vara nollavslutad.
Utlöser en auditing event
ctypes.string_at
med argumentenptr
,size
.
- ctypes.WinError(code=None, descr=None)¶
Skapar en instans av
OSError
. Om code inte är specificerad anropasGetLastError()
för att bestämma felkoden. Om descr inte anges, anropasFormatError()
för att få en textuell beskrivning av felet.Tillgänglighet: Windows
Ändrad i version 3.3: Tidigare skapades en instans av
WindowsError
, som nu är ett alias avOSError
.
- ctypes.wstring_at(ptr, size=-1)¶
Returnerar den breda teckensträngen på void *ptr. Om size anges används det som antal tecken i strängen, annars antas strängen vara nollavslutad.
Utlöser en auditing event
ctypes.wstring_at
med argumentenptr
,size
.
- ctypes.memoryview_at(ptr, size, readonly=False)¶
Returnera ett
memoryview
-objekt av längd storlek som refererar till minnet som börjar vid void *ptr.Om readonly är true kan det returnerade
memoryview
-objektet inte användas för att ändra det underliggande minnet. (Ändringar som gjorts på annat sätt kommer fortfarande att återspeglas i det returnerade objektet)Denna funktion liknar
string_at()
med den viktiga skillnaden att den inte gör en kopia av det angivna minnet. Det är ett semantiskt likvärdigt (men mer effektivt) alternativ tillmemoryview((c_byte * size).from_address(ptr))
. (Medanfrom_address()
bara tar heltal, kan ptr också ges som ettctypes.POINTER
eller ettbyref()
-objekt)Utlöser en auditing event
ctypes.memoryview_at
med argumentenaddress
,size
,readonly
.Tillagd i version 3.14.
Datatyper¶
- class ctypes._CData¶
Denna icke-offentliga klass är den gemensamma basklassen för alla ctypes-datatyper. Bland annat innehåller alla instanser av ctypes-typen ett minnesblock som innehåller C-kompatibla data; adressen till minnesblocket returneras av hjälpfunktionen
addressof()
. En annan instansvariabel exponeras som_objects
; denna innehåller andra Python-objekt som måste hållas vid liv ifall minnesblocket innehåller pekare.Vanliga metoder för ctypes-datatyper, dessa är alla klassmetoder (för att vara exakt är de metoder för metaclass):
- from_buffer(source[, offset])¶
Denna metod returnerar en ctypes-instans som delar buffert med käll-objektet. Objektet källa måste stödja gränssnittet för skrivbar buffert. Den valfria parametern offset anger en förskjutning i källbufferten i byte; standardvärdet är noll. Om källbufferten inte är tillräckligt stor uppstår ett
ValueError
.Utlöser en auditing event
ctypes.cdata/buffer
med argumentenpointer
,size
,offset
.
- from_buffer_copy(source[, offset])¶
Denna metod skapar en ctypes-instans genom att kopiera bufferten från källans objektbuffert som måste vara läsbar. Den valfria parametern offset anger en förskjutning i källbufferten i byte; standardvärdet är noll. Om källbufferten inte är tillräckligt stor uppstår ett
ValueError
.Utlöser en auditing event
ctypes.cdata/buffer
med argumentenpointer
,size
,offset
.
- from_address(address)¶
Den här metoden returnerar en ctypes-typinstans som använder det minne som anges av address, som måste vara ett heltal.
Denna metod, och andra som indirekt anropar denna metod, ger skapar en auditing event
ctypes.cdata
med argumentetaddress
.
- from_param(obj)¶
Denna metod anpassar obj till en ctypes-typ. Den anropas med det faktiska objekt som används i ett utländskt funktionsanrop när typen finns i den utländska funktionens
argtypes
-tupel; den måste returnera ett objekt som kan användas som parameter för funktionsanropet.Alla ctypes-datatyper har en standardimplementering av denna classmethod som normalt returnerar obj om det är en instans av typen. Vissa typer accepterar även andra objekt.
- in_dll(library, name)¶
Denna metod returnerar en ctypes-typinstans som exporteras av ett delat bibliotek. name är namnet på den symbol som exporterar data, library är det laddade delade biblioteket.
Gemensamma klassvariabler för ctypes-datatyper:
- __pointer_type__¶
Den pekartyp som skapades genom anrop av
POINTER()
för motsvarande ctypes-datatyp. Om en pekartyp ännu inte skapats saknas attributet.Tillagd i version 3.14.
Vanliga instansvariabler för ctypes datatyper:
- _b_base_¶
Ibland äger inte ctypes-datainstanser det minnesblock de innehåller, utan de delar istället en del av minnesblocket för ett basobjekt. Den skrivskyddade medlemmen
_b_base_
är det rot-ctypes-objekt som äger minnesblocket.
- _b_needsfree_¶
Denna skrivskyddade variabel är sann när ctypes-datainstansen har allokerat minnesblocket själv, annars falsk.
- _objects¶
Denna medlem är antingen
None
eller en ordbok som innehåller Python-objekt som måste hållas vid liv så att minnesblockets innehåll hålls giltigt. Detta objekt är endast exponerat för felsökning; ändra aldrig innehållet i denna ordbok.
Grundläggande datatyper¶
- class ctypes._SimpleCData¶
Denna icke-offentliga klass är basklass för alla grundläggande ctypes-datatyper. Den nämns här eftersom den innehåller de gemensamma attributen för de grundläggande ctypes-datatyperna.
_SimpleCData
är en underklass till_CData
, så den ärver deras metoder och attribut. ctypes-datatyper som inte är och inte innehåller pekare kan nu picklas.Instanser har ett enda attribut:
- value¶
Detta attribut innehåller det faktiska värdet för instansen. För heltals- och pekartyper är det ett heltal, för teckentyper är det ett objekt eller en sträng med enstaka teckenbytes, för teckenspekartyper är det ett objekt eller en sträng med Python-bytes.
När attributet
value
hämtas från en ctypes-instans returneras vanligtvis ett nytt objekt varje gång.ctypes
implementerar inte originalobjektretur, alltid konstrueras ett nytt objekt. Detsamma gäller för alla andra ctypes-objektinstanser.
Grundläggande datatyper, när de returneras som resultat av anrop från främmande funktioner, eller till exempel genom att hämta strukturfältmedlemmar eller arrayobjekt, konverteras transparent till ursprungliga Python-typer. Med andra ord, om en utländsk funktion har en restype
av c_char_p
, kommer du alltid att få ett Python bytes-objekt, inte en c_char_p
-instans.
Underklasser av grundläggande datatyper ärver inte detta beteende. Så om en utländsk funktion restype
är en subklass av c_void_p
, kommer du att få en instans av denna subklass från funktionsanropet. Naturligtvis kan du få pekarens värde genom att komma åt attributet value
.
Dessa är de grundläggande ctypes-datatyperna:
- class ctypes.c_byte¶
Representerar C:s datatyp signed char och tolkar värdet som ett litet heltal. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_char¶
Representerar C char-datatypen och tolkar värdet som ett enda tecken. Konstruktören accepterar en valfri stränginitialiserare, strängens längd måste vara exakt ett tecken.
- class ctypes.c_char_p¶
Representerar datatypen C char* när den pekar på en nollavslutad sträng. För en allmän teckenpekare som också kan peka på binära data måste
POINTER(c_char)
användas. Konstruktören accepterar en heltalsadress eller ett bytes-objekt.
- class ctypes.c_double¶
Representerar datatypen C double. Konstruktören accepterar en valfri float-initialiserare.
- class ctypes.c_longdouble¶
Representerar datatypen C long double. Konstruktorn accepterar en valfri float-initialiserare. På plattformar där
sizeof(long double) == sizeof(double)
är det ett alias tillc_double
.
- class ctypes.c_float¶
Representerar datatypen C float. Konstruktören accepterar en valfri float-initialiserare.
- class ctypes.c_double_complex¶
Representerar C double complex-datatypen, om den finns tillgänglig. Konstruktören accepterar en valfri
complex
-initialiserare.Tillagd i version 3.14.
- class ctypes.c_float_complex¶
Representerar C float complex-datatypen, om sådan finns. Konstruktören accepterar en valfri
complex
-initialiserare.Tillagd i version 3.14.
- class ctypes.c_longdouble_complex¶
Representerar C long double complex-datatypen, om den finns tillgänglig. Konstruktören accepterar en valfri
complex
-initialiserare.Tillagd i version 3.14.
- class ctypes.c_int¶
Representerar datatypen C signed int. Konstruktorn accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs. På plattformar där
sizeof(int) == sizeof(long)
är det ett alias tillc_long
.
- class ctypes.c_int16¶
Representerar C 16-bitars signed int-datatypen. Vanligtvis ett alias för
c_short
.
- class ctypes.c_int32¶
Representerar C 32-bitars signed int-datatypen. Vanligtvis ett alias för
c_int
.
- class ctypes.c_int64¶
Representerar C 64-bitars signed int-datatypen. Vanligtvis ett alias för
c_longlong
.
- class ctypes.c_long¶
Representerar datatypen C signed long. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_longlong¶
Representerar datatypen C signed long long. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_short¶
Representerar datatypen C signed short. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_size_t¶
Representerar datatypen C
size_t
.
- class ctypes.c_ssize_t¶
Representerar datatypen C
ssize_t
.Tillagd i version 3.2.
- class ctypes.c_time_t¶
Representerar datatypen C
time_t
.Tillagd i version 3.12.
- class ctypes.c_ubyte¶
Representerar C unsigned char-datatypen, tolkar värdet som ett litet heltal. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_uint¶
Representerar datatypen C unsigned int. Konstruktorn accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs. På plattformar där
sizeof(int) == sizeof(long)
är det ett alias förc_ulong
.
- class ctypes.c_uint8¶
Representerar C 8-bitars datatypen unsigned int. Det är ett alias för
c_ubyte
.
- class ctypes.c_uint16¶
Representerar C 16-bitars unsigned int-datatypen. Vanligtvis ett alias för
c_ushort
.
- class ctypes.c_uint32¶
Representerar C 32-bitars unsigned int-datatypen. Vanligtvis ett alias för
c_uint
.
- class ctypes.c_uint64¶
Representerar C 64-bitars unsigned int-datatypen. Vanligtvis ett alias för
c_ulonglong
.
- class ctypes.c_ulong¶
Representerar datatypen C unsigned long. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_ulonglong¶
Representerar datatypen C unsigned long long. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_ushort¶
Representerar datatypen C unsigned short. Konstruktören accepterar en valfri heltalsinitialiserare; ingen kontroll av överflöd görs.
- class ctypes.c_void_p¶
Representerar C void*-typen. Värdet representeras som ett heltal. Konstruktören accepterar en valfri heltalsinitialiserare.
- class ctypes.c_wchar¶
Representerar datatypen C
wchar_t
och tolkar värdet som en unicode-sträng med ett tecken. Konstruktören accepterar en valfri stränginitialiserare, strängens längd måste vara exakt ett tecken.
- class ctypes.c_wchar_p¶
Representerar datatypen C wchar_t*, som måste vara en pekare till en nollavslutad bred teckensträng. Konstruktören accepterar en heltalsadress eller en sträng.
- class ctypes.c_bool¶
Representerar C:s datatyp bool (mer exakt _Bool från C99). Dess värde kan vara
True
ellerFalse
, och konstruktören accepterar alla objekt som har ett sanningsvärde.
- class ctypes.HRESULT¶
Representerar ett värde av
HRESULT
, som innehåller information om framgång eller fel för ett funktions- eller metodanrop.Tillgänglighet: Windows
- class ctypes.py_object¶
Representerar datatypen C PyObject*. Anrop av detta utan argument skapar en
NULL
PyObject*-pekare.Ändrad i version 3.14:
py_object
är nu en generic type.
Modulen ctypes.wintypes
tillhandahåller en hel del andra Windows-specifika datatyper, till exempel HWND
, WPARAM
eller DWORD
. Några användbara strukturer som MSG
eller RECT
är också definierade.
Strukturerade datatyper¶
- class ctypes.Union(*args, **kw)¶
Abstrakt basklass för unioner i inbyggd byte-ordning.
Unions har samma attribut och beteende som strukturer; se
Structure
-dokumentationen för mer information.
- class ctypes.BigEndianUnion(*args, **kw)¶
Abstrakt basklass för unioner i big endian byteordning.
Tillagd i version 3.11.
- class ctypes.LittleEndianUnion(*args, **kw)¶
Abstrakt basklass för unioner i byteordning little endian.
Tillagd i version 3.11.
- class ctypes.BigEndianStructure(*args, **kw)¶
Abstrakt basklass för strukturer i big endian byteordning.
- class ctypes.LittleEndianStructure(*args, **kw)¶
Abstrakt basklass för strukturer i byteordning little endian.
Strukturer och unioner med icke inhemsk byteordning kan inte innehålla fält av pekartyp eller andra datatyper som innehåller fält av pekartyp.
- class ctypes.Structure(*args, **kw)¶
Abstrakt basklass för strukturer i nativ byte-ordning.
Konkreta struktur- och unionstyper måste skapas genom att underklassa en av dessa typer och åtminstone definiera en klassvariabel
_fields_
.ctypes
skapar descriptor som gör det möjligt att läsa och skriva fälten genom direkt attributåtkomst. Dessa är- _fields_¶
En sekvens som definierar strukturfälten. Elementen måste vara 2-tupler eller 3-tupler. Det första objektet är fältets namn, det andra objektet anger fältets typ; det kan vara vilken ctypes-datatyp som helst.
För fält av heltalstyp som
c_int
kan ett tredje valfritt element anges. Det måste vara ett litet positivt heltal som definierar fältets bitbredd.Fältnamn måste vara unika inom en struktur eller union. Detta kontrolleras inte, endast ett fält kan nås när namnen upprepas.
Det är möjligt att definiera klassvariabeln
_fields_
efter den class-sats som definierar underklassen Structure, vilket gör det möjligt att skapa datatyper som direkt eller indirekt refererar till sig själva:klass Lista(Struktur): pass List._fields_ = [("pnext", POINTER(List)), ... ]
Klassvariabeln
_fields_
kan bara ställas in en gång. Senare tilldelningar kommer att ge upphov till ettAttributeError
.Dessutom måste klassvariabeln
_fields_
definieras innan struktur- eller unionstypen används första gången: en instans eller underklass skapas,sizeof()
anropas på den, och så vidare. Senare tilldelningar till_fields_
kommer att ge upphov till ettAttributeError
. Om_fields_
inte har ställts in innan sådan användning, kommer strukturen eller unionen inte att ha några egna fält, som om_fields_
var tom.Subsubklasser av strukturtyper ärver fälten i basklassen plus de
_fields_
som definieras i subsubklassen, om sådana finns.
- _pack_¶
Ett valfritt litet heltal som gör det möjligt att åsidosätta inriktningen av strukturfälten i instansen.
_pack_
måste redan vara definierat när_fields_
tilldelas, annars har det ingen effekt. Att sätta detta attribut till 0 är samma sak som att inte sätta det alls.Detta är endast implementerat för den MSVC-kompatibla minneslayouten.
Deprecated since version 3.14, will be removed in version 3.19: Av historiska skäl, om
_pack_
är icke-noll, kommer den MSVC-kompatibla layouten att användas som standard. På icke-Windows-plattformar är denna standard föråldrad och kommer att bli ett fel i Python 3.19. Om det är avsett, sätt_layout_
till'ms'
explicit.
- _align_¶
Ett valfritt litet heltal som gör det möjligt att åsidosätta strukturens inriktning när den packas eller packas upp till/från minnet. Att sätta detta attribut till 0 är samma sak som att inte sätta det alls.
Tillagd i version 3.13.
- _layout_¶
En valfri sträng som namnger struct/union-layouten. Den kan för närvarande vara inställd på:
"ms"
: den layout som används av Microsofts kompilator (MSVC). I GCC och Clang kan denna layout väljas med__attribute__((ms_struct))
."gcc-sysv"
: den layout som används av GCC med datamodellen System V eller ”SysV-liknande”, som används på Linux och macOS. Med den här layouten måste_pack_
vara unset eller noll.
Om det inte anges explicit kommer
ctypes
att använda en standard som matchar plattformens konventioner. Denna standard kan ändras i framtida Python-utgåvor (till exempel när en ny plattform får officiellt stöd, eller när en skillnad mellan liknande plattformar upptäcks). För närvarande kommer standardvärdet att vara:I Windows:
"ms"
När
_pack_
anges:"ms"
. (Detta är föråldrat; se_pack_
dokumentation)Annars:
"gcc-sysv"
_layout_
måste redan vara definierad när_fields_
tilldelas, annars har den ingen effekt.Tillagd i version 3.14.
- _anonymous_¶
En valfri sekvens som listar namnen på namnlösa (anonyma) fält.
_anonymous_
måste redan vara definierat när_fields_
tilldelas, annars har det ingen effekt.De fält som anges i denna variabel måste vara av strukturtyp eller unionstyp.
ctypes
skapar deskriptorer i strukturtypen som gör det möjligt att komma åt de nästlade fälten direkt, utan att behöva skapa struktur- eller unionsfältet.Här är ett exempel på en typ (Windows):
klass _U(Union): _fields_ = [("lptdesc", POINTER(TYPEDESC)), ("lpadesc", POINTER(ARRAYDESC)), ("hreftype", HREFTYPE)] klass TYPEDESC(Struktur): _anonymous_ = ("u",) _fields_ = [("u", _U), ("vt", VARTYPE)]
Strukturen
TYPEDESC
beskriver en COM-datatyp, fältetvt
anger vilket av unionsfälten som är giltigt. Eftersom fältetu
är definierat som ett anonymt fält är det nu möjligt att komma åt medlemmarna direkt från TYPEDESC-instansen.td.lptdesc
ochtd.u.lptdesc
är likvärdiga, men den förra är snabbare eftersom den inte behöver skapa en tillfällig unionsinstans:td = TYPEDESC() td.vt = VT_PTR td.lptdesc = POINTER(some_type) td.u.lptdesc = POINTER(some_type)
Det är möjligt att definiera sub-subklasser av strukturer, de ärver fälten i basklassen. Om subklassdefinitionen har en separat variabel
_fields_
, läggs de fält som anges i denna till basklassens fält.Struktur- och unionskonstruktörer accepterar både positionella argument och nyckelordsargument. Positionella argument används för att initiera medlemsfält i samma ordning som de visas i
_fields_
. Nyckelord i konstruktorn tolkas som attributtilldelningar, vilket innebär att de initierar_fields_
med samma namn eller skapar nya attribut för namn som inte finns i_fields_
.
- class ctypes.CField(*args, **kw)¶
Deskriptor för fält i en
Structure
ochUnion
. Till exempel:>>> class Color(Structure): ... _fields_ = ( ... ('red', c_uint8), ... ('green', c_uint8), ... ('blue', c_uint8), ... ('intense', c_bool, 1), ... ('blinking', c_bool, 1), ... ) ... >>> Color.red <ctypes.CField 'red' type=c_ubyte, ofs=0, size=1> >>> Color.green.type <class 'ctypes.c_ubyte'> >>> Color.blue.byte_offset 2 >>> Color.intense <ctypes.CField 'intense' type=c_bool, ofs=3, bit_size=1, bit_offset=0> >>> Color.blinking.bit_offset 1
Alla attribut är skrivskyddade.
CField
-objekt skapas via_fields_
; instansiera inte klassen direkt.Tillagd i version 3.14: Tidigare hade deskriptorer endast attributen
offset
ochsize
och en läsbar strängrepresentation; klassenCField
var inte direkt tillgänglig.- name¶
Namn på fältet, som en sträng.
- type¶
Typ av fält, som en ctypes class.
- offset¶
- byte_offset¶
Offset för fältet, i byte.
För bitfält är detta offset för den underliggande byte-alignerade lagringsenheten; se
bit_offset
.
- byte_size¶
Storlek på fältet, i byte.
För bitfields är detta storleken på den underliggande lagringsenheten. Vanligtvis har den samma storlek som bitfältets typ.
- size¶
För fält som inte är bitfält, motsvarande
byte_size
.För bitfält innehåller detta ett bakåtkompatibelt bitpackat värde som kombinerar
bit_size
ochbit_offset
. Föredrar att använda de explicita attributen istället.
- is_bitfield¶
True om detta är ett bitfält.
- bit_offset¶
- bit_size¶
Platsen för ett bitfält inom dess lagringsenhet, det vill säga inom
byte_size
bytes minne med början vidbyte_offset
.För att få fältets värde, läs lagringsenheten som ett heltal, shift left med
bit_offset
och ta debit_size
minst signifikanta bitarna.För icke-bitfält är
bit_offset
noll ochbit_size
är lika medbyte_size * 8
.
- is_anonymous¶
True om fältet är anonymt, dvs. innehåller nästlade underfält som bör slås samman till en innehållande struktur eller union.
Arrayer och pekare¶
- class ctypes.Array(*args)¶
Abstrakt basklass för arrayer.
Det rekommenderade sättet att skapa konkreta array-typer är att multiplicera valfri
ctypes
-datatyp med ett icke-negativt heltal. Alternativt kan du underklassa den här typen och definiera klassvariablerna_length_
och_type_
. Array-element kan läsas och skrivas med hjälp av standardåtkomst för subscript och slice; för slice-läsning är det resulterande objektet inte i sig självt enArray
.- _length_¶
Ett positivt heltal som anger antalet element i matrisen. Subskriptioner utanför intervallet resulterar i ett
IndexError
. Kommer att returneras avlen()
.
- _type_¶
Anger typen för varje element i matrisen.
Array-underklassens konstruktörer accepterar positionella argument som används för att initiera elementen i ordning.
- ctypes.ARRAY(type, length)¶
Skapar en array. Motsvarar
type * length
, där type är enctypes
-datatyp och length ett heltal.Denna funktion är soft deprecated till förmån för multiplikation. Det finns inga planer på att ta bort den.
- class ctypes._Pointer¶
Privat, abstrakt basklass för pekare.
Konkreta pekartyper skapas genom att anropa
POINTER()
med den typ som ska pekas på; detta görs automatiskt avpointer()
.Om en pekare pekar på en array kan dess element läsas och skrivas med hjälp av standardåtkomst för subscript och slice. Pekarobjekt har ingen storlek, så
len()
kommer att ge upphov tillTypeError
. Negativa subscripts läser från minnet före pekaren (som i C), och out-of-range subscripts kraschar förmodligen med en access violation (om du har tur).- _type_¶
Anger vilken typ som pekas ut.
- contents¶
Returnerar det objekt som pekaren till pekar på. Om du tilldelar detta attribut ändras pekaren till att peka på det tilldelade objektet.
Undantag¶
- exception ctypes.ArgumentError¶
Detta undantag uppstår när ett anrop av en utländsk funktion inte kan konvertera ett av de passerade argumenten.
- exception ctypes.COMError(hresult, text, details)¶
Detta undantag uppstår när ett COM-metodanrop misslyckades.
- hresult¶
Heltalsvärdet som representerar felkoden.
- text¶
Felmeddelandet.
- details¶
5-tupeln
(descr, source, helpfile, helpcontext, progid)
.descr är den textuella beskrivningen. source är det språkberoende
ProgID
för den klass eller det program som orsakade felet. helpfile är sökvägen till hjälpfilen. helpcontext är identifieraren för hjälpsammanhanget. progid ärProgID
för det gränssnitt som definierade felet.
Tillgänglighet: Windows
Tillagd i version 3.14.