How can I implement a static attribute in Python? - python

How can I implement a static property or method-pair in Python using a sharable and accessible static attribute?
class StaticClass:
__static_attr: str
#classmethod
def set(cls, input__):
cls.__static_class = input__
#classmethod
def get(cls):
return cls.__static_attr
StaticClass.set("Hello!")
print(StaticClass.get())
Output:
C:\Users\pc\AppData\Local\Microsoft\WindowsApps\python3.7.exe C:/Users/pc/source/repos/main.py
Traceback (most recent call last):
File "C:/Users/pc/source/repos/main.py", line 15, in <module>
print(StaticClass.get())
File "C:/Users/pc/source/repos/main.py", line 11, in get
return cls.__static_attr
AttributeError: type object 'StaticClass' has no attribute '_StaticClass__static_attr'
Process finished with exit code 1
Edit: The above source code has a typo in set(). If that typo is fixed, the code runs perfectly.
However, in the case of my original source code, that attribute was a List[str]. In that case, the program only runs only if the attribute is initialized through a pair of square brackets [].
import os
from typing import List
class SearchFilesInTheDirectory:
__file_list: List[str] = []
#classmethod
def do_indexing_of_files(cls, path, file_extension):
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(file_extension):
cls.__file_list.append(os.path.join(root, file))
#classmethod
def get_files_list(cls):
return cls.__file_list
#classmethod
def printf(cls):
if cls.__file_list is not None:
for file in cls.__file_list:
print(file)
else:
print("directory is empty")
#classmethod
def write_to_file(cls, file_name):
if cls.__file_list is not None:
with open(file_name, 'w') as f:
for f_name in cls.__file_list:
f.write("%s\t%s\n" % f_name)
else:
print("directory is empty")

It would be a better idea is to initialize the class static variable, not just declare its type. This way you would be able to call get even before set, and have it return a default value:
class StaticClass:
__static_attr = ""
#classmethod
def set(cls, input__):
cls.__static_attr = input__
#classmethod
def get(cls):
return cls.__static_attr
StaticClass.set("Hello!")
print(StaticClass.get())
Also, it seems like your original code had a typo, as a result of which set method was assigning to a variable other than the one you were declaring (__static_class instead of __static_attr). Because of that, and because the static variable was not initialized, your get method failed.

Related

AttributeError: 'Program' object has no attribute 'file'

class Program:
def Main(self):
fname = QFileDialog.getOpenFileName()
filepath = str(fname[0])
fileObject = filepath.split('/')
file = fileObject[len(fileObject) - 1]
def image(self, Main):
img1 = cv2.imread(Main.file())
i want to put in img1 the file from function Main() but i get
Traceback (most recent call last):
File "test.py", line 7, in image
img1 = cv2.imread(Main.file())
AttributeError: 'Program' object has no attribute 'file'
There are some weird things in your code as far as I can see:
I don't know how you're calling the image method, but it currently receives a Main value. Correct me if I'm wrong since this is pure speculation, but I think you wanted to call the Main method of Program. If so, that's not how you do it. You can refactor it as:
class Program:
def Main(self):
fname = QFileDialog.getOpenFileName()
filepath = str(fname[0])
fileObject = filepath.split('/')
file = fileObject[len(fileObject) - 1]
# Remove Main from method signature, since it's a method from Program
def image(self):
# Call Main from the self object
img1 = cv2.imread(self.Main.file())
You're calling self.Main.file() inside the image method. Since Main is a method and it does not have another method called file, it'll throw a AttributeError. Another pure speculation, but I think you wanted to access the variable file inside the Main method. If so, that's not how you do it. You can't access a variable inside another method, but you can access a value returned by that method. You can refactor your Main to return the file that you want (and rename it to a proper name, such as get_file):
class Program:
# Rename Main to a more descriptive name
def get_file(self):
fname = QFileDialog.getOpenFileName()
filepath = str(fname[0])
fileObject = filepath.split('/')
# Return it so we can access this value outside of it
return fileObject[len(fileObject) - 1]
def image(self):
# Access the file returned by get_file
# Since this a method of Program, call it using the self object
file = self.get_file()
# Use the returned value
img1 = cv2.imread(file)
Some minor improvements:
class Program:
# Rename Main to a more descriptive name
def get_file(self):
fname = QFileDialog.getOpenFileName()
filepath = str(fname[0])
fileObject = filepath.split('/')
# You can remove use -1 as index to the last value
return fileObject[-1]
def image(self):
file = self.get_file()
# Probably you want to return the variable below
return cv2.imread(file)
Full code:
class Program:
def get_file(self):
fname = QFileDialog.getOpenFileName()
filepath = str(fname[0])
fileObject = filepath.split('/')
return fileObject[-1]
def image(self):
file = self.get_file()
return cv2.imread(file)

How to pass a variable from a function to a class?

