To get a string representation of a class name we can use obj.__class__.__name__ is it possible to overload these methods so that I can return my string instead of the actual class name?
Let's try! (Yes, this works):
>>> class Foo(object):
... pass
...
>>> obj = Foo()
>>> obj.__class__.__name__ = 'Bar'
>>> obj
<__main__.Bar object at 0x7fae8ba3af90>
>>> obj.__class__
<class '__main__.Bar'>
You could also have just done Foo.__name__ = 'Bar', I used obj.__class__.__name__ to be consistent with your question.
Yep.
class A:
def __init__(self):
self.__class__.__name__ = 'B'
But this seems like a bad idea.
You can do this:
>>> class Foo(object):
... def __init__(self):
... self.__class__.__name__ = "Bar"
...
>>> print Foo().__class__.__name__
Bar
Or you can make your own double underscore attribute.
>>> class Foo(object):
... __name__ = "Bar"
...
>>> print Foo().__name__
Bar
But why would you want to do this? I don't see any possible use for this. BTW, I realize this is not the same as __class__.__name__, but I don't think changing __class__.__name__ is generally a good idea.
Related
I can make a synthetic class cls1 that inherits from cls.
>>> class cls(object):
... def func(self,arg):
... print 'func',arg
>>> def func1(self):
... print "func 1 of cls1"
>>> def func2(self):
... print "func2 of cls1"
>>> d=dict(func1=func1,func2=func2)
>>> cls1=type('cls1',(cls,),d)
Everything works as expected:
>>> obj=cls1()
>>> obj.func(7)
func 7
I can also replace cls1 with FOO:
>>> cls1=type('FOO',(cls,),d)
that gives me:
'cls1': <class '__main__.FOO'>,
Does this (changing __name__ variable) alter the behavior of cls1 and how (everything still works fine)?
You're just changing the name of your class, so it should matter only if you rely on the name somehow:
>>> type(obj)
__main__.FOO
>>> isintance(obj, cls1)
True
That works fine, but what about pickling (that I think rely on the name) ?
For example, before the name change, you can pickle obj without any problem. You can't afterwards.
PicklingError: Can't pickle <class '__main__.FOO'>: it's not found as __main__.FOO
Maybe the title is a little screwed up but is there a way to make an instance of a class inside the same class in Python?
Something like this:
class Foo:
foo = Foo()
I know that the interpreter says that Foo is not declared but is there a way to achieve this?
Update:
This is what I'm trying to do:
class NPByteRange (Structure):
_fields_ = [ ('offset', int32),
('lenght', uint32),
('next', POINTER(NPByteRange)) ]
The interpreter only minds if you try to do it in a context where Foo is not declared. There are contexts where it is. The simplest example is in a method:
>>> class Beer(object):
... def have_another(self):
... return Beer()
...
>>> x=Beer()
>>> x.have_another()
<__main__.Beer object at 0x10052e390>
If its important that the object be a property, you can just use the property builtin.
>>> class Beer(object):
... #property
... def another(self):
... return Beer()
...
>>> guinness=Beer()
>>> guinness.another
<__main__.Beer object at 0x10052e610>
Finally, if it's truly necessary that it be a class property, well, you can do that, too.
Let's say I have a class like this:
class Test(object):
prop = property(lambda self: "property")
The descriptor takes priority whenever I try to access Test().prop. So that will return 'property'. If I want to access the object's instance storage, I can do:
x = Test()
x.__dict__["prop"] = 12
print(x.__dict__["prop"])
However if I change my class to:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
How do I do the same, and access the internal storage of x, to write 12 and read it back, since x.__dict__ no longer exist?
I am fairly new with Python, but I understand the Python philosophy is to give complete control, so why is an implementation detail preventing me from doing that?
Isn't Python missing a built-in function that could read from an instance internal storage, something like:
instance_vars(x)["prop"] = 12
print(instance_vars(x)["prop"])
which would work like vars, except it also works with __slots__, and with built-in types that don't have a __dict__?
Short answer, You can't
The problem is that slots are themselves implemented in terms of descriptors. Given:
class Test(object):
__slots__ = ("prop",)
t = Test()
the phrase:
t.prop
Is translated, approximately to:
Test.prop.__get__(t, Test)
where Test.prop is a <type 'member_descriptor'> crafted by the run-time specifically to load prop values out of Test instances from their reserved space.
If you add another descriptor to the class body definition, it masks out the member_descriptor that would let you get to the slotted attribute; there's no way to ask for it, it's just not there anymore. It's effectively like saying:
class Test(object):
#property
def prop(self):
return self.__dict__['prop']
#property
def prop(self):
return "property"
You've defined it twice. there's no way to "get at" the first prop definition.
but:
Long answer, you can't in a general way. You can
You can still abuse the python type system to get at it using another class definition. You can change the type of a python object, so long as it has the exact same class layout, which roughly means that it has all of the same slots:
>>> class Test1(object):
... __slots__ = ["prop"]
... prop = property(lambda self: "property")
...
>>> class Test2(object):
... __slots__ = ["prop"]
...
>>> t = Test1()
>>> t.prop
'property'
>>> t.__class__ = Test2
>>> t.prop = 5
>>> t.prop
5
>>> t.__class__ = Test1
>>> t.prop
'property'
But there's no general way to introspect an instance to work out its class layout; you just have to know from context. You could look at it's __slots__ class attribute, but that won't tell you about the slots provided in the superclass (if any) nor will it give you any hint if that attribute has changed for some reason after the class was defined.
I don't quite understand what and why you want to do this, but does this help you?
>>> class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
>>> a = Test()
>>> b = Test()
>>> a.prop
'property'
>>> tmp = Test.prop
>>> Test.prop = 23
>>> a.prop
23
>>> Test.prop = tmp; del tmp
>>> b.prop
'property'
of course, you cannot overwrite the property on a per-instance basis, that's the whole point of slotted descriptors.
Note that subclasses of a class with __slots__ do have a __dict__ unless you manually define __slots__, so you can do:
>>> class Test2(Test):pass
>>> t = Test2()
>>> t.prop
'property'
>>> t.__dict__['prop'] = 5
>>> t.__dict__['prop']
5
>>> Test2.prop
<property object at 0x00000000032C4278>
but still:
>>> t.prop
'property'
and that's not because of __slots__, it's the way descriptors work.
your __dict__ is bypassed on attribute lookup, you are just abusing it as data structure that happens to be there for storing a state.
it is equivalent to do this:
>>> class Test(object):
__slots__ = ("prop", "state")
prop = property(lambda self: "property")
state = {"prop": prop}
>>> t.prop
'property'
>>> t.state["prop"] = 5
>>> t.state["prop"]
5
>>> t.prop
'property'
If you really ever want to do something like that, and you REALL REALLY need something like that, you can always override __getattribute__ and __setattribute__, it's just as stupid... This is just to prove it to you:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
__internal__ = {}
def __getattribute__(self, k):
if k == "__dict__":
return self.__internal__
else:
try:
return object.__getattribute__(self, k)
except AttributeError, e:
try:
return self.__internal__[k]
except KeyError:
raise e
def __setattribute__(self, k, v):
self.__internal__[k] = v
object.__setattribute__(self, k, v)
t = Test()
print t.prop
t.__dict__["prop"] = "test"
print "from dict", t.__dict__["prop"]
print "from getattr", t.prop
import traceback
# These won't work: raise AttributeError
try:
t.prop2 = "something"
except AttributeError:
print "see? I told you!"
traceback.print_exc()
try:
print t.prop2
except AttributeError:
print "Haha! Again!"
traceback.print_exc()
(Tried it on Python 2.7)
It's exactly what you expect I guess. Don't do this, it's useless.
I have a two part question.
>>> class One(object):
... pass
...
>>> class Two(object):
... pass
...
>>> def digest(constr):
... c = apply(constr)
... print c.__class__.__name__
... print constr.__class__.__name__
...
>>> digest(Two)
Two
type
How would one create object 'Two'? Neither constr() or c() work; and it seems that apply turns it into a type.
What happens when you pass a class rather and an instance into a method?
Classes are high level objects, so you can simply pass them like this:
def createMyClass ( myClass ):
obj = myClass()
return obj
class A ( object ):
pass
>>> x = createMyClass( A )
>>> type( x )
<class '__main__.A'>
How would one create object 'Two'?
Neither constr() or c() work; and it
seems that apply turns it into a
type.
The above comment was made in regards to this code:
>>> def digest(constr):
... c = apply(constr)
... print c.__class__.__name__
... print constr.__class__.__name__
apply (deprecated: see #pyfunc's answer) certainly does not turn the class Two into a type: It already is one.
>>> class Two(object): pass
...
>>> type(Two)
<type 'type'>
Classes are first class objects: they're instances of type. This makes sense if you look at the next example.
>>> two = Two()
>>> type(two)
<class '__main__.Two'>
You can see that a class very clearly functions as a type because it can be returned from type. Here's another example.
>>> Three = type('Three', (Two, ), {'foo': 'bar'})
>>> type(Three)
<type 'type'>
>>> three = Three()
>>> type(three)
<class '__main__.Three'>
You can see that type is a class that can be instantiated. Its constructor takes three arguments: the name of the class, a tuple of base classes and a dictionary containing the class attributes. It returns a new type aka class.
As to your final question,
What happens when you pass a class
rather and an instance into a method?
You're going to have to be more specific. Classes are just instances of type and so are first class objects. Asking what happens if I pass a class into a method is like asking what happens if I pass an integer into a method: It depends entirely on what the method is expecting.
Just another one example:
def InstanceFactory(classname):
cls = globals()[classname]
return cls()
class A(object):
def start(self):
print "a.start"
class B(object):
def start(self):
print "b.start"
InstanceFactory("A").start()
InstanceFactory("B").start()
If the class belongs to another module:
def InstanceFactory(modulename, classname):
if '.' in modulename:
raise ValueError, "can't handle dotted modules yet"
mod = __import__(modulename)
cls = getattr(mod, classname]
return cls()
I am confused though. Wasn't apply() deprecated since 2.3
http://www.python.org/dev/peps/pep-0290/
We don't need this any more.
apply(f, args, kwds) --> f(*args, **kwds)
Others have been moved / considered deprecated in modern usage:
buffer()
coerce()
and intern()
Simply use : Classname() to create an object.
I'm sorry for my silly question, but... let's suppose I have these classes:
class A():
msg = 'hehehe'
class B(A):
msg = 'hohoho'
class C(B):
pass
and an instance of B or C. How do I get the variable 'msg' from the parent's class object through this instance?
I've tried this:
foo = B()
print super(foo.__class__).msg
but got the message: "TypeError: super() argument 1 must be type, not classobj".
You actually want to use
class A(object):
...
...
b = B()
bar = super(b.__class__, b)
print bar.msg
Base classes must be new-style classes (inherit from object)
If the class is single-inherited:
foo = B()
print foo.__class__.__bases__[0].msg
# 'hehehe'
If the class is multiple-inherited, the question makes no sense because there may be multiple classes defining the 'msg', and they could all be meaningful. You'd better provide the actual parent (i.e. A.msg). Alternatively you could iterate through all direct bases as described in #Felix's answer.
Not sure why you want to do this
>>> class A(object):
... msg = 'hehehe'
...
>>> class B(A):
... msg = 'hohoho'
...
>>> foo=B()
>>> foo.__class__.__mro__[1].msg
'hehehe'
>>>
As msg is a class variable, you can just do:
print C.msg # prints hohoho
If you overwrite the variable (as you do in class B), you have to find the right parent class. Remember that Python supports multiple inheritance.
But as you define the classes and you now that B inherits from A you can always do this:
class B(A):
msg = 'hohoho'
def get_parent_message(self):
return A.msg
UPDATE:
The most reliable thing would be:
def get_parent_attribute(instance, attribute):
for parent in instance.__class__.__bases__:
if attribute in parent.__dict__:
return parent.__dict__[attribute]
and then:
foo = B()
print get_parent_attribute(foo, 'msg')
Try with:
class A(object):
msg = 'hehehe'
EDIT:
For the 'msg' attribute you would need:
foo = B()
bar = super(foo.__class__, foo)
print bar.msg
#for B() you can use __bases__
print foo.__class__.__bases__[0].msg
But this is not gonna be easy when there are multiple base classes and/or the depth of hierarchy is not one.