Questions regarding Python and Class specific variables - python

I have a question regarding python and class initialized variables.
So I recently noticed in Python (2.7.X) that if you set a class variable that hasn't been defined or initialized, you are still able to call and access the data within that variable.
For instance:
class Test:
def __init__(self):
self.a = "Hello"
t = Test()
print t.a
t.b = "World"
print t.b
Output:
Hello
World
I would expect 'print t.b' to error because b hasn't been defined in the Test() class but it runs without any issue. Why is this happening? Can anyone explain?
http://ideone.com/F2LxLh
Thank you for your time.

From the docs on instance objects (t is an instance object because it is an instance of the custom class Test):
Data attributes need not be declared; like local variables, they spring into existence when they are first assigned to.
However you can get your expected behavior by using __slots__ with a new-style class. This overrides the default dictionary storage for attributes to make the object more memory efficient, and it also results in an AttributeError if you try to assign to an attribute not defined in __slots__, for example:
>>> class Test(object):
... __slots__ = ['a']
...
>>> t = Test()
>>> t.a = "Hello"
>>> t.b = "World"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'b'

This is expected behaviour. You can add attributes in Python at any time without errors. Even without setting attributes in the __init__ you can add new ones on the fly:
>>> class Test:
... pass
...
>>> t = Test()
>>> t.foo = '3'
>>> t.foo
'3'

If you want you can change this behavior by writing your own __setattr__ method ( see docs )
class Test:
def __init__(self):
self.__dict__[ 'a' ] = "Hello"
def __setattr__( self, name, value ):
if name not in self.__dict__:
raise Exception( 'No attribute: ' + name )
else:
self.__dict__[ name ] = value
t = Test()
t.a = 'hello world'
print ( t.a )
t.b = "World" # <<< this will throw exception

Related

How to initialise class itself as class Object

How to initialise class as an object with same name
>>> class test:
def name(self,name_):
self.name = name_
>>> a= test()
>>> a
<__main__.test instance at 0x027036C0>
>>> test
<class __main__.test at 0x0271CDC0>
here a is an object so I can do a.name("Hello")
But what I want to achieve is test.name("Hello") without doing something like test = test()
The simple answer is don't bother with a "setter" function. Just access the attribute directly. eg.
a = test()
a.name = "setting an instance attribute"
test.name = "setting the class attribute"
b = test()
# b has no name yet, so it defaults the to class attribute
assert b.name == "setting the class attribute"
If the function is doing something a little more complicated than just setting an attribute then you can make it a classmethod. eg.
class Test(object):
# you are using python 2.x -- make sure your classes inherit from object
# Secondly, it's very good practice to use CamelCase for your class names.
# Note how the class name is highlighted in cyan in this code snippet.
#classmethod
def set_name(cls, name):
cls.name = name
Test.set_name("hello")
assert Test().name == "hello"

Adding a new attribute to Python object?

