I understood python descriptor but I have a little confusion about this..
if you have a class descriptor as follows
class Descriptor(object):
def __get__(self, instance, owner):
print 'getting'
return self.value
def __set__(self, instance, value):
print 'setting'
self.value = value
def __delete__(self, instance):
print 'deleting'
del self.value
and a class whose attributes we want to manage is something like this..
class Test(object):
name = Descriptor()
def __init__(self, name):
print 'init test'
self.name = name
when I create object of class Test and do something it gives me answer like this...
t = Test('abc')
init test
setting
>>> t.name
getting
'abc'
>>> del t.name
deleting
>>> t
<__main__.Test object at 0x013FCCD0>
>>> t.name
getting
Now I want to have a class Test1 something like this..
class Test1(object):
def __init__(self, value):
print 'init test1'
self.name = Descriptor()
self. value = value
and if I create object of Test1 and try to access attribute of instance of Test1, I get output something like this..
t1 = Test1(12)
t1.name
>>> getting
>>> 12
>>> t1.name = 30
>>> setting
Q 1) my question is that is this name attribute declared in init of Test1, is bound to instance of Test1 or not... because when I try to get attribute dictionary of t1, it return empty dict...
t1.__dict__
>>> {}
same for class Test's instance t
t.__dict__
>>> {}
When I add a new attribute to any of these instances, like this...
t.some = 'some'
>>> t1.some = 'some'
and again if I try to access attribute dictionary it gives me only which I have added just now.. now all instance attribute
t.__dict__
>>> {'some': 'some'}
>>> t1.__dict__
>>> {'some': 'some'}
Q 2) So what is the difference between instance attributes defined in init (like variable name and value in class Descriptor and Test) and attributes defined after instance creation (like variable t.some).
Q 3) How class Test is different than class Test1.
In Test1 your Descriptor isn't really used as a descriptor, it's just a normal attribute called name, that happens to have some the special methods. But that doensn't really make it a descriptor yet.
If you read the docs about how descriptors are invoked, youll see the mechanism that is used to invoke the descriptors methods. In your case this would mean t.name woud be roughly equivalent to:
type(t).__dict__['name'].__get__(t, type(t))
and t1.name:
type(t1).__dict__['name'].__get__(t1, type(t1))
name is looked up in the __dict__ of the class, not of the instance, so that's where the difference is, Test1.__dict__ doesn't have a descriptor called name:
>>> Test.__dict__['name']
<__main__.Descriptor object at 0x7f637a57bc90>
>>> Test1.__dict__['name']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'name'
What you also should consider, is that your descriptor sets the value attribute on itself, that means all instances of Test will share the same value:
>>> t1 = Test(1)
init test
setting
>>> t2 = Test(2)
init test
setting
>>> t1.name
getting
2
>>> t2.name
getting
2
>>> t1.name = 0
setting
>>> t2.name
getting
0
I think that what yo acutally want to do is to set value on instance instead of self, that would get you the expected behaviour in Test.
Related
I am new to Python and I inherited someone's code that had the following code structure. Why do I get an object not callable and how can I redefine this method again even after re-assigning l.bar. Another question would therefore be what's the difference between l.bar and l.bar()?
>>> class foo(object):
... def __init__(self):
... self.name = "Food"
... class bar(object):
... def __init__(self):
... self.name = "Is"
... class tea(object):
... def __init__(self):
... self.name = "Good"
...
>>> l = foo()
>>> m = l.bar()
>>> m.name = "Was"
>>> l.bar = m
>>> r = l.bar()
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'bar' object is not callable
As others have pointed out, it's generally not good practice to have nested classes. But, here's a breakdown of what's happening:
class foo(object):
def __init__(self):
self.name = "Food"
class bar(object):
def __init__(self):
self.name = "Is"
class tea(object):
def __init__(self):
self.name = "Good"
l = foo() # l is now an instance of foo
print l.name # "Food"
m = l.bar() # m is now an instance of bar
print m.name # "Is"
m.name = "Was" # you've assigned m's name to "Was"
print m.name # "Was"
l.bar = m # you are overriding foo's nested bar class now with an instance of bar
print l.name # "Food"
print l.bar # <__main__.bar object at 0x108371ad0>: this is now an instance, not a class
print l.bar.name # "Was"
r = l.bar() # you are now trying to call an instance of bar
The last line doesn't work because of the same reasons calling l() or foo()() doesn't work.
If you absolutely must figure out a way to make foo.bar().name return something else, you can create a new class and reassign foo.bar to it. But, this is really gross and not recommended. Hopefully, you can just change that original code.
print foo.bar().name # "Is"
class NewBar(object):
def __init__(self):
self.name = 'Was'
foo.bar = NewBar
print foo.bar().name # "Was"
Why do i get an object not callable
You assigned l.bar to be an instance of the class foo.bar (specifically, you assigned m to it). Instances of that class aren't callable, therefore l.bar isn't callable.
how can i redefine this method again even after re-assigning l.bar
Maybe this advice is too obvious, but don't re-assign l.bar.
However, you can reset l.bar so that it refers to the method it originally referred to, by doing del l.bar.
The reason this works is because if the individual object has no bar attribute of its own, then Python looks next to see whether its class has an attribute of the same name. So, to begin with the expression l.bar evaluates to the class foo.bar, since l has type foo. Then you assigned l a bar attribute of its own, so l.bar suddenly starts evaluating to that object instead. You can restore normality by deleting the object's own attribute.
what's the difference between l.bar and l.bar()
l.bar just gets the value of the attribute bar from the object l (or from its class, if the object l doesn't have one of its own, as explained above. If that fails too it'd go to base classes). l.bar() gets the value of that attribute and then calls it. () at this position means a function call, so the thing you put it after had better be callable.
It is not clear which of the following problems you are experiencing:
1. indentation issue
When copy-pasting from source to terminal, indentation sometimes gets messed up. in ipython you can use %paste to safely paste code.
The correctly indented class declarations are:
class foo(object):
def __init__(self):
self.name = "Food"
class bar(object):
def __init__(self):
self.name = "Is"
class tea(object):
def __init__(self):
self.name = "Good"
But then the other commands make no sense.
2. instance is not the same as class
When defining a class inside a class, you have to use the outer class name to "get" to the inner class name. I.e.:
class foo(object):
def __init__(self):
self.name = "Food"
class bar(object):
def __init__(self):
self.name = "Is"
class tea(object):
def __init__(self):
self.name = "Good"
foo_inst = foo()
bar_inst = foo.bar()
tea_inst = foo.bar.tea()
Anyhow, these lines still make not much sense:
>>> l.bar = m
>>> r = l.bar()
Why would you want to override bar which is (was) a class name...
For example, we have a class:
class A:
def __init__(self, a):
self.a = a
what is the function call to replace:
A.a
I want to apply it with map function.
Your question is not very clear but if you want to change the value of A.a in python it is as simple as
A.a = "New Value"
From what I've read from the python documentation, it seems that you can do that without the need of setter() and getter() function like other languages. I took this example from the link hyperlinked above.
class Employee:
pass
john = Employee() # Create an empty employee record
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
The functional equivalent of doing class.attribute is to use getattr(class, 'attribute'):
>>> class A:
... def __init__(self, a):
... self.a = a
...
>>> obj = A(1)
>>> obj.a
1
>>> getattr(obj, 'a')
1
>>>
From the documentation:
getattr(object, name[, default])
Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s
attributes, the result is the value of that attribute. For example,
getattr(x, 'foobar') is equivalent to x.foobar. If the named
attribute does not exist, default is returned if provided, otherwise
AttributeError is raised.
So I don't come from a computer science background and I am having trouble googling/SO searching on the right terms to answer this question. If I have a Python class with a class variable objects like so:
class MyClass(object):
objects = None
pass
MyClass.objects = 'test'
print MyClass.objects # outputs 'test'
a = MyClass()
print a.objects # also outputs 'test'
both the class and instances of the class will have access to the objects variable. I understand that I can change the instance value like so:
a.objects = 'bar'
print a.objects # outputs 'bar'
print MyClass.objects # outputs 'test'
but is it possible to have a class variable in Python that is accessible to users of the class (i.e. not just from within the class) but not accessible to the instances of that class? I think this is called a private member or static member in other languages?
Python is designed to allow instances of a class to access that class's attributes through the instance.
This only goes one level deep, so you can use a metaclass:
class T(type):
x = 5
class A(object):
__metaclass__ = T
Note that the metaclass syntax is different in Python 3. This works:
>>> A.x
5
>>> A().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'
It doesn't prevent you setting the attribute on instances of the class, though; to prevent that you'd have to play with __setattr__ magic method:
class A(object):
x = 1
def __getattribute__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__getattribute__(name)
def __setattr__(self, name, value):
if name == 'x':
raise AttributeError
return super(A, self).__setattr__(name, value)
def __delattr__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__delattr__(name)
The simplest way of achieving it is to use a descriptor. Descriptors are the thing meant for giving a higher level of control over attribute access. For example:
class ClassOnly(object):
def __init__(self, name, value):
self.name = name
self.value = value
def __get__(self, inst, cls):
if inst is not None:
msg = 'Cannot access class attribute {} from an instance'.format(self.name)
raise AttributeError(msg)
return self.value
class A(object):
objects = ClassOnly('objects', [])
Used as:
In [11]: a = A()
In [12]: a.objects
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-24afc67fd0ba> in <module>()
----> 1 a.objects
<ipython-input-9-db6510cd313b> in __get__(self, inst, cls)
5 def __get__(self, inst, cls):
6 if inst is not None:
----> 7 raise AttributeError('Cannot access class attribute {} from an instance'.format(self.name))
8 return self.value
AttributeError: Cannot access class attribute objects from an instance
In [13]: A.objects
Out[13]: []
If you want there to be a "single source of truth" for objects, you could make it a mutable type:
class MyClass(object):
objects = []
With immutable types, the fact that each instance starts out with the same reference from MyClass is irrelevant, as the first time that attribute is changed for the instance, it becomes "disconnected" from the class's value.
However, if the attribute is mutable, changing it in an instance changes it for the class and all other instances of the class:
>>> MyClass.objects.append(1)
>>> MyClass.objects
[1]
>>> a = MyClass()
>>> a.objects
[1]
>>> a.objects.append(2)
>>> a.objects
[1, 2]
>>> MyClass.objects
[1, 2]
In Python, nothing is really "private", so you can't really prevent the instances from accessing or altering objects (in that case, is it an appropriate class attribute?), but it is conventional to prepend names with an underscore if you don't ordinarily want them to be accessed directly: _objects.
One way to actually protect objects from instance access would be to override __getattribute__:
def __getattribute__(self, name):
if name == "objects":
raise AttributeError("Do not access 'objects' though MyClass instances.")
return super(MyClass, self).__getattribute__(name)
>>> MyClass.objects
[1]
>>> a.objects
...
AttributeError: Do not access 'objects' though MyClass instances.
No, you can't (EDIT: you can't in a way that is completely unaccessible, like in Java or C++).
You can do this, if you like:
class MyClass(object):
objects = None
pass
MyClass_objects = 'test'
print MyClass_objects # outputs 'test'
a = MyClass()
print a.objects # outputs 'None'
or this:
in your_module.py:
objects = 'test'
class MyClass(object):
objects = None
pass
in yourapp.py:
import your_module
print your_module.objects # outputs 'test'
a = your_module.MyClass()
print a.objects # outputs 'None'
the reason is:
When you create an instance of some class there is nothing to prevent
you from poking around inside and using various internal, private
methods that are (a) necessary for the class to function, BUT (b) not
intended for direct use/access.
Nothing is really private in python. No class or class instance can
keep you away from all what's inside (this makes introspection
possible and powerful). Python trusts you. It says "hey, if you want
to go poking around in dark places, I'm gonna trust that you've got a
good reason and you're not making trouble."
Karl Fast
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 function which is a class method, and i want to test a attribute of the class which may or may not be None, but will exist always.
class classA():
def __init__(self, var1, var2 = None):
self.attribute1 = var1
self.attribute2 = var2
#classmethod
def func(self,x):
if self.attribute2 is None:
do something
i get the error
AttributeError: class classA has no attribute 'attributeB'
when i access the attribute like i showed but if on command line i can see it works,
x = classA()
x.attribute2 is None
True
so the test works.
if i remove the #classmethod decorator from func, the problem disapears.
if i leave the #classmethod decorator, it only seems to affect variables which are supplied default values in the super-class's constructor.
whats going on in the above code?
There is a difference between class attributes and instance attributes. A quick demonstration would be this:
>>> class A(object):
... x=4
... def __init__(self):
... self.y=2
>>> a=A() #a is now an instance of A
>>> A.x #Works as x is an attribute of the class
2: 4
>>> a.x #Works as instances can access class variables
3: 4
>>> a.y #Works as y is an attribute of the instance
4: 2
>>> A.y #Fails as the class A has no attribute y
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
A.y #Fails as the class A has no attribute y
AttributeError: type object 'A' has no attribute 'y'
>>>
Now, when a method of a class is decorated with classmethod, that signals that it does not take an instance, but takes the class itself as the parameter. Thus, conventionally we name the first argument cls, and not self. In your code, classA has no attributes, and so trying to access attribute2 fails. This difference can be shown with the below code:
>>> class B(object):
... x=2
... def __init__(self):
... self.x=7
... def pr1(self):
... print self.x
... #classmethod
... def pr2(cls):
... print cls.x
>>> b=B()
>>> B.x
2
>>> b.x
7
>>> b.pr1()
7
>>> b.pr2()
2
>>> B.pr2()
2
I might not have been clear enough, so if you are still confused just search classmethod or new-style classes and read up a bit on this.
You should first test to see if you HAVE the attribute with hasattr() or somesuch.
class classA(superClass):
def func(self,x):
if not hasattr(self, "attributeB") or self.attributeB is None:
do somthing
You may also want to make sure that the sub-class is calling the constructor method from the parent class. That attribute is obviously getting assigned after you're referencing it. So make sure the class is properly constructed with
parentclassName.__init__(self, ... )
self in an instance method is the instance. self (or more traditionally, cls) in a class method is the class. Attributes bound on an instance are not visible on the class. The only way to make this work would be to pass the instance to the class method, at which point you may as well just make it an instance method.
The two attributes are instance attributes, not class attributes. The class method is trying to reference class attributes. Neither your attribute1 nor your attribute2 exist on the class: they exist on the instance.
I don't know how to fix this, but this is the source of the problem.
(Verified by changing attribute2 to attribute1 in func.)
So the question should really be, "How to reference instance attributes within a class method?"