How to access a method's attribute - python

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

Related

Do instance variables declared outside of `__init__()` have any differences in python?

I'm wondering weather it is necessary to define class instance variable within class declarations.
I tried assigning a new instance variable after the object (class instance) was already created, and looks like there is no difference. Are there any caveats in this approach?
class Context():
def __init__(self, extension):
self.extension = extension
c = Context('extension+')
print(f"before: {c.__dict__}")
c.new_var = 'new_var_content'
print(c.extension + c.new_var)
print(f"after: {c.__dict__}")
printed:
before: {'extension': 'extension+'}
extension+new_var_content
after: {'extension': 'extension+', 'new_var': 'new_var_content'}
There is no difference between declaring self.foo within a def __init__(self, <arguments>): definition, and declaring it after an object has been instantiated.
Both assignments have instance-level scope.
Given -
class Context:
i_am_a_class_variable = 'class_string'
def __init__(self, bar):
self.bar = bar
See -
class attributes can be accessed without instantiating an object.
>>> Context.i_am_a_class_variable
'class_string'
instance attributes can be assigned during instantiation using the __init__(self) function.
>>> Context.bar
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-8be0704da5be> in <module>
----> 1 Context.bar
>>> instance = Context('bar')
>>> instance.bar
'bar'
instance attributes can be assigned after instantiation, directly
>>> instance = Context('bar')
>>> instance.foo = 'foo'
>>> instance.foo
'foo'
Speaking in terms of whether you can assign a value to the property or create a new property, there is no difference if you do it within init or anywhere else after the object is created as in both cases it gets added in dict of the object(unless you use slots)
However, if you want your class to be initialized with desired state (i.e, having some mandatory variables with default/preset values) , you should put it in init. Since init is called implicitly as soon as object is created, you object will be having desired state.

Python: How to fix, if a static class variable gets a different function reference pointer?

I wonder why my class calls the referenced function (assigned to a static class variable) with with an argument. If I assign the function reference to a normal class variable it works like expected.
Here my example code:
# This function is not editable, because it's imported from an API
def getStuff():
print "I do my stuff!!!"
class foo(object):
GET_STUFF = getStuff
def __init__(self):
print "static var: ",self.GET_STUFF
self.GET_STUFF()
print "outer func: ",getStuff
foo()
This comes up with the following error:
outer func: <function getStuff at 0x0000000003219908>
static var: <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
Traceback (most recent call last):
File "C:/example.py", line 13, in <module>
foo()
File "C:/example.py", line 10, in __init__
self.GET_STUFF()
TypeError: getStuff() takes no arguments (1 given)
To fix this issue I point the function reference inside the constructor to the class variable:
class foo(object):
def __init__(self):
self.GET_STUFF = getStuff
print "static var: ",self.GET_STUFF
self.GET_STUFF()
The result is like expected and works fine:
outer func: <function getStuff at 0x000000000331F908>
static var: <function getStuff at 0x000000000331F908>
I do my stuff!!!
But:
I wanted to use a static class variable, because it makes it easy to read and simple to setup for different API's. So in the end I would come up with some wrapper classes like in the following:
from API01 import getStuff01
from API02 import getStuff02
# bar calculates stuff object from the API (it calls GET_STUFF)
# and stores the object into self.stuff
import bar
class foo01(bar):
GET_STUFF = getStuff01
def DoSomething(self, volume):
self.stuff.volume = volume
class foo02(bar):
GET_STUFF = getStuff02
def DoSomething(self, volume):
self.stuff.volume = volume
# [...] and so on..
Is there a way to bring it to work in the way I want to setup my wrapper classes, or do I really have to define a constructor for each wrapper class?
Thanks
The reason for the error is that
self.GET_STUFF()
actually means
tmp = getattr(self, 'GET_STUFF')
tmp(self)
That means these two classes are equivalent:
def foo(self): pass
class Foo(object):
a = foo
class Bar(object):
def a(self): pass
In both cases, a function object is added to the class as a member and that means for Python that the function wants self as the first parameter.
To achieve what you want:
from API01 import getStuff01
def wrapper01(self):
getStuff01()
class foo01(object):
GET_STUFF = wrapper01
Just for extend Aaron answer, if you want to have static methods you can use the #staticmethod decorator:
class Calc:
#staticmethod
def sum(x, y):
return x + y
print (Calc.sum(3,4))
>>> 7
I thought already that my object is calling the referenced function with itself as argument. After a bit of research I finally found a solution. When I use a class variable to point to a function it will not referencing a direct pointer. It references the function as a bounced method of it's class. To get rid of the default call of calling a method with getattr, the call function of getattr for the class itself has to be overwritten (in this case the class bar, because foo (the wrapper classes) inherits the functionalities of bar:
import inspect
class bar(object):
GET_STUFF = None
def __getattribute__(self, name):
attr = object.__getattribute__(self,name)
if name == "GET_STUFF":
# Check: is method and is bounced?
if inspect.ismethod(attr) and attr.im_self is not None:
return attr.__func__
return attr
getattr of bar is now pointing to the original function reference, but only for the class variable GET_STUFF, because I want to leave the default functionality for the rest of my variables.
So, when I now execute the following:
class foo(bar):
GET_STUFF = getStuff
def __init__(self):
print "inner func: ",self.GET_STUFF
self.GET_STUFF()
foo()
I get the expected result and can write my wrappers without producing additional code for each module with those wrapper classes:
outer func: <function getStuff at 0x00000000034259E8>
inner func: <function getStuff at 0x00000000034259E8>
I do my stuff!!!

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

