Using a metaclass on a class drived from another class implemented in CHow would a Python script running on Linux call a routine in a Python script running under Wine?Are static class variables possible?What are metaclasses in Python?How to randomly select an item from a list?Getting the class name of an instance?How do you read from stdin?class << self idiom in RubyPython class inherits objectWhy is reading lines from stdin much slower in C++ than Python?Flask + SQLAlchemy - custom metaclass to modify column setters (dynamic hybrid_property)Immutable attribute in python class and type check
What makes Ada the language of choice for the ISS's safety-critical systems?
What is the actual quality of machine translations?
How did old MS-DOS games utilize various graphic cards?
What ways have you found to get edits from non-LaTeX users?
How can I tell the difference between unmarked sugar and stevia?
Why did the Herschel Space Telescope need helium coolant?
Should I avoid hard-packed crusher dust trails with my hybrid?
Is it a problem if <h4>, <h5> and <h6> are smaller than regular text?
Preventing employees from either switching to competitors or opening their own business
What do abbreviations in movie scripts stand for?
Fixing obscure 8080 emulator bug?
What's up with this leaf?
Universal hash functions with homomorphic XOR property
Generate a Graeco-Latin square
How to signal to my players that the following part is supposed to be played on fast forward?
C++ Arduino IDE receiving garbled `char` from function
What is the highest possible temporary AC at level 1, without any help from others?
How to return a security deposit to a tenant
Frame failure sudden death?
Impedance ratio vs. SWR
Second (easy access) account in case my bank screws up
How to hide an urban landmark?
Pre-1972 sci-fi short story or novel: alien(?) tunnel where people try new moves and get destroyed if they're not the correct ones
How to forge a multi-part weapon?
Using a metaclass on a class drived from another class implemented in C
How would a Python script running on Linux call a routine in a Python script running under Wine?Are static class variables possible?What are metaclasses in Python?How to randomly select an item from a list?Getting the class name of an instance?How do you read from stdin?class << self idiom in RubyPython class inherits objectWhy is reading lines from stdin much slower in C++ than Python?Flask + SQLAlchemy - custom metaclass to modify column setters (dynamic hybrid_property)Immutable attribute in python class and type check
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I am working on a ctypes
drop-in-replacement / extension and ran into an issue I do not fully understand.
I am trying to build a class factory for call-back function decorators similar to CFUNCTYPE and WINFUNCTYPE. Both factories produce classes derived from ctypes._CFuncPtr
. Like every ctypes
function interface, they have properties like argtypes
and restype
. I want to extend the classes allowing an additional property named some_param
and I thought, why not, let's try this with "getter" and "setter" methods - how hard can it be ...
Because I am trying to use "getter" and "setter" methods (@property
) on a property of a class (NOT a property of objects), I ended up writing a metaclass. Because my class is derived from ctypes._CFuncPtr
, I think my metaclass must be derived from ctypes._CFuncPtr.__class__
(I could be wrong here).
The example below works, sort of:
import ctypes
class a_class:
def b_function(self, some_param_parg):
class c_class_meta(ctypes._CFuncPtr.__class__):
def __init__(cls, *args):
super().__init__(*args) # no idea if this is good ...
cls._some_param_ = some_param_parg
@property
def some_param(cls):
return cls._some_param_
@some_param.setter
def some_param(cls, value):
if not isinstance(value, list):
raise TypeError('some_param must be a list')
cls._some_param_ = value
class c_class(ctypes._CFuncPtr, metaclass = c_class_meta):
_argtypes_ = ()
_restype_ = None
_flags_ = ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
return c_class
d_class = a_class().b_function([1, 2, 3])
print(d_class.some_param)
d_class.some_param = [2, 6]
print(d_class.some_param)
d_class.some_param = # Raises an error - as expected
So far so good - using the above any further does NOT work anymore. The following pseudo-code (if used on an actual function from a DLL or shared object) will fail - in fact, it will cause the CPython interpreter to segfault ...
some_routine = ctypes.windll.LoadLibrary('some.dll').some_routine
func_type = d_class(ctypes.c_int16, ctypes.c_int16) # similar to CFUNCTYPE/WINFUNCTYPE
func_type.some_param = [4, 5, 6] # my "special" property
some_routine.argtypes = (ctypes.c_int16, func_type)
@func_type
def demo(x):
return x - 1
some_routine(4, demo) # segfaults HERE!
I am not entirely sure what goes wrong. ctypes._CFuncPtr
is implemented in C, which could be a relevant limitation ... I could also have made a mistake in the implementation of the metaclass. Can someone enlighten me?
(For additional context, I am working on this function.)
python python-3.x ctypes metaclass
add a comment |
I am working on a ctypes
drop-in-replacement / extension and ran into an issue I do not fully understand.
I am trying to build a class factory for call-back function decorators similar to CFUNCTYPE and WINFUNCTYPE. Both factories produce classes derived from ctypes._CFuncPtr
. Like every ctypes
function interface, they have properties like argtypes
and restype
. I want to extend the classes allowing an additional property named some_param
and I thought, why not, let's try this with "getter" and "setter" methods - how hard can it be ...
Because I am trying to use "getter" and "setter" methods (@property
) on a property of a class (NOT a property of objects), I ended up writing a metaclass. Because my class is derived from ctypes._CFuncPtr
, I think my metaclass must be derived from ctypes._CFuncPtr.__class__
(I could be wrong here).
The example below works, sort of:
import ctypes
class a_class:
def b_function(self, some_param_parg):
class c_class_meta(ctypes._CFuncPtr.__class__):
def __init__(cls, *args):
super().__init__(*args) # no idea if this is good ...
cls._some_param_ = some_param_parg
@property
def some_param(cls):
return cls._some_param_
@some_param.setter
def some_param(cls, value):
if not isinstance(value, list):
raise TypeError('some_param must be a list')
cls._some_param_ = value
class c_class(ctypes._CFuncPtr, metaclass = c_class_meta):
_argtypes_ = ()
_restype_ = None
_flags_ = ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
return c_class
d_class = a_class().b_function([1, 2, 3])
print(d_class.some_param)
d_class.some_param = [2, 6]
print(d_class.some_param)
d_class.some_param = # Raises an error - as expected
So far so good - using the above any further does NOT work anymore. The following pseudo-code (if used on an actual function from a DLL or shared object) will fail - in fact, it will cause the CPython interpreter to segfault ...
some_routine = ctypes.windll.LoadLibrary('some.dll').some_routine
func_type = d_class(ctypes.c_int16, ctypes.c_int16) # similar to CFUNCTYPE/WINFUNCTYPE
func_type.some_param = [4, 5, 6] # my "special" property
some_routine.argtypes = (ctypes.c_int16, func_type)
@func_type
def demo(x):
return x - 1
some_routine(4, demo) # segfaults HERE!
I am not entirely sure what goes wrong. ctypes._CFuncPtr
is implemented in C, which could be a relevant limitation ... I could also have made a mistake in the implementation of the metaclass. Can someone enlighten me?
(For additional context, I am working on this function.)
python python-3.x ctypes metaclass
add a comment |
I am working on a ctypes
drop-in-replacement / extension and ran into an issue I do not fully understand.
I am trying to build a class factory for call-back function decorators similar to CFUNCTYPE and WINFUNCTYPE. Both factories produce classes derived from ctypes._CFuncPtr
. Like every ctypes
function interface, they have properties like argtypes
and restype
. I want to extend the classes allowing an additional property named some_param
and I thought, why not, let's try this with "getter" and "setter" methods - how hard can it be ...
Because I am trying to use "getter" and "setter" methods (@property
) on a property of a class (NOT a property of objects), I ended up writing a metaclass. Because my class is derived from ctypes._CFuncPtr
, I think my metaclass must be derived from ctypes._CFuncPtr.__class__
(I could be wrong here).
The example below works, sort of:
import ctypes
class a_class:
def b_function(self, some_param_parg):
class c_class_meta(ctypes._CFuncPtr.__class__):
def __init__(cls, *args):
super().__init__(*args) # no idea if this is good ...
cls._some_param_ = some_param_parg
@property
def some_param(cls):
return cls._some_param_
@some_param.setter
def some_param(cls, value):
if not isinstance(value, list):
raise TypeError('some_param must be a list')
cls._some_param_ = value
class c_class(ctypes._CFuncPtr, metaclass = c_class_meta):
_argtypes_ = ()
_restype_ = None
_flags_ = ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
return c_class
d_class = a_class().b_function([1, 2, 3])
print(d_class.some_param)
d_class.some_param = [2, 6]
print(d_class.some_param)
d_class.some_param = # Raises an error - as expected
So far so good - using the above any further does NOT work anymore. The following pseudo-code (if used on an actual function from a DLL or shared object) will fail - in fact, it will cause the CPython interpreter to segfault ...
some_routine = ctypes.windll.LoadLibrary('some.dll').some_routine
func_type = d_class(ctypes.c_int16, ctypes.c_int16) # similar to CFUNCTYPE/WINFUNCTYPE
func_type.some_param = [4, 5, 6] # my "special" property
some_routine.argtypes = (ctypes.c_int16, func_type)
@func_type
def demo(x):
return x - 1
some_routine(4, demo) # segfaults HERE!
I am not entirely sure what goes wrong. ctypes._CFuncPtr
is implemented in C, which could be a relevant limitation ... I could also have made a mistake in the implementation of the metaclass. Can someone enlighten me?
(For additional context, I am working on this function.)
python python-3.x ctypes metaclass
I am working on a ctypes
drop-in-replacement / extension and ran into an issue I do not fully understand.
I am trying to build a class factory for call-back function decorators similar to CFUNCTYPE and WINFUNCTYPE. Both factories produce classes derived from ctypes._CFuncPtr
. Like every ctypes
function interface, they have properties like argtypes
and restype
. I want to extend the classes allowing an additional property named some_param
and I thought, why not, let's try this with "getter" and "setter" methods - how hard can it be ...
Because I am trying to use "getter" and "setter" methods (@property
) on a property of a class (NOT a property of objects), I ended up writing a metaclass. Because my class is derived from ctypes._CFuncPtr
, I think my metaclass must be derived from ctypes._CFuncPtr.__class__
(I could be wrong here).
The example below works, sort of:
import ctypes
class a_class:
def b_function(self, some_param_parg):
class c_class_meta(ctypes._CFuncPtr.__class__):
def __init__(cls, *args):
super().__init__(*args) # no idea if this is good ...
cls._some_param_ = some_param_parg
@property
def some_param(cls):
return cls._some_param_
@some_param.setter
def some_param(cls, value):
if not isinstance(value, list):
raise TypeError('some_param must be a list')
cls._some_param_ = value
class c_class(ctypes._CFuncPtr, metaclass = c_class_meta):
_argtypes_ = ()
_restype_ = None
_flags_ = ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
return c_class
d_class = a_class().b_function([1, 2, 3])
print(d_class.some_param)
d_class.some_param = [2, 6]
print(d_class.some_param)
d_class.some_param = # Raises an error - as expected
So far so good - using the above any further does NOT work anymore. The following pseudo-code (if used on an actual function from a DLL or shared object) will fail - in fact, it will cause the CPython interpreter to segfault ...
some_routine = ctypes.windll.LoadLibrary('some.dll').some_routine
func_type = d_class(ctypes.c_int16, ctypes.c_int16) # similar to CFUNCTYPE/WINFUNCTYPE
func_type.some_param = [4, 5, 6] # my "special" property
some_routine.argtypes = (ctypes.c_int16, func_type)
@func_type
def demo(x):
return x - 1
some_routine(4, demo) # segfaults HERE!
I am not entirely sure what goes wrong. ctypes._CFuncPtr
is implemented in C, which could be a relevant limitation ... I could also have made a mistake in the implementation of the metaclass. Can someone enlighten me?
(For additional context, I am working on this function.)
python python-3.x ctypes metaclass
python python-3.x ctypes metaclass
edited Mar 24 at 17:33
s-m-e
asked Mar 24 at 17:20
s-m-es-m-e
1,57521839
1,57521839
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Maybe ctypes metaclasses simply won't work nicely being subclasses - since it is itself written in C, it may bypass the routes inheritance imposes for some shortcuts and end up in failures.
Ideally this "bad behavior" would have to be properly documented, filled as bugs against CPython's ctypes and fixed - to my knowledge there are not many people who can fix ctypes bugs.
On the other hand, having a metaclass just because you want a property-like attribute at class level is overkill.
Python's property
itself is just pre-made, very useful builtin class that implements the descriptor protocol. Any class you create yourself that implements proper __get__
and __set__
methods can replace "property" (and often, when logic is shared across property-attributes, leads to shorter, non duplicated code)
On a second though, unfortunately, descriptor setters will only work for instances, not for classes (which makes sense, since doing cls.attr
will already get you the special code-guarded value, and there is no way a __set__
method could be called on it)
So, if you could work with "manually" setting the values in the cls.__dict__
and putting your logic in the __get__
attribute, you could do:
PREFIX = "_cls_prop_"
class ClsProperty:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
value = owner.__dict__.get(PREFIX + self.name)
# Logic to transform/check value goes here:
if not isinstance(value, list):
raise TypeError('some_param must be a list')
return value
def b_function(some_param_arg):
class c_class(ctypes._CFuncPtr):
_argtypes_ = ()
_restype_ = None
_flags_ = 0 # ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
_some_param_ = ClsProperty()
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
return c_class
d_class = b_function([1, 2, 3])
print(d_class._some_param_)
d_class._some_param_ = [1, 2]
print(d_class._some_param_)
If that does not work, I don't think other approaches trying to extend CTypes metaclass will work anyway, but if you want a try, instead of a "meta-property", you might try to customize the metaclass' __setitem__
instead, to do your parameter checking, instead of using property
.
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The linec_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails withTypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?
– s-m-e
Mar 28 at 21:10
Yes - sorry for that -setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.
– jsbueno
Mar 29 at 19:13
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55326437%2fusing-a-metaclass-on-a-class-drived-from-another-class-implemented-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Maybe ctypes metaclasses simply won't work nicely being subclasses - since it is itself written in C, it may bypass the routes inheritance imposes for some shortcuts and end up in failures.
Ideally this "bad behavior" would have to be properly documented, filled as bugs against CPython's ctypes and fixed - to my knowledge there are not many people who can fix ctypes bugs.
On the other hand, having a metaclass just because you want a property-like attribute at class level is overkill.
Python's property
itself is just pre-made, very useful builtin class that implements the descriptor protocol. Any class you create yourself that implements proper __get__
and __set__
methods can replace "property" (and often, when logic is shared across property-attributes, leads to shorter, non duplicated code)
On a second though, unfortunately, descriptor setters will only work for instances, not for classes (which makes sense, since doing cls.attr
will already get you the special code-guarded value, and there is no way a __set__
method could be called on it)
So, if you could work with "manually" setting the values in the cls.__dict__
and putting your logic in the __get__
attribute, you could do:
PREFIX = "_cls_prop_"
class ClsProperty:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
value = owner.__dict__.get(PREFIX + self.name)
# Logic to transform/check value goes here:
if not isinstance(value, list):
raise TypeError('some_param must be a list')
return value
def b_function(some_param_arg):
class c_class(ctypes._CFuncPtr):
_argtypes_ = ()
_restype_ = None
_flags_ = 0 # ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
_some_param_ = ClsProperty()
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
return c_class
d_class = b_function([1, 2, 3])
print(d_class._some_param_)
d_class._some_param_ = [1, 2]
print(d_class._some_param_)
If that does not work, I don't think other approaches trying to extend CTypes metaclass will work anyway, but if you want a try, instead of a "meta-property", you might try to customize the metaclass' __setitem__
instead, to do your parameter checking, instead of using property
.
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The linec_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails withTypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?
– s-m-e
Mar 28 at 21:10
Yes - sorry for that -setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.
– jsbueno
Mar 29 at 19:13
add a comment |
Maybe ctypes metaclasses simply won't work nicely being subclasses - since it is itself written in C, it may bypass the routes inheritance imposes for some shortcuts and end up in failures.
Ideally this "bad behavior" would have to be properly documented, filled as bugs against CPython's ctypes and fixed - to my knowledge there are not many people who can fix ctypes bugs.
On the other hand, having a metaclass just because you want a property-like attribute at class level is overkill.
Python's property
itself is just pre-made, very useful builtin class that implements the descriptor protocol. Any class you create yourself that implements proper __get__
and __set__
methods can replace "property" (and often, when logic is shared across property-attributes, leads to shorter, non duplicated code)
On a second though, unfortunately, descriptor setters will only work for instances, not for classes (which makes sense, since doing cls.attr
will already get you the special code-guarded value, and there is no way a __set__
method could be called on it)
So, if you could work with "manually" setting the values in the cls.__dict__
and putting your logic in the __get__
attribute, you could do:
PREFIX = "_cls_prop_"
class ClsProperty:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
value = owner.__dict__.get(PREFIX + self.name)
# Logic to transform/check value goes here:
if not isinstance(value, list):
raise TypeError('some_param must be a list')
return value
def b_function(some_param_arg):
class c_class(ctypes._CFuncPtr):
_argtypes_ = ()
_restype_ = None
_flags_ = 0 # ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
_some_param_ = ClsProperty()
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
return c_class
d_class = b_function([1, 2, 3])
print(d_class._some_param_)
d_class._some_param_ = [1, 2]
print(d_class._some_param_)
If that does not work, I don't think other approaches trying to extend CTypes metaclass will work anyway, but if you want a try, instead of a "meta-property", you might try to customize the metaclass' __setitem__
instead, to do your parameter checking, instead of using property
.
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The linec_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails withTypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?
– s-m-e
Mar 28 at 21:10
Yes - sorry for that -setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.
– jsbueno
Mar 29 at 19:13
add a comment |
Maybe ctypes metaclasses simply won't work nicely being subclasses - since it is itself written in C, it may bypass the routes inheritance imposes for some shortcuts and end up in failures.
Ideally this "bad behavior" would have to be properly documented, filled as bugs against CPython's ctypes and fixed - to my knowledge there are not many people who can fix ctypes bugs.
On the other hand, having a metaclass just because you want a property-like attribute at class level is overkill.
Python's property
itself is just pre-made, very useful builtin class that implements the descriptor protocol. Any class you create yourself that implements proper __get__
and __set__
methods can replace "property" (and often, when logic is shared across property-attributes, leads to shorter, non duplicated code)
On a second though, unfortunately, descriptor setters will only work for instances, not for classes (which makes sense, since doing cls.attr
will already get you the special code-guarded value, and there is no way a __set__
method could be called on it)
So, if you could work with "manually" setting the values in the cls.__dict__
and putting your logic in the __get__
attribute, you could do:
PREFIX = "_cls_prop_"
class ClsProperty:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
value = owner.__dict__.get(PREFIX + self.name)
# Logic to transform/check value goes here:
if not isinstance(value, list):
raise TypeError('some_param must be a list')
return value
def b_function(some_param_arg):
class c_class(ctypes._CFuncPtr):
_argtypes_ = ()
_restype_ = None
_flags_ = 0 # ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
_some_param_ = ClsProperty()
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
return c_class
d_class = b_function([1, 2, 3])
print(d_class._some_param_)
d_class._some_param_ = [1, 2]
print(d_class._some_param_)
If that does not work, I don't think other approaches trying to extend CTypes metaclass will work anyway, but if you want a try, instead of a "meta-property", you might try to customize the metaclass' __setitem__
instead, to do your parameter checking, instead of using property
.
Maybe ctypes metaclasses simply won't work nicely being subclasses - since it is itself written in C, it may bypass the routes inheritance imposes for some shortcuts and end up in failures.
Ideally this "bad behavior" would have to be properly documented, filled as bugs against CPython's ctypes and fixed - to my knowledge there are not many people who can fix ctypes bugs.
On the other hand, having a metaclass just because you want a property-like attribute at class level is overkill.
Python's property
itself is just pre-made, very useful builtin class that implements the descriptor protocol. Any class you create yourself that implements proper __get__
and __set__
methods can replace "property" (and often, when logic is shared across property-attributes, leads to shorter, non duplicated code)
On a second though, unfortunately, descriptor setters will only work for instances, not for classes (which makes sense, since doing cls.attr
will already get you the special code-guarded value, and there is no way a __set__
method could be called on it)
So, if you could work with "manually" setting the values in the cls.__dict__
and putting your logic in the __get__
attribute, you could do:
PREFIX = "_cls_prop_"
class ClsProperty:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
value = owner.__dict__.get(PREFIX + self.name)
# Logic to transform/check value goes here:
if not isinstance(value, list):
raise TypeError('some_param must be a list')
return value
def b_function(some_param_arg):
class c_class(ctypes._CFuncPtr):
_argtypes_ = ()
_restype_ = None
_flags_ = 0 # ctypes._FUNCFLAG_STDCALL # change for CFUNCTYPE or WINFUNCTYPE etc ...
_some_param_ = ClsProperty()
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
return c_class
d_class = b_function([1, 2, 3])
print(d_class._some_param_)
d_class._some_param_ = [1, 2]
print(d_class._some_param_)
If that does not work, I don't think other approaches trying to extend CTypes metaclass will work anyway, but if you want a try, instead of a "meta-property", you might try to customize the metaclass' __setitem__
instead, to do your parameter checking, instead of using property
.
edited Mar 29 at 19:14
answered Mar 25 at 15:00
jsbuenojsbueno
58.5k684133
58.5k684133
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The linec_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails withTypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?
– s-m-e
Mar 28 at 21:10
Yes - sorry for that -setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.
– jsbueno
Mar 29 at 19:13
add a comment |
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The linec_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails withTypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?
– s-m-e
Mar 28 at 21:10
Yes - sorry for that -setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.
– jsbueno
Mar 29 at 19:13
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The line
c_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails with TypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?– s-m-e
Mar 28 at 21:10
Thanks a lot for the answer. I thought I would not get one at all. Actually, it was an answer of yours to a question of mine that inspired the whole mad project, so thanks for that too ;) I (mildly) edited the code in your answer to reflect how it should look like AFAIK (?), but it still does not work. The line
c_class.__dict__[PREFIX + '_some_param_'] = some_param_arg
fails with TypeError: 'mappingproxy' object does not support item assignment
. I have not yet managed to make some sense of it. What do I have to do to complete the example?– s-m-e
Mar 28 at 21:10
Yes - sorry for that -
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.– jsbueno
Mar 29 at 19:13
Yes - sorry for that -
setattr(c_class, PREFIX + "_some_param_", some_param_arg)
should work there.– jsbueno
Mar 29 at 19:13
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55326437%2fusing-a-metaclass-on-a-class-drived-from-another-class-implemented-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown