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.

Å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

c_bool

_Bool

bool (1)

c_char

char

1-teckens byte-objekt

c_wchar

wchar_t

1-teckens sträng

c_byte

char

int

c_ubyte

unsigned char

int

c_short

short

int

c_ushort

unsigned short

int

c_int

int

int

c_int8

int8_t

int

c_int16

int16_t

int

c_int32

int32_t

int

c_int64

int64_t

int

c_uint

unsigned int

int

c_uint8

uint8_t

int

c_uint16

uint16_t

int

c_uint32

uint32_t

int

c_uint64

uint64_t

int

c_long

long

int

c_ulong

unsigned long

int

c_longlong

__int64 eller long long

int

c_ulonglong

unsigned __int64 eller unsigned long long

int

c_size_t

size_t

int

c_ssize_t

ssize_t eller Py_ssize_t

int

c_time_t

time_t

int

c_float

float

flyt

c_double

double

flyt

c_longdouble

long double

flyt

c_char_p

char* (NUL-terminerad)

bytes objekt eller None

c_wchar_p

wchar_t* (NUL-terminerad)

sträng eller None

c_void_p

void*

int eller None

  1. 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

c_float_complex

float complex

komplex

c_double_complex

double complex

komplex

c_longdouble_complex

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 ...>
>>>

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 är NULL 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

Hitta delade bibliotek

När du programmerar i ett kompilerat språk används delade bibliotek när du kompilerar/länkar ett program och när programmet körs.

Syftet med funktionen find_library() är att hitta ett bibliotek på ett sätt som liknar det som kompilatorn eller runtime-laddaren gör (på plattformar med flera versioner av ett delat bibliotek bör den senaste laddas), medan ctypes-biblioteksladdarna fungerar som när ett program körs och anropar runtime-laddaren direkt.

Modulen ctypes.util innehåller en funktion som kan hjälpa till att bestämma vilket bibliotek som ska laddas.

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änkalternativet -l). Om inget bibliotek kan hittas returneras None.

Den exakta funktionaliteten är systemberoende.

På Linux försöker find_library() köra externa program (/sbin/ldconfig, gcc, objdump och ld) för att hitta biblioteksfilen. Den returnerar filnamnet på biblioteksfilen.

Ändrad i version 3.6: Under Linux används värdet för miljövariabeln LD_LIBRARY_PATH vid sökning efter bibliotek, om ett bibliotek inte kan hittas på något annat sätt.

Här är några exempel:

>>> from ctypes.util import find_library
>>> find_library("m")
'libm.so.6'
>>> find_library("c")
'libc.so.6'
>>> find_library("bz2")
'libbz2.so.1.0'
>>>

På macOS och Android använder find_library() systemets standardnamngivningsscheman och sökvägar för att hitta biblioteket och returnerar ett fullständigt söknamn om det lyckas:

>>> from ctypes.util import find_library
>>> find_library("c")
'/usr/lib/libc.dylib'
>>> find_library("m")
'/usr/lib/libm.dylib'
>>> find_library("bz2")
'/usr/lib/libbz2.dylib'
>>> find_library("AGL")
'/System/Library/Frameworks/AGL.framework/AGL'
>>>

På Windows söker find_library() längs systemets sökväg och returnerar det fullständiga sökvägsnamnet, men eftersom det inte finns något fördefinierat namngivningsschema kommer ett anrop som find_library("c") att misslyckas och returnera None.

Om du omsluter ett delat bibliotek med ctypes, kan det vara bättre att bestämma det delade bibliotekets namn under utvecklingstiden och hårdkoda det i omslutningsmodulen istället för att använda find_library() för att hitta biblioteket vid körning.

Listning av laddade delade bibliotek

När du skriver kod som förlitar sig på kod som laddats från delade bibliotek kan det vara bra att veta vilka delade bibliotek som redan har laddats i den aktuella processen.

Modulen ctypes.util tillhandahåller funktionen dllist(), som anropar de olika API:er som tillhandahålls av de olika plattformarna för att avgöra vilka delade bibliotek som redan har laddats in i den aktuella processen.

Den exakta utmatningen av denna funktion är systemberoende. På de flesta plattformar representerar den första posten i listan själva den aktuella processen, som kan vara en tom sträng. På glibc-baserad Linux kan till exempel returen se ut som:

>>> from ctypes.util import dllist
>>> dllist()
['', 'linux-vdso.so.1', '/lib/x86_64-linux-gnu/libm.so.6', '/lib/x86_64-linux-gnu/libc.so.6', ... ]

Ladda delade bibliotek

Det finns flera sätt att ladda in delade bibliotek i Python-processen. Ett sätt är att instansiera en av följande klasser:

class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

Instanser av denna klass representerar laddade delade bibliotek. Funktioner i dessa bibliotek använder standard C-anropskonventionen och antas returnera int.