Being from OOPS background, It looks strange to see below code from link
def f():
f.beencalled = True
return 0
My question:
1)
From the above code,
Is f a reference variable pointing to an object f of class 'function'?
2)
We add a new attribute beencalled to an object f, so now 'function' class does not have this attribute beencalled defined and we say that object f is an object of class 'function'? Does it make sense?
1) Yes:
>>> def f():
print(type(f))
>>> f()
>>> <class 'function'>
2) The function class does not have a new attribute, but the object f does. Adding or removing attributes to/from an object does not affect which attributes other objects of that class will have:
>>> class A: pass
>>> a = A()
>>> a.var = 7
>>> b = A()
>>> b.var
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
b.newvar
AttributeError: 'A' object has no attribute 'var'
Classes are much more flexible in python than in Java or C++. Objects can have attributes not defined in their class, or even lack attributes that were defined in their class! Look at this:
>>> class A:
def __init__(self, a):
self.var = a
>>> obj = A(7)
>>> del obj.var #deletes the var attribute from obj, does not change the A class
>>> obj.var
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
obj.var
AttributeError: 'A' object has no attribute 'var'
>>> obj2 = A(6)
>>> obj2.var #obj2 is a new object, so the fact we deleted var from obj doesn't affect it
6
EDIT: after a bit of searching I found an explanation for why this behavior was chosen (source):
To implement user-defined objects, I settled on the simplest possible
design; a scheme where objects were represented by a new kind of
built-in object that stored a class reference pointing to a "class
object" shared by all instances of the same class, and a dictionary,
dubbed the "instance dictionary", that contained the instance
variables.
In this implementation, the instance dictionary would contain the
instance variables of each individual object whereas the class object
would contain stuff shared between all instances of the same class--in
particular, methods. In implementing class objects, I again chose the
simplest possible design; the set of methods of a class were stored in
a dictionary whose keys are the method names. This, I dubbed the class
dictionary. To support inheritance, class objects would additionally
store a reference to the class objects corresponding to the base
classes. At the time, I was fairly naïve about classes, but I knew
about multiple inheritance, which had recently been added to C++. I
decided that as long as I was going to support inheritance, I might as
well support a simple-minded version of multiple inheritance. Thus,
every class object could have one or more base classes.
In this implementation, the underlying mechanics of working with
objects are actually very simple. Whenever changes are made to
instance or class variables, those changes are simply reflected in the
underlying dictionary object. For example, setting an instance
variable on an instance updates its local instance dictionary.
Likewise, when looking up the value of a instance variable of an
object, one merely checks its instance dictionary for the existence of
that variable. If the variable is not found there, things become a
little more interesting. In that case, lookups are performed in the
class dictionary and then in the class dictionaries of each of the
base classes.
On a slightly different note, you can change this behavior for custom classes.
class FooBar(object):
__slots__ = ["foo","bar","baz"]
# if you don't define __slots__, you can add attr to the object as needed
# if you do, the object can only contain those attributes.
def __init__(self,foo=None,bar=None,baz=None):
self.foo = foo
self.bar = bar
self.baz = baz
def __str__(self):
return "I'm a FooBar with id {0} with foo: {1.foo}, bar: {1.bar}, baz: {1.baz}".format(id(self),self)
>>> a = FooBar("a","B","CCC")
>>> print(a)
I'm a FooBar with id 47260256 with foo: a, bar: B, baz: CCC
>>> a.spam = "eggs"
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
a.spam = "eggs"
AttributeError: 'FooBar' object has no attribute 'spam'
Alternately, without defining __slots__:
class BooFar(object):
def __str__(self):
return "I'm a BooFar with the following attributes:\n{}".format(self.__dict__)
>>> b = BooFar()
>>> print(b)
I'm a BooFar with the following attributes:
{}
>>> b.spam = "eggs"
>>> print(b)
I'm a BooFar with the following attributes:
{'spam': 'eggs'}
f() in just an instance of types.FunctionType, and instances can have their own attributes.
Adding an attribute to an instance won't affect its class unless you've overridden the __setattr__ method of that class and doing something evil there.
>>> import types
>>> def func(): pass
>>> isinstance(func, types.FunctionType)
True

How to access a method's attribute

Is it possible to access a method's attribute directly? I tried this and it fails:
class Test1:
def show_text(self):
self.my_text = 'hello'
Which results in:
>>> t = Test1()
>>> t.my_text
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Test1 instance has no attribute 'my_text'
I found that using this made it work:
class Test1:
def __init__(self):
self.my_text = 'hello'
But I'm wondering if it's still possible to access attributes of methods directly? Or am I doing something Very Bad?
Instance variables are created once the object has been instantiated and only after they have been assigned to.
class Example(object):
def doSomething(self):
self.othervariable = 'instance variable'
>> foo = Example()
>> foo.othervariable
AttributeError: 'Example' object has no attribute 'othervariable'
Since othervariable is assigned inside doSomething - and we haven't called it yet -, it does not exist.
Once we call it, though:
>> foo.doSomething()
>> foo.othervariable
'instance variable'
__init__ is a special method that automatically gets invoked whenever class instantiation happens. Which is why when you assign your variable in there, it is accessible right after you create a new instance.
class Example(object):
def __init__(self):
self.othervariable = 'instance variable'
>> foo = Example()
>> foo.othervariable
'instance variable'
my_text attribute doesn't exist until you don't call show_text:
>>> class Test1:
... def show_text(self):
... self.my_text = 'hello'
...
>>> t = Test1()
>>> t.show_text()
>>> t.my_text
'hello'
If you want your attributes to be created during instance creation then place them in __init__ method.
Your first example didn't work: since you never use show_text() method, your object will never have attribute my_text (that will be "added" to your object only when you invoke that method).
Second example is good, because __init__ method is executed as soon as your object is instantiated.
Moreover, is a good practice to access object attribute through getter method on object itself so the best way you can modify your code is
class Test1:
def __init__(self,value):
self.my_text = value
def show_text(self):
return self.my_text
and then use in that way
t = Test1('hello')
t.show_text()
At last, will be also good to have a method like this
def set_text(self,new_text):
self.my_text = new_text

