Calling an inherited property in python [duplicate] - python

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Polymorphism in Python
Hi
I'm trying to call a property in a class, that is inherited from my baseclass, but it doesn't work. I guess I'm missing something, but what?
Here is my code:
class Produkt:
def __init__(self,pID,pProdNavn,pNetto):
self.__produktId = pID #atributt for produkt nummer
self.__produktNavn = pProdNavn #atributt for produkt navn
self.__produktNetto = pNetto #egenskap for nettopris
def getName(self): #Metode for å finne produktnavnet
return self.__produktNavn
class Bok(Produkt):
def __init__(self,pID,pProdNavn,pNetto,pForfatter):
Produkt.__init__(self,pID,pProdNavn,pNetto)
self.__produktForfatter = pForfatter #atributtp for forfatter
def getNet(self):
return self.__produktNetto
as you see I'm trying to call the _productNetto property that is inherited from my Produkt class.
What am I doing wrong?
/Andy

It works fine if you don't use double underscore in attribute names
class Produkt:
def __init__(self,pID,pProdNavn,pNetto):
self.produktId = pID
self.produktNavn = pProdNavn
self.produktNetto = pNetto
def getName(self):
return self.__produktNavn
class Bok(Produkt):
def __init__(self,pID,pProdNavn,pNetto,pForfatter):
Produkt.__init__(self,pID,pProdNavn,pNetto)
self.produktForfatter = pForfatter
def getNet(self):
return self.produktNetto
x = Bok(1, 2, 3, 4)
print x.getNet()
output:
3
Otherwise the names get mangled and it is looking for attribute _Bok__produktNetto. See: http://docs.python.org/reference/expressions.html#atom-identifiers
AttributeError: Bok instance has no attribute '_Bok__produktNetto'

