Workaround for not having __set_name__ in Python versions before 3.6
up vote
3
down vote
favorite
In Python 3.6, I can use the __set_name__
hook to get the class attribute name of a descriptor. How can I achieve this in python 2.x?
This is the code which works fine in Python 3.6:
class IntField:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def __set_name__(self, owner, name):
self.name = name
class Example:
a = IntField()
python python-2.7
add a comment |
up vote
3
down vote
favorite
In Python 3.6, I can use the __set_name__
hook to get the class attribute name of a descriptor. How can I achieve this in python 2.x?
This is the code which works fine in Python 3.6:
class IntField:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def __set_name__(self, owner, name):
self.name = name
class Example:
a = IntField()
python python-2.7
I edited your question a little.__set_name__
was introduced in 3.6.
– timgeb
Nov 10 at 18:23
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
In Python 3.6, I can use the __set_name__
hook to get the class attribute name of a descriptor. How can I achieve this in python 2.x?
This is the code which works fine in Python 3.6:
class IntField:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def __set_name__(self, owner, name):
self.name = name
class Example:
a = IntField()
python python-2.7
In Python 3.6, I can use the __set_name__
hook to get the class attribute name of a descriptor. How can I achieve this in python 2.x?
This is the code which works fine in Python 3.6:
class IntField:
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def __set_name__(self, owner, name):
self.name = name
class Example:
a = IntField()
python python-2.7
python python-2.7
edited Nov 10 at 18:21
timgeb
43.6k106085
43.6k106085
asked Nov 10 at 17:35
Naga
566
566
I edited your question a little.__set_name__
was introduced in 3.6.
– timgeb
Nov 10 at 18:23
add a comment |
I edited your question a little.__set_name__
was introduced in 3.6.
– timgeb
Nov 10 at 18:23
I edited your question a little.
__set_name__
was introduced in 3.6.– timgeb
Nov 10 at 18:23
I edited your question a little.
__set_name__
was introduced in 3.6.– timgeb
Nov 10 at 18:23
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
accepted
You may be looking for metaclasses, with it you can process the class attributes at class creation time.
class FooDescriptor(object):
def __get__(self, obj, objtype):
print('calling getter')
class FooMeta(type):
def __init__(cls, name, bases, attrs):
for k, v in attrs.iteritems():
if issubclass(type(v), FooDescriptor):
print('FooMeta.__init__, attribute name is "{}"'.format(k))
class Foo(object):
__metaclass__ = FooMeta
foo = FooDescriptor()
f = Foo()
f.foo
Output:
FooMeta.__init__, attribute name is "foo"
calling getter
If you need to change the class before it is created you need to override __new__
instead of __init__
at your metaclass. See this answer for more information on this topic: Is there any reason to choose __new__ over __init__ when defining a metaclass?
add a comment |
up vote
1
down vote
There are various solutions with different degrees of hackishness. I always liked to use a class decorator for this.
class IntField(object):
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def with_intfields(*names):
def with_concrete_intfields(cls):
for name in names:
field = IntField()
field.name = name
setattr(cls, name, field)
return cls
return with_concrete_intfields
You can use it like this:
@with_intfields('a', 'b')
class Example(object):
pass
e = Example()
Demo:
$ python2.7 -i clsdec.py
>>> [x for x in vars(Example) if not x.startswith('_')]
['a', 'b']
>>> Example.a.name
'a'
>>> e.a = 3
>>> e.b = 'test'
[...]
ValueError: expecting integer
Make sure to explicitly subclass from object
in Python 2.7, that got me tripped up when I drafted the first version of this answer.
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
You may be looking for metaclasses, with it you can process the class attributes at class creation time.
class FooDescriptor(object):
def __get__(self, obj, objtype):
print('calling getter')
class FooMeta(type):
def __init__(cls, name, bases, attrs):
for k, v in attrs.iteritems():
if issubclass(type(v), FooDescriptor):
print('FooMeta.__init__, attribute name is "{}"'.format(k))
class Foo(object):
__metaclass__ = FooMeta
foo = FooDescriptor()
f = Foo()
f.foo
Output:
FooMeta.__init__, attribute name is "foo"
calling getter
If you need to change the class before it is created you need to override __new__
instead of __init__
at your metaclass. See this answer for more information on this topic: Is there any reason to choose __new__ over __init__ when defining a metaclass?
add a comment |
up vote
1
down vote
accepted
You may be looking for metaclasses, with it you can process the class attributes at class creation time.
class FooDescriptor(object):
def __get__(self, obj, objtype):
print('calling getter')
class FooMeta(type):
def __init__(cls, name, bases, attrs):
for k, v in attrs.iteritems():
if issubclass(type(v), FooDescriptor):
print('FooMeta.__init__, attribute name is "{}"'.format(k))
class Foo(object):
__metaclass__ = FooMeta
foo = FooDescriptor()
f = Foo()
f.foo
Output:
FooMeta.__init__, attribute name is "foo"
calling getter
If you need to change the class before it is created you need to override __new__
instead of __init__
at your metaclass. See this answer for more information on this topic: Is there any reason to choose __new__ over __init__ when defining a metaclass?
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
You may be looking for metaclasses, with it you can process the class attributes at class creation time.
class FooDescriptor(object):
def __get__(self, obj, objtype):
print('calling getter')
class FooMeta(type):
def __init__(cls, name, bases, attrs):
for k, v in attrs.iteritems():
if issubclass(type(v), FooDescriptor):
print('FooMeta.__init__, attribute name is "{}"'.format(k))
class Foo(object):
__metaclass__ = FooMeta
foo = FooDescriptor()
f = Foo()
f.foo
Output:
FooMeta.__init__, attribute name is "foo"
calling getter
If you need to change the class before it is created you need to override __new__
instead of __init__
at your metaclass. See this answer for more information on this topic: Is there any reason to choose __new__ over __init__ when defining a metaclass?
You may be looking for metaclasses, with it you can process the class attributes at class creation time.
class FooDescriptor(object):
def __get__(self, obj, objtype):
print('calling getter')
class FooMeta(type):
def __init__(cls, name, bases, attrs):
for k, v in attrs.iteritems():
if issubclass(type(v), FooDescriptor):
print('FooMeta.__init__, attribute name is "{}"'.format(k))
class Foo(object):
__metaclass__ = FooMeta
foo = FooDescriptor()
f = Foo()
f.foo
Output:
FooMeta.__init__, attribute name is "foo"
calling getter
If you need to change the class before it is created you need to override __new__
instead of __init__
at your metaclass. See this answer for more information on this topic: Is there any reason to choose __new__ over __init__ when defining a metaclass?
edited Nov 10 at 18:14
answered Nov 10 at 18:08
geckos
722615
722615
add a comment |
add a comment |
up vote
1
down vote
There are various solutions with different degrees of hackishness. I always liked to use a class decorator for this.
class IntField(object):
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def with_intfields(*names):
def with_concrete_intfields(cls):
for name in names:
field = IntField()
field.name = name
setattr(cls, name, field)
return cls
return with_concrete_intfields
You can use it like this:
@with_intfields('a', 'b')
class Example(object):
pass
e = Example()
Demo:
$ python2.7 -i clsdec.py
>>> [x for x in vars(Example) if not x.startswith('_')]
['a', 'b']
>>> Example.a.name
'a'
>>> e.a = 3
>>> e.b = 'test'
[...]
ValueError: expecting integer
Make sure to explicitly subclass from object
in Python 2.7, that got me tripped up when I drafted the first version of this answer.
add a comment |
up vote
1
down vote
There are various solutions with different degrees of hackishness. I always liked to use a class decorator for this.
class IntField(object):
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def with_intfields(*names):
def with_concrete_intfields(cls):
for name in names:
field = IntField()
field.name = name
setattr(cls, name, field)
return cls
return with_concrete_intfields
You can use it like this:
@with_intfields('a', 'b')
class Example(object):
pass
e = Example()
Demo:
$ python2.7 -i clsdec.py
>>> [x for x in vars(Example) if not x.startswith('_')]
['a', 'b']
>>> Example.a.name
'a'
>>> e.a = 3
>>> e.b = 'test'
[...]
ValueError: expecting integer
Make sure to explicitly subclass from object
in Python 2.7, that got me tripped up when I drafted the first version of this answer.
add a comment |
up vote
1
down vote
up vote
1
down vote
There are various solutions with different degrees of hackishness. I always liked to use a class decorator for this.
class IntField(object):
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def with_intfields(*names):
def with_concrete_intfields(cls):
for name in names:
field = IntField()
field.name = name
setattr(cls, name, field)
return cls
return with_concrete_intfields
You can use it like this:
@with_intfields('a', 'b')
class Example(object):
pass
e = Example()
Demo:
$ python2.7 -i clsdec.py
>>> [x for x in vars(Example) if not x.startswith('_')]
['a', 'b']
>>> Example.a.name
'a'
>>> e.a = 3
>>> e.b = 'test'
[...]
ValueError: expecting integer
Make sure to explicitly subclass from object
in Python 2.7, that got me tripped up when I drafted the first version of this answer.
There are various solutions with different degrees of hackishness. I always liked to use a class decorator for this.
class IntField(object):
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError('expecting integer')
instance.__dict__[self.name] = value
def with_intfields(*names):
def with_concrete_intfields(cls):
for name in names:
field = IntField()
field.name = name
setattr(cls, name, field)
return cls
return with_concrete_intfields
You can use it like this:
@with_intfields('a', 'b')
class Example(object):
pass
e = Example()
Demo:
$ python2.7 -i clsdec.py
>>> [x for x in vars(Example) if not x.startswith('_')]
['a', 'b']
>>> Example.a.name
'a'
>>> e.a = 3
>>> e.b = 'test'
[...]
ValueError: expecting integer
Make sure to explicitly subclass from object
in Python 2.7, that got me tripped up when I drafted the first version of this answer.
edited Nov 10 at 18:08
answered Nov 10 at 17:55
timgeb
43.6k106085
43.6k106085
add a comment |
add a comment |
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%2f53241645%2fworkaround-for-not-having-set-name-in-python-versions-before-3-6%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
I edited your question a little.
__set_name__
was introduced in 3.6.– timgeb
Nov 10 at 18:23