Python Class Variable Initialization

I'd like to store some information about a class as class (static) variables. However, I can't figure out how these things get initialized. Here is a basic, dumb example:
class A(object):
clsVar = 'a'
#classmethod
def clsMeth(cls):
print 'changing clsVar'
cls.clsVar = 'b'
A.clsMeth()
# prints 'changing clsVar'
print A.clsVar # prints 'a'
A.clsVar = 'b'
print A.clsVar # prints 'b'
Since the function got called (as the print statement worked), why didn't the class variable stay changed? Do I have to use a metaclass if I don't want to do it after the class definition completes?
[Specifically, I want clsMeth to be a decorator and have the class variable be a list of all the functions that were so decorated. I'm guessing this isn't the right way to go about accomplishing that, so I've moved on, but I'm still curious.]
EDIT: As numerous people have pointed out, the code above won't run. I was running it in an IPython session where the call to A.clsMeth() would refer to a previous version of A and run. Such are the risks of using an interpreted language, I guess. I ended up going with something like this:
outsideDict = {}
def outsideDec(func):
outsideDict[func.__name__] = func
class A(object):
#outsideDec
def someMethod(self):
print 'ID %s' % id(self)
def otherMethod(self):
print 'other'
print outsideDict
one, two = A(), A()
outsideDict['someMethod'](one)
outsideDict['someMethod'](two)
Perhaps this should be another question, but when outsideDec gets run, is there a way to tell what class it's argument is a member of? Or is there a better way of doing introspection like this in Python? I recognize I'm veering off course here so I'll accept the answer below and do more research. Thanks everyone!
The call to A.clsMeth() in the definition of A will not run, as A does not exist at that point:
>>> class A(object):
... clsVar = 'a'
... #classmethod
... def clsMeth(cls):
... print 'changing clsVar'
... cls.clsVar = 'b'
... A.clsMeth()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in A
NameError: name 'A' is not defined
The code may have seemed to work if A had been defined previously (eg, if you were testing it out in the REPL), but the call to A.clsMeth would have been called on the old class, which would be shadowed by the new one.
However, we can definitely put that call after the definition and get the result you want:
>>> class A(object):
... clsVar = 'a'
... #classmethod
... def clsMeth(cls):
... print 'changing clsVar'
... cls.clsVar = 'b'
...
>>> A.clsMeth()
changing clsVar
>>> A.clsVar
'b'
Of course, as fabianhrj noted, you can put it in the constructor as well, but it won't be called until you create an instance.

Access to class attributes of parent classes

I would like to know what is the best way to get all the attributes of a class when I don't know the name of them.
Let's say I have:
#!/usr/bin/python2.4
class A(object):
outerA = "foobar outerA"
def __init__(self):
self.innerA = "foobar innerA"
class B(A):
outerB = "foobar outerB"
def __init__(self):
super(B, self).__init__()
self.innerB = "foobar innerB"
if __name__ == '__main__':
b = B()
Using hasattr/getattr to get the "outerA" class field of my b instance works fine:
>>> print hasattr(b, "outerA")
>>> True
>>> print str(getattr(b, "outerA"))
>>> foobar outerA
Ok, that's good.
But what if I don't exactly know that b has inherited a field called "outerA" but I still want to get it?
To access b's inner fields, I usually use b.__dict__ . To get b.outerB, I can use b.__class__.__dict__ but that still doesn't show "outerA" among it fields:
>>> print "-------"
>>> for key, val in b.__class__.__dict__.iteritems():
... print str(key) + " : " + str(val)
>>> print "-------\n"
Shows:
-------
__module__ : __main__
__doc__ : None
__init__ : <function __init__ at 0xb752aaac>
outerB : foobar outerB
-------
Where's my outerA?? :D
I am sure I can keep "climbing" the class hierarchy and get all the fields, but that doesn't seem like the greatest solution...
As there are hasattr(), getattr()... isn't there something like a listattr() that would give all the available attributes of an instance?
Thank you!
I think you're looking for dir() - it works just as well within code as in the shell.
Try dir(b). The resulting list includes inherited attributes.

Categories