The problem is that you named those members with two leading underscores, which makes them invisible under those names outside that class (see http://docs.python.org/tutorial/classes.html).
If you rename those fields with a single underscore in both places, it will work as you intend.

Related

Creating classes dynamically in python [duplicate]

This question already has answers here:
How can I dynamically create derived classes from a base class
(4 answers)
Closed 10 months ago.
Is it a good coding practice to have the class name as variable.
E.g
def create_class(class_name):
class class_name:
def __init__(self):
do_sth....
class_instance = class_name()
return class_instance
for object in objects:
res = create_class(object)
I wanted to create different classes which are present in a list like objects=[person,vehicle, location ..]. What could be other alternative way to do it ?
class_name is a class, you can set a name property for your class, like this:
class class_name:
def __init__(self,name):
self.name = name
def __str__(self):
return str(self.name)
objects=["person","vehicle","location"]
for obj in objects:
res = class_name(obj)
print(res)

giving error while accessing method outside of class [duplicate]

This question already has answers here:
Python NameError: name is not defined
(4 answers)
Closed 4 years ago.
class one(object):
b=squares
def squares(self):
print('hi')
getting the following error:
NameError: name 'squares' is not defined
This should work for you. Let me explain it. First code should go inside of methods, these methods can be combined into classes. You shouldn't place code in the class directly.
In Python when an object is instantiated the __init__(self) method is called directly. This method takes the self argument which will hold the attributes and functions available for this class. In our case, I added an attribute called self.size = 5. Then we call the squares(self) function. Notice we access it as self.function_name().
Then in that function we pass the self argument. Notice how we can access the self.size attribute from this function.
class one(object):
def __init__(self):
self.size = 5
b = self.squares()
def squares(self):
print('hi' + str(self.size))
o = one()
If you want a generic function not tied to your object. Then you need to define it before the class.
def squares(a):
return a*a
class One():
def __init__(self, a):
self.num = a
self.example()
def example(self):
b=squares(self.num)
print(b)
obj = One(4)

How to use Python console to look at the internals of the classes implementing __getattr__? [duplicate]

This question already has answers here:
What is the meaning of single and double underscore before an object name?
(18 answers)
Closed 5 years ago.
Suppose we have an advanced class that implements a lot or special functions, including
__getattr__
__getitem__
__iter__
__repr__
__str__
An example would be ParseResults class in pyparsing.py.
Removing the (no doubt important) details, the constructor looks like this
def __init__( ... ):
self.__doinit = False
self.__name = None
self.__parent = None
self.__accumNames = {}
self.__asList = asList
self.__modal = modal
self.__toklist = toklist[:]
self.__tokdict = dict()
And then we have __getattr__ and __getitem__:
def __getattr__( self, name ):
try:
return self[name]
except KeyError:
return ""
def __getitem__( self, i ):
if isinstance( i, (int,slice) ):
return self.__toklist[i]
else:
if i not in self.__accumNames:
return self.__tokdict[i][-1][0]
else:
return ParseResults([ v[0] for v in self.__tokdict[i] ])
I'd like to be able to do something like print res.__tokdict in the console, but that would not work: it prints empty string, as the __getattr__ implementation should.
How do I work around this and see the actual data in the object?
What is happening here is name mangling. Quoting the documentation:
Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped.
This mechanism is used to prevent the subclasses from accidentally overriding an attribute from a base class.
In our particular case, the __tokdict attribute that is set in ParseResults.__init__() can thus be accessed as my_instance._ParseResults__tokdict.
Quick example:
>>> class Foo(object):
... def __init__(self, x):
... self.__x = x
...
>>> f = Foo(7)
>>> f._Foo__x
7
>>> f.__dict__ # let's see what's inside the instance
{'_Foo__x': 7}

python context of passed-to-class function [duplicate]

This question already has answers here:
Adding a method to an existing object instance in Python
(19 answers)
Closed 7 years ago.
In my model I have a class containing a rather generic function, which calls a higher order function. I put together a simple example of it:
class AClass(object):
def __init__(self, prop, fun):
self.prop = prop
self.fun = fun
def do_sth(self):
self.fun()
def namely_this_(context):
print 2*context.prop
obj1 = AClass(3, namely_this_)
obj1.do_sth()
This snippet contains everything to know, just note, that it could be continued by something like:
def namely_this_2(self):
print 4*self.prop
obj2 = AClass(2, namely_this_2)
obj2.do_sth()
The above code does not run, instead it throws a
TypeError: namely_this_() takes exactly 1 argument (0 given)
Instead, I have to change the do_sth to
def do_sth(self):
self.fun(self) # the *self* in the parenthesis added
Question: In what way does the namely_this_ differ from functions defined inside a class and is my workaround a viable solution?
An instance method is a property of the class, not the instance itself. If you changed your init to assign fun to self.__class__.fun, it would work; except then of course all instances would share the same function, which is clearly not what you want.
In order to make it an actual method, you need to make it an instance of types.MethodType:
def __init__(self, prop, fun):
self.prop = prop
self.fun = types.MethodType(fun, self)

Multiple instances of a class containing a list in python [duplicate]

This question already has answers here:
Python appending to two lists when it should only append to one
(3 answers)
Closed 8 years ago.
When running following code in python, i create 2 objects of one class, that contains a list object:
class Test():
def run(self):
obj1 = klasse("Werner")
obj2 = klasse("Franz")
print obj1.name
print obj2.name
obj2.add_name("Thomas")
print obj2.name
class klasse(object):
name = [];
def __init__(self, value):
self.name.append(str(value))
def add_name(self, value):
self.name.append(str(value))
if __name__ == "__main__":
Test().run()
this returns in console:
['Werner', 'Franz']
['Werner', 'Franz']
['Werner', 'Franz', 'Thomas']
The Question: it seems to be the same list object in the two created klasse.objects. Whats the solution to isolate the name lists in every created object?
The console output should be:
['Werner']
['Franz']
['Franz', 'Thomas']
The implementation for your klasse should be like the following :
class klasse(object):
# name = [] if this was the case, the name would be a class variable,
# and all instances would share it
def __init__(self, value):
self.name = [] # but now it is a separate for each instance
self.add_name(value)
def add_name(self, value):
self.name.append(str(value))
edit: incorporated #Jon Clements's suggestion.
I just ran into this a couple of hours ago.
As the comments indicate when you define a variable inside a class but outside of a method of the class, that is a class level variable. Class level variables are the equivalent of static variables in other languages. There exists only one copy of the variable that is shared by all instances of that class. Interestingly enough, the variable also exists when there is no instance of the class. With your existing code base, try print klasse.name.
If you define a variable inside a method of a class, the variable unique to the instance of the class that defined it. To get the effect desired, you need to create and initialize self.name inside the __init__ method. This will create a unique instance of the variable in each instance of the class.
One side note, it is considered best practice in python and most other OO languages that class names be capitalized.
If you don't prepend with self. the variable will be a class variable, not an instance variable, meaning that for each object, the value will be the same. For this case, to make name an instance variable, you would do the following:
self.name = []
In case this was not evident in your testing, you cannot declare self.myVariable outside of a function.
In class Klasse, name variable is class level variable so before creating new instance of that class first check whether name list is empty or not. If not empty then make it empty in init() as this function called every time instance of that class being created.
>>> class klasse(object):
... name = []
... def __init__(self, value):
... if self.name:
... self.name = []
... self.name = [value]
... def add_name(self, value):
... self.name.append(str(value))
...
>>> class Test():
... def run(self):
... obj1 = klasse("Werner")
... obj2 = klasse("Franz")
...
... print obj1.name
... print obj2.name
... obj2.add_name("Thomas")
... print obj2.name
...
>>> Test().run()
['Werner']
['Franz']
['Franz', 'Thomas']

Categories