I Windows kan det misslyckas att skapa en CDLL-instans även om DLL-namnet finns. När en DLL som är beroende av den inlästa DLL:en inte hittas, uppstår ett OSError-fel med meddelandet ”[WinError 126] Den angivna modulen kunde inte hittas”. Detta felmeddelande innehåller inte namnet på den DLL som saknas eftersom Windows API inte returnerar denna information, vilket gör det svårt att diagnostisera detta fel. För att lösa det här felet och avgöra vilken DLL som inte hittas måste du hitta listan över beroende DLL:er och avgöra vilken som inte hittas med hjälp av Windows felsöknings- och spårningsverktyg.

Ändrad i version 3.12: Parametern namn kan nu vara en path-like object.

Se även

Microsofts DUMPBIN-verktyg – Ett verktyg för att hitta DLL-beroenden.

class ctypes.OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

Instanser av denna klass representerar inlästa delade bibliotek, funktioner i dessa bibliotek använder anropskonventionen stdcall och antas returnera den Windows-specifika HRESULT-koden. HRESULT-värden innehåller information som anger om funktionsanropet misslyckades eller lyckades, tillsammans med ytterligare felkod. Om returvärdet signalerar ett misslyckande, skapas automatiskt ett OSError.

Tillgänglighet: Windows

Ändrad i version 3.3: tidigare användes WindowsError, som nu är ett alias för OSError.

Ändrad i version 3.12: Parametern namn kan nu vara en path-like object.

class ctypes.WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

Instanser av den här klassen representerar laddade delade bibliotek, funktioner i dessa bibliotek använder anropskonventionen stdcall och antas returnera int som standard.

Tillgänglighet: Windows

Ändrad i version 3.12: Parametern namn kan nu vara en path-like object.

Python global interpreter lock släpps innan anrop av någon funktion som exporteras av dessa bibliotek, och återfås efteråt.

class ctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)

Instanser av denna klass beter sig som CDLL-instanser, förutom att Python GIL inte släpps under funktionsanropet, och efter att funktionen har exekverats kontrolleras Pythons felflagga. Om fel-flaggan är satt, uppstår ett Python-undantag.

Därför är detta endast användbart för att anropa Python C api-funktioner direkt.

Ändrad i version 3.12: Parametern namn kan nu vara en path-like object.

Alla dessa klasser kan instansieras genom att anropa dem med minst ett argument, sökvägen till det delade biblioteket. Om du har ett befintligt handtag till ett redan laddat delat bibliotek kan det skickas som den namngivna parametern handle, annars används den underliggande plattformens funktion dlopen() eller LoadLibrary() för att ladda biblioteket i processen och för att få ett handtag till det.

Parametern mode kan användas för att ange hur biblioteket laddas. För mer information, se dlopen(3) manpage. I Windows ignoreras mode. På posix-system läggs RTLD_NOW alltid till och är inte konfigurerbart.

Parametern use_errno, när den är satt till true, aktiverar en ctypes-mekanism som gör det möjligt att komma åt systemets errno-felnummer på ett säkert sätt. ctypes upprätthåller en trådlokal kopia av systemets errno-variabel; om du anropar utländska funktioner som skapats med use_errno=True byts errno-värdet före funktionsanropet ut mot ctypes privata kopia, och samma sak händer omedelbart efter funktionsanropet.

Funktionen ctypes.get_errno() returnerar värdet på den privata kopian av ctypes, och funktionen ctypes.set_errno() ändrar den privata kopian av ctypes till ett nytt värde och returnerar det tidigare värdet.

Parametern use_last_error, när den är satt till true, aktiverar samma mekanism för Windows-felkoden som hanteras av Windows API-funktionerna GetLastError() och SetLastError(); ctypes.get_last_error() och ctypes.set_last_error() används för att begära och ändra ctypes privata kopia av Windows-felkoden.

Parametern winmode används i Windows för att ange hur biblioteket laddas (eftersom mode ignoreras). Den tar alla värden som är giltiga för Win32 API:s flaggparameter LoadLibraryEx. När den utelämnas är standardinställningen att använda de flaggor som ger den säkraste DLL-laddningen, vilket undviker problem som DLL-kapning. Att ange den fullständiga sökvägen till DLL:en är det säkraste sättet att se till att rätt bibliotek och beroenden laddas.

Ändrad i version 3.8: Lagt till parametern winmode.

ctypes.RTLD_GLOBAL

Flagga som ska användas som mode-parameter. På plattformar där denna flagga inte är tillgänglig definieras den som heltalet noll.

ctypes.RTLD_LOCAL

Flagga att använda som mode-parameter. På plattformar där detta inte är tillgängligt är det samma sak som RTLD_GLOBAL.

ctypes.DEFAULT_MODE

Det standardläge som används för att ladda delade bibliotek. I OSX 10.3 är detta RTLD_GLOBAL, annars är det samma som RTLD_LOCAL.

Instanser av dessa klasser har inga publika metoder. Funktioner som exporteras av det delade biblioteket kan nås som attribut eller via index. Observera att om du använder funktionen via ett attribut cachas resultatet och därför returneras samma objekt varje gång om du använder den upprepade gånger. Å andra sidan returnerar åtkomst via ett index ett nytt objekt varje gång:

>>> from ctypes import CDLL
>>> libc = CDLL("libc.so.6")  # On Linux
>>> libc.time == libc.time
True
>>> libc['time'] == libc['time']
False

Följande publika attribut finns tillgängliga, deras namn börjar med ett understreck för att inte krocka med exporterade funktionsnamn:

PyDLL._handle

Det systemhandtag som används för att komma åt biblioteket.

PyDLL._name

Namnet på det bibliotek som skickas i konstruktören.

Delade bibliotek kan också laddas med hjälp av ett av de prefabricerade objekten, som är instanser av klassen LibraryLoader, antingen genom att anropa metoden LoadLibrary() eller genom att hämta biblioteket som attribut för laddningsinstansen.

class ctypes.LibraryLoader(dlltype)

Klass som laddar delade bibliotek. dlltype bör vara en av typerna CDLL, PyDLL, WinDLL eller OleDLL.

__getattr__() har ett speciellt beteende: Det gör det möjligt att ladda ett delat bibliotek genom att komma åt det som attribut för en biblioteksladdningsinstans. Resultatet cachas, så upprepade attributåtkomster returnerar samma bibliotek varje gång.

LoadLibrary(name)

Ladda in ett delat bibliotek i processen och returnera det. Denna metod returnerar alltid en ny instans av biblioteket.

Dessa prefabricerade bibliotekslastare finns tillgängliga:

ctypes.cdll

Skapar CDLL-instanser.

ctypes.windll

Skapar WinDLL-instanser.

Tillgänglighet: Windows

ctypes.oledll

Skapar OleDLL-instanser.

Tillgänglighet: Windows

ctypes.pydll

Skapar PyDLL-instanser.

För direkt åtkomst till C Python Api finns ett färdigt Python shared library-objekt tillgängligt:

ctypes.pythonapi

En instans av PyDLL som exponerar Python C API-funktioner som attribut. Observera att alla dessa funktioner antas returnera C int, vilket naturligtvis inte alltid är sant, så du måste tilldela rätt restype-attribut för att använda dessa funktioner.

Att ladda ett bibliotek via något av dessa objekt ger upphov till en auditing event ctypes.dlopen med strängargumentet name, namnet som används för att ladda biblioteket.

Åtkomst till en funktion i ett laddat bibliotek ger upphov till en granskningshändelse ctypes.dlsym med argumenten library (biblioteksobjektet) och name (symbolens namn som en sträng eller ett heltal).

I de fall då endast bibliotekshandtaget är tillgängligt i stället för objektet, ger åtkomst till en funktion upphov till en granskningshändelse ctypes.dlsym/handle med argumenten handle (det råa bibliotekshandtaget) och name.

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 attributet errcheck.

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 tupeln argtypes, denna metod gör det möjligt att anpassa det faktiska argumentet till ett objekt som den utländska funktionen accepterar. Exempelvis kommer ett c_char_p-objekt i argtypes-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ör errno 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 ett COMError.

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 argumentet obj.

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 metod AddRef, 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 dess Release-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 en int. 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 argumenten init, 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äknar c_wchar.

Utlöser en auditing event ctypes.create_unicode_buffer med argumenten init, 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 returneras None.

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 till POINTER 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 argumentet errno.

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 argumentet error.

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 argumenten ptr, size.

ctypes.WinError(code=None, descr=None)

Skapar en instans av OSError. Om code inte är specificerad anropas GetLastError() för att bestämma felkoden. Om descr inte anges, anropas FormatError() 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 av OSError.

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 argumenten ptr, 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 till memoryview((c_byte * size).from_address(ptr)). (Medan from_address() bara tar heltal, kan ptr också ges som ett ctypes.POINTER eller ett byref()-objekt)

Utlöser en auditing event ctypes.memoryview_at med argumenten address, 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 argumenten pointer, 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 argumenten pointer, 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 argumentet address.

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 till c_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 till c_long.

class ctypes.c_int8

Representerar C 8-bitars signed int-datatypen. Det är ett alias för c_byte.

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ör c_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 eller False, 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 ett AttributeError.

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 ett AttributeError. 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ältet vt anger vilket av unionsfälten som är giltigt. Eftersom fältet u är definierat som ett anonymt fält är det nu möjligt att komma åt medlemmarna direkt från TYPEDESC-instansen. td.lptdesc och td.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 och Union. 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 och size och en läsbar strängrepresentation; klassen CField 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 och bit_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 vid byte_offset.

För att få fältets värde, läs lagringsenheten som ett heltal, shift left med bit_offset och ta de bit_size minst signifikanta bitarna.

För icke-bitfält är bit_offset noll och bit_size är lika med byte_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 en Array.

_length_

Ett positivt heltal som anger antalet element i matrisen. Subskriptioner utanför intervallet resulterar i ett IndexError. Kommer att returneras av len().

_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 en ctypes-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 av pointer().

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 till TypeError. 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 är ProgID för det gränssnitt som definierade felet.

Tillgänglighet: Windows

Tillagd i version 3.14.