Questions regarding Python and Class specific variables

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

Understanding python class attributes

I am very new to programming and started learning python. Might look very stupid question, so please pardon my ignorance.
Consider the following snippet of code :
class Test1:
bar = 10
def display(self,foo):
self.foo=foo
print "foo : ",self.foo #80
def display1(self):
print "bar: ", self.bar #10
print "again foo: ", self.foo #80
if __name__ == '__main__':
test1 = Test1()
test1.display(80)
test1.display1()
print test1.bar #10
print test1.foo #80
I want to understand what is the difference between using foo and bar (wrt to where we have defined them) as in scope wise they are equally accessible at all places compared to each other and only difference is that one is inside function and other is inside Class but they both are still "instance" variable.
So which is good practice?
Also, if I slightly modify display function as below :
def display(self,foo):
self.foo=foo
foo = foo
print "self.foo : ",self.foo
print "foo : ",foo
Can someone please explain how python sees this, as in what difference/significance this self keyword is bringing in between two foo.
bar is a class attribute and foo is an instance attribute. The main difference is that bar will be available to all class instances while foo will be available to an instance only if you call display on that instance
>>> ins1 = Test1()
ins1.bar works fine because it is a class attribute and is shared by all instances.
>>> ins1.bar
10
But you can't access foo directly here as it is not defined yet:
>>> ins1.foo
Traceback (most recent call last):
File "<ipython-input-62-9495b4da308f>", line 1, in <module>
ins1.foo
AttributeError: Test1 instance has no attribute 'foo'
>>> ins1.display(12)
foo : 12
>>> ins1.foo
12
If you want to initialize some instance attributes when the instance is created then place them inside the __init__ method.
class A(object):
bar = 10
def __init__(self, foo):
self.foo = foo #this gets initialized when the instance is created
def func(self, x):
self.spam = x #this will be available only when you call func() on the instance
...
>>> a = A(10)
>>> a.bar
10
>>> a.foo
10
>>> a.spam
Traceback (most recent call last):
File "<ipython-input-85-3b4ed07da1b4>", line 1, in <module>
a.spam
AttributeError: 'A' object has no attribute 'spam'
>>> a.func(2)
>>> a.spam
2
bar is a class attribute. Since classes in Python are objects, they too can have attributes. bar just happens to live on that Test object, not an instance thereof.
Because of the way Python resolves attribute lookups, it looks like test1 has a bar attribute, but it doesn't.
foo on the other hand lives on the instance test1 after calling display(80). This means that different instances of Testcan have different values in their respective foo attributes.
Of course, you could use class variables as some kind of "shared default value", which you can then "override" with an instance attribute, but that might get confusing.
Second question
def display(self,foo):
self.foo=foo
foo = foo
print "self.foo : ",self.foo
print "foo : ",foo
Let's just get a detail out of the way: self is not a keyword, it's just convention to call the first argument "self", you could also call it "this" or "that" or "bar" if you liked, but I wouldn't recommend that.
Python will pass the object, on which the method was called as the first argument.
def display(self,foo):
This foo is the name of the first parameter of the display instance-function.
self.foo=foo
This sets the attribute with the name "foo" of the instance, on which you called display() to the value, which you passed as first argument. Using your example test1.display(80), self will be test1, foo is 80 and test1.foo will thus be set to 80.
foo = foo
This does nothing at all. It references the first parameter foo.
The next two lines again reference the instance variable foo and the first parameter foo.
Personally, I don't like defining instance variables inside of methods other than __init__ or as class variables like bar in your example above.
Again, personally, I like to see every member of my class by looking at the top. Whether it is a class variable that you use as an instance variable (something I don't usually do) or an instance variable defined in __init__, it is easy to tell what is and isn't defined in a class by inspecting the first section of the class definition.
If you won't need to access a variable as a class member (ie. you are only defining it there to avoid writing self.variable = val in the __init__ method, then I would steer clear of it. If you might need to access it as a class variable, then doing what you are with bar is ok in my book.
This would be my preferred way of writing you class.
class Test1:
def __init__(self):
self.foo = None
self.bar = 10
def display(self,foo):
self.foo=foo
print "foo : ",self.foo #80
def display1(self):
print "bar: ", self.bar #10
print "again foo: ", self.foo #80

Categories