I want to create a class in python that includes class level constants for special instances of the class. i.e. something like this:
class Testing:
SPECIAL = Testing("special")
def __init__(self, name):
self.name = name
def test_specials():
norm = Testing("norm")
assert norm.name == "norm"
assert Testing.SPECIAL.name == "special"
If I try the above code, it fails saying: NameError: name 'Testing' is not defined.
How should I model this?
Thanks to Anthony for the answer above. The solution is this:
class Testing:
def __init__(self, name):
self.name = name
Testing.SPECIAL = Testing("special")
def test_specials():
norm = Testing("norm")
assert norm.name == "norm"
assert Testing.SPECIAL.name == "special"
Related
I want to set some constants as members of a class and I feel this is the wrong way to do it:
class Unit:
def __init__(self, SYMBOL=None, RATIO_TO_METER=None):
self._symbol = SYMBOL
self._ratio_to_meter = RATIO_TO_METER
def __repr__(self):
return self._symbol
class Inch(Unit):
SYMBOL = 'in'
RATIO_TO_METER = 0.0254
class Metre(Unit):
SYMBOL = 'm'
RATIO_TO_METER = 1
class Yard(Unit):
SYMBOL = 'yd'
RATIO_TO_METER = 0.9144
For instance the __repr__ method returns None. It seems to execute when Unit instantiates and not when I would like to, namely when self._symbol has received a value.
I could make it work by having an __init__ method in each child class but that would not be DRY.
What is the right to do it?
You already set class attributes, there is no need to pass those into __init__. Just use the class attributes directly:
class Unit:
SYMBOL = None
RATIO_TO_METER = None
def __repr__(self):
return self.SYMBOL
class Inch(Unit):
SYMBOL = 'in'
RATIO_TO_METER = 0.0254
class Metre(Unit):
SYMBOL = 'm'
RATIO_TO_METER = 1
class Yard(Unit):
SYMBOL = 'yd'
RATIO_TO_METER = 0.9144
There is little point in setting instance attributes; you already have direct access to the class attributes.
class Shape:
def __init__(self,center,name):
self.__name = name
self.center = center
def getName(self):
return self.__name
def __add__(self,otherShape):
return Shape(name = self.__name, center = self.center + otherShape.center)
class Size:
def __init__(self,surface,magnitude):
self.surface = surface
self.magnitude = magnitude
def __eq__(self, otherSize):
try:
a = self.magnitude == otherSize.magnitude and self.surface == otherSize.surface
except:
print('Wrong type of atributes')
return a
class Dreieck(Size,Shape):
def __init__(self,center,name,surface,magnitude,a,b,c):
Shape.__init__(self,center,name)
Size.__init__(self,surface,magnitude)
Dreieck.a = a
Dreieck.b = b
Dreieck.c = c
def pitagoras(self):
if self.a+self.b==self.c and self.a**2 + self.b**2 == self.c**2:
return True
else:
return False
def __add__(self,otherDreieck):
return Dreieck(self.center, self.__name, self.surface, self.magnitude,self.a+otherDreieck.a, self.b+otherDreieck.b, self.c+otherDreieck.b)
I am doing a simple example of multiple inheritance in Python, and I can't find why by adding two objects of class Dreieck I get an AttributeError 'Dreieck' object has no attribute 'name'. I suppose it is because the name attribute is private, but I thought I was inheriting it here:
Shape.__init__(self,center,name)
Outside the class itself, private names are mangled. See Private Variables and Class-local References.
You can work around it by using the mangled name in your code. In other words try referencing it as self._Shape__name.
Just a simple class definition withh subclasses to show inheritance
import datetime
class LibaryItem: #The base class definition
def __init__(self, t, a, i): # initialiser method
self.__Title = t
self.__Author_Artist = a
self.__ItemID = i
self.__OnLoan = False
self.DueDate = datetime.date.today()
def GetTitle(self):
return(self.__Title)
# All other Get methods go here
def Borrowing(self):
self.__OnLoan = True
self.__DueDate = self.__DueDate + datetime.timedelta(weeks = 3)
def Returning(self):
self.OnLoan = False
def PrintDetails(self):
print(self.__Title, '; ', self.__Author_Artist,'; ',end='') # end='' Appends a space instead of a newline
print(self.__ItemID, '; ', self.__OnLoan,'; ', self.__DueDate)
class Book(LibaryItem):# A subclass definition
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
# This statement calls the constructor for the base class
self.__IsRequested = False
self.__RequestBy = 0
def GetIsRequested(self):
return(self.__IsRequested)
class CD(LibaryItem):
def __init__(self, t, a, i): # Initialiser method
LibaryItem.__init__(self, t, a, i)
self.__Genre = ""
def GetGenre(self):
return(self.__Genre)
def SetGenre(self, g):
self.__Genre = g
Instantiating a subclass
ThisBook = Book('Title', 'Author', 'ItemID')
ThisCD = CD('Title', 'Author', 'ItemID')
This is my problem here I don't understand why the ThisBook the object's attribute doesn't change from False its default value to True.
# Using A method
print(ThisBook.GetIsRequested())
ThisBook.IsRequested = True
print(ThisBook.GetIsRequested())
Thank you a reason to why this doesn't work would be helpful
You probably meant to do
ThisBook.__IsRequested = True
which you can't do because of name mangling. You could write another setter.
But before you dive too deeply into writing a lot of getters and setters you should be aware that the pythonic way is to not use them. Or, if additional logic is required, to use the #property decorator.
class LibaryItem:
def __init__(self, title, author, itemid): # initialiser method
self.title = title
self.author = author
self.itemid = itemid
self._onloan = False
self.duedate = datetime.date.today()
#property
def onloan(self):
return self._onloan
#onloan.setter
def onloan(self, value):
if value:
self.duedate += datetime.timedelta(weeks = 3)
self._onloan = value
def __str__(self):
return "%s; %s; %s; %s; %s" % (self.title, self.author, self.itemid, self.onloan, self.duedate)
class Book(LibaryItem):
def __init__(self, title, author, itemid):
LibaryItem.__init__(self, title, author, itemid)
self.requested = False
self.requestby = 0
and then
ThisBook = Book('Title', 'Author', 'ItemID')
print(ThisBook.requested)
ThisBook.requested = True
ThisBook.onloan = True
print(ThisBook.duedate)
You can't access a field with 2 underscores prefix like that (see What is the meaning of a single- and a double-underscore before an object name?).
You need to write a proper setter:
def SetIsRequested(self, val):
self.__IsRequested = val
What you are experiencing is the typical silliness of dynamic languages. A field on class can be set w/o being declared and the interpreter can't help you by pointing out that you've just created a new field called "IsRequested" in your class. Saves you some typing but costs you in ability of your interpreter and IDE to prevent you from messing up.
I have no idea what is wrong! This is a very simple program and I have done a lot head banging! Please someone enlighten me!
This a lab problem from the CSE 111 - Programming Language II course. They teach Java at the university and the code I wrote in Java works fine.
I just have to create a Student class with some fields to hold the basic information about a student with methods to get and set the attributes. Then create an instance of that class and tryout the methods.
But every time I run this program the following error occurs:
TypeError: set_name() takes exactly 1 positional argument (2 given)
Here is the code I wrote.
class Student:
'''Student class'''
name = None
id = 0
address = None
cgpa = None
def get_name():
return name
def set_name(n):
name = n
def get_id():
return id
def set_id(i):
id = i
def get_address():
return address
def set_address(a):
address = a
def get_cgpa():
return cgpa
def set_cgpa(c):
cgpa = c
#An object of Student class
jack = Student()
jack.set_name('jacky')
print(jack.get_name())
You're not accepting a reference to your instance as the first argument to that method, i.e. your set_name() should be written:
def set_name(self, n):
self.name = n
This is somewhat different from other languages where there is a built-in keyword (such as this) that refers to the current object. Python passes that reference explicitly, as an argument to the method.
All your other methods must be modified similarly.
Note that just setting name = n sets a local variable name which goes away when the method ends; it does not set anything on the instance. You have to explicitly set self.name if you want an instance attribute.
Also, and this is a matter of style, but you do not usually write set and get methods in Python. It is normal practice to set and get attributes directly. If you want to do validation of values, use a property instead. So basically, none of your methods are actually necessary in good style.
However, you don't have an __init__() method. Usually you would pass the desired attributes of the instance when instantiating the class and save these on the instance.
class Student:
def __init__(self, name, id, address, cgpa):
self.name = name
self.id = id
self.address = address
self.cgpa = cgpa
herman = Student("Herman Munster", 12345, "1313 Mockingbird Lane", 4.0)
Try this:
import sys
class Student:
'''Student class'''
self.name = None
self.id = 0
self.address = None
self.cgpa = None
def get_name(self):
return self.name
def set_name(self, n):
self.name = n
def get_id(self):
return self.id
def set_id(self, i):
self.id = i
def get_address(self):
return self.address
def set_address(self, a):
self.address = a
def get_cgpa(self):
return self.cgpa
def set_cgpa(self, c):
self.cgpa = c
You need to pass self as the first argument to each member function of the class. Member variables must then be referred to with self, i.e. self.name. Furthermore, you may wish to include an __init__() function; this serves usually to initialize any member variables, and is called at the instantiation of the class.
Take a look at the Python documentation here for some examples on well-formed classes: http://docs.python.org/tutorial/classes.html#random-remarks
In Python, you need to pass in self for each of your member functions. You also need to reference class variables as self.x, if you want them to take an effect.
Here are a couple examples that you need to apply to the rest of your code.
def set_name(self, n):
self.name = n
def get_cgpa(self):
return self.cgpa
There is some explanation for why this is the case in the documentation.
This is because first argument of methods is self - the class instance.
See What is the purpose of self?
and http://docs.python.org/tutorial/classes.html#class-objects
I have a python code like this.
File named mymodule.py
class MyBase(object):
pass
File named data.py
from mymodule import MyBase
class A:
class NestA(MyBase):
pass
class NestB(MyBase):
pass
class B:
class NestA(MyBase):
pass
class NestB(MyBase):
pass
if I have a = A.NestA (not it is referring to a class, a is not the object of class NestA but the class itself) how do I find out what nested class hierarchy does a belong to? a.name gives me NestA so that is not a problem. I want to find out what outer class NestA is part of, i.e class A or class B. How do I do it?
You can do this with the inspect module:
import inspect
a = A.NestA
print a in [x[1] for x in inspect.getmembers(A, inspect.isclass)]
print a in [x[1] for x in inspect.getmembers(B, inspect.isclass)]
Result:
True
False
Addendum:
If you don't know anything about the classes in the module, you can backtrack and get the module.
# for each class in a's module...
for klass in inspect.getmembers(inspect.getmodule(a), inspect.isclass):
# see if a is in that class
if a in [x[1] for x in inspect.getmembers(klass[1], inspect.isclass)]:
print a, "is a member of", klass[0]
Result:
__main__.NestA is a member of A
You can use __qualname__ to get the nested class hierarchy,
A.NestA.__qualname__ == 'A.NestA'
You can do something like this with metaclass programming.
class SetOuterClassType(type):
def __init__(cls, name, bases, attrs):
for attrname, attrvalue in attrs.iteritems():
if getattr(attrvalue, '__set_outerclass__', False):
attrvalue.__outerclass__ = cls
class OuterClassSetter(object):
__metaclass__ = SetOuterClassType
class MyBase(object):
#classmethod
def fullname(cls):
if hasattr(cls,'__outerclass__'):
return '%s.%s' % (
cls.__outerclass__.__name__, cls.__name__ )
else:
return '%s' % cls.__name__
class A(OuterClassSetter):
class NestA(MyBase):
__set_outerclass__ = True
class NestB(MyBase):
__set_outerclass__ = True
class B(OuterClassSetter):
class NestA(MyBase):
__set_outerclass__ = True
class NestB(MyBase):
__set_outerclass__ = True
print A.NestA.fullname() # prints 'A.NestA'
print A.NestB.fullname() # prints 'A.NestB'
print B.NestA.fullname() # prints 'B.NestA'
print B.NestB.fullname() # prints 'B.NestB'