How can I print path outside function:
class FirstClas:
path = ''
def num(self):
path = "C:\\Users\\JOHN\\Desktop\\test.txt"
return path
print(path)
This method don't print anything.
This result:
C:\Python\python.exe C:/Users/JOHN/Desktop/test/tt.py
Process finished with exit code 0
You need to create an instance from the class that you created.
I would suggest doing this:
test = FirstClas()
print(test.num())
Hope this helps
Your method never gets called, and the class variable path is pointless here. Do:
class FirstClas:
def num(self):
path = "C:\\Users\\JOHN\\Desktop\\test.txt"
return path
print(FirstClas().num()) # note that this is outside the class!
I don't think you quite understand the purpose of classes, but here's how to make what you have "work" (in the sense that there are no fatal errors):
File global_variable.py
def init_global_variable():
"""initialize variable"""
global GLOBALS_DICT
GLOBALS_DICT = {}
def set_variable(name, value):
"""set variable"""
try:
GLOBALS_DICT[name] = value
return True
except KeyError:
return False
def get_variable(name):
"""get variable"""
try:
return GLOBALS_DICT[name]
except KeyError:
return "Not Found"
init_global_variable() # ADDED.
File tt.py
import os
#import lib.global_variable as glv
import global_variable as glv # Since I don't have your whole package.
class FirstClas:
def num(self):
path = "C:\\Users\\JOHN\\Desktop\\test.txt"
return path
def imag(self):
icon_file = os.path.join(
glv.get_variable("APP_PATH"),
glv.get_variable("DATA_DIR"),
"paths",
"PathExcel",
)
return icon_file
class Second:
# Put statements in a method so they don't run when the class is defined.
def run(self):
test = FirstClas()
print('first: ' + test.num())
print('second: ' + test.imag())
second = Second()
second.run()
Output:
first: C:\Users\JOHN\Desktop\test.txt
second: Not Found\Not Found\paths\PathExcel
the path does not changed(path = ' ') because you don't run the function num

python - remain in base class when calling parent method from child

I have the following base class:
class ClientRepo(Repository):
def __init__(self) -> None:
self.__clientList = []
def hasClientWithId(self, clientId):
for client in self.__clientList:
if client.getId() == clientId:
return True
return False
def addClient(self, client):
if type(client).__name__ == 'ClientDAO':
if not self.hasClientWithId(client.getId()):
client.setClientId(self.__maximumIndexInClientList() + 1)
self.__clientList.append(client)
else:
raise ObjectAlreadyInCollectionException
else:
raise TypeError
which basically only holds a list and can add a ClientDAO to it.
And the following, which derives from it:
class ClientFileRepository(ClientRepo):
def __init__(self, fileName) -> None:
super().__init__()
self.__fileName = fileName
self.__file = None
def hasClientWithId(self, clientId):
self.__loadRepo()
hasClientWithId = super().hasClientWithId(clientId)
super().clean()
return hasClientWithId
def addClient(self, client):
self.__loadRepo()
super().addClient(client)
self.__storeRepo()
super().clean()
def __loadFileReadMode(self):
self.__file = open(self.__fileName, "r")
def __loadFileWriteMode(self):
self.__file = open(self.__fileName, "w")
def __closeFile(self):
self.__file.close()
def __loadRepo(self):
self.__loadFileReadMode()
for line in self.__file:
splitLine = line.split()
clientToAdd = ClientDAO(splitLine[1])
clientToAdd.setClientId(int(splitLine[0]))
super().addClientWithId(clientToAdd)
self.__closeFile()
def __storeRepo(self):
self.__loadFileWriteMode()
self.__file.write("")
for client in super().getList():
self.__file.write(self.clientToString(client))
self.__closeFile()
def clientToString(self, clientDAO):
return str(clientDAO.getId()) + " " + clientDAO.getName() + "\n"
a class which should load the list from a file, call addClient from parent, and store the updated list in the file. The problem is that after child class loads the file in addClient, it calls the method in the parent, which calls hasClientWithId, from the child, again. But I want it to call hasClientWithId, from the parent, that is, the context it is in. Can I achieve that?
I can think of several ways to achieve your goal. I ranked them from worst to best
1. Exactly what you asked for
You wanted that ClientRepo.addClient calls ClientRepo.hasClientWithId instead of ClientFileRepository.hasClientWithId. It is possible to enforce that:
class ClientRepo(Repository):
def addClient(self, client):
if type(client).__name__ == 'ClientDAO':
if not ClientRepo.hasClientWithId(self, client.getId()):
client.setClientId(self.__maximumIndexInClientList() + 1)
self.__clientList.append(client)
else:
raise ObjectAlreadyInCollectionException
else:
raise TypeError
This is not a good approach, because it's unintuitive and breaks the principles of OOP. Any other programmer writing a subclass of ClientRepo that overrides hasClientWithId would expect that this will have an effect for every call to hasClientWithId even inside of addClient
2. Let ClientFileRepository decide which function to use
Add a variable
self.__isFileOpen = False
in ClientFileRepository.__init__, set it to True when you open the file and to False when you close the file. Then change the hasClientWithId within ClientFileRepository to
def hasClientWithId(self, clientId):
if not self.__isFileOpen:
self.__loadRepo()
result = super().hasClientWithId(clientId)
super().clean()
return result
else:
return super().hasClientWithId(clientId)
to avoid opening the same file again. This works, but it is pretty difficult to write new functions for this class, because you always need to be aware if the function call is a call from within your class or from somewhere else. Also this seems pretty inefficient, because you read and write the entire file, even when you only add one client.
3. Read the file only once and modify the underlying ClientRepo
class ClientFileRepository(ClientRepo):
def __init__(self, fileName) -> None:
super().__init__()
self.__fileName = fileName
self.__loadRepo()
# No hasClientWithId needed
def addClient(self, client):
super().addClient(client)
self.__storeRepo()
def __loadRepo(self):
with open(self.__filename) as file:
for line in file:
splitLine = line.split()
clientToAdd = ClientDAO(splitLine[1])
clientToAdd.setClientId(int(splitLine[0]))
super().addClientWithId(clientToAdd)
def __storeRepo(self):
with open(self.__filename, "w") as file:
file.write("")
for client in super().getList():
file.write(self.clientToString(client))
This obviously assumes that the file is not changed by someone else between calls to addClient and the program still overwrites the entire file for every addClient. If this is a problem for you it is best to be explicit and make loadRepo and storeRepo public. Then the programmer using this class can decide when loading and saving are necessary and useful. You can use context managers for this.
Extra: Read and save the file for every method
You can use function decorators to use solution 2 without writing the same code for every function:
import functools
def loadAndStore(function):
#functoools.wraps(function)
def wrappedFunction(self, *args, **kwargs):
if self.__isFileOpen:
return function(self, *args, **kwargs)
else:
self.__isFileOpen = True
self.__loadRepo()
try:
return function(self, *args, **kwargs)
except Exception as e: # Only catch expected exceptions
raise
finally:
self.__storeRepo()
self.clear() # some cleanup
self.__isFileOpen = False
return wrappedFunction
class ClientFileRepository(ClientRepo):
def __init__(self, fileName) -> None:
super().__init__()
self.__fileName = fileName
self.__isFileOpen = False
#loadAndStore
def hasClientWithId(self, clientId):
return super().hasClientWithId(clientId)
#loadAndStore
def addClient(self, client):
super().addClient(client)
def __loadRepo(self):
with open(self.__filename) as file:
for line in file:
splitLine = line.split()
clientToAdd = ClientDAO(splitLine[1])
clientToAdd.setClientId(int(splitLine[0]))
super().addClientWithId(clientToAdd)
def __storeRepo(self):
with open(self.__filename, "w") as file:
file.write("")
for client in super().getList():
file.write(self.clientToString(client))
Be careful here, using this is not very intuitive. For example self.__isFileOpen is defined in __init__, but none of the methods below directly use it. Instead its use is hidden in the loadAndStore decorator.
Some quick hints at the end:
type(client).__name__ == 'ClientDAO' is bad practice. Use isinstance(client, ClientDAO) to fully adopt OOP
If this is not part of a bigger project with given naming conventions use the python style guide
Using private variables like __fileName is generally considered unnecessary, just prefix the variable with one underscore to indicate "internal use". The same is true for functions.

Using one class from another class

I wrote a simple program to read through a log and to parse through and obtain the lowest beginning number (the head) and to print it. I am now editing that program and combining it with a class I wrote to parse an actual logfile. Essentially, as opposed to sorting based off of the simple number from the log from my previous program, I now need to reference the parsed information from one class into another class. I was wondering what the most convenient way to do this. I am a beginner programmer in python and don't know if I can explicitly reference the class.
Here are the classes.
Parser
class LogLine:
SEVERITIES = ['EMERG','ALERT','CRIT','ERR','WARNING','NOTICE','INFO','DEBUG']
severity = 1
def __init__(self, line):
try:
m = re.match(r"^(\d{4}-\d{2}-\d{2}\s*\d{2}:\d{2}:\d{2}),?(\d{3}),?(\s+\[(?:[^\]]+)\])+\s+[A-Z]+\s+(\s?[a-zA-Z0-9\.])+\s?(\((?:\s?\w)+\))\s?(\s?.)+", line)
timestr, msstr, sevstr, self.filename, linestr, self.message = m.groups()
self.line = int(linestr)
self.sev = self.SEVERITIES.index(sevstr)
self.time = float(calendar.timegm(time.strptime(timestr, "%Y-%m-%d %H:%M:%S,%f"))) + float(msstr)/1000.0
dt = datetime.strptime(t, "%Y-%m-%d %H:%M:%S,%f")
except Exception:
print 'error',self.filename
def get_time(self):
return self.time
def get_severity(self):
return self.sev
def get_message(self):
return self.message
def get_filename(self):
return self.filename
def get_line(self):
return self.line
Sorter
class LogFile:
def __init__(self,filepath):
self.logfile = open(filepath, "r")
self.head = None
def __str__(self):
return "x=" + str(self.x) + "y="+str(self.y)
def readline(self):
if self.head != None:
h = self.head
self.head = None
return h
else:
return self.logfile.readline().rstrip(' ')
def get_line(self):
if self.head == None:
self.head = self.readline().rstrip(' ')
return self.head.get.line()
else:
return self.head.get.line()
def close (self):
self.logfile.close()
I have begun to edit my second class by adding the get_line function. Don't know if I'm on the right track.
In simpler terms, I need the head to become "LogLine"
It is okay to use one class from another class. You have one class that parses a single line from a log file and builds an object that represents the line; and you have another class that reads lines from a log file. It would be very natural for the second class to call the first class.
Here is a very simple class that reads all lines from a log file and builds a list:
class LogFile(object):
def __init__(self,filepath):
with open(filepath, "r") as f:
self.lst = [LogLine(line) for line in f]
You can see that self.lst is being set to a list of lines from the input log file, but not just the text of the line; the code is calling LogLine(line) to store instances of LogLine. If you want, you can sort the list after you build it:
self.lst.sort(key=LogLine.get_line)
If the log files are very large, it might not be practical to build the list. You have a .get_line() method function, and we can use that:
class LogFile(object):
def __init__(self,filepath):
self.logfile = open(filepath, "r")
def get_line(self):
try:
line = next(self.logfile) # get next line from open file object
return LogLine(line)
except StopIteration: # next() raises this when you reach the end of the file
return None # return
def close(self):
self.logfile.close()
An open file object (returned by the open() function) can be iterated. We can call next() on this object and it will give us the next input line. When the end of file is reached, Python will raise StopIteration to signal the end of the file.
Here the code will catch the StopIteration exception and return None when the end of the log file is reached. But I think this isn't the best way to handle this problem. Let's make the LogFile class work in for loops and such:
class LogFile(object):
def __init__(self,filepath):
self.f = open(filepath)
def __next__(self): # Python 3.x needs this to be named "__next__"
try:
line = next(self.f)
return LogLine(line)
except StopIteration:
# when we reach the end of input, close the file object
self.f.close()
# re-raise the exception
raise
next = __next__ # Python 2.x needs this to be named "next"
A for loop in Python will repeatedly call the .__next__() method function (Python 3.x) or else the .next() method function (Python 2.x) until the StopIteration exception is raised. Here we have defined both method function names so this code should work in Python 2.x or in Python 3.x.
Now you can do this:
for ll in LogFile("some_log_file"):
... # do something with ll, which will always be a LogLine instance

Python Issue - Map and Classes - Beginner

I'm attempting to use Map to reference a class function, but am having difficulty with formatting/ordering. I have heard that using map is sort of obsolete so I am definitely open to alternative solutions (for loops?) Thanks in advance.
lognames = [ "C:\Users\makker1\Desktop\logs\loga.txt",
"C:\Users\makker1\Desktop\logs\logb.txt",
"C:\Users\makker1\Desktop\logs\logc.txt" ]
class LogFile:
def __init__(self,filepath):
self.logfile = open(filepath, "r")
self.head = None
def __str__(self):
return "x=" + str(self.x) + "y="+str(self.y)
def readline (self):
if self.head != None:
self.head = self.logfile.readline()
def previewline (self):
if self.head == None:
self.head = self.logfile.readline()
def close (self):
self.logfile.close()
logs = map(LogFile(self,filepath).__init__(), lognames)
heads = map(lambda log: None, logs)
>>>
Traceback (most recent call last):
File "C:\Users\makker1\Desktop\mergesort-final.py", line 30, in <module>
logs = map(LogFile(self,filepath).__init__, lognames)
NameError: name 'self' is not defined
>>>
If any more info is needed, please let me know. I realize that there are tons of posts about this very problem and have sorted through many of them with no avail.
Here is a list comprehension answer. I like this better than map().
logs = [LogFile(fname) for fname in lognames]
You don't have to call __init__ explicitly. Try:
logs = map(LogFile, lognames)
Sometimes it helps to think of a class as being callable. You can think of a class as something like the following:
def LogFile(filepath):
class _LogFile:
def __init__(self, path):
...
return _LogFile(filepath)
Basically, a class can be thought of as something that you call to create an object instance. This isn't really true, but in many cases it will appear to be.

Categories