Python Global Variables in Class? - python

I have a list of instances of my Business class. I'm used to defining the variables for a class at the top of the class. On of the variables in the Business class is a list of tags. When I loop through the list of businesses some have tags, some don't. Out of the 20 businesses the 4th element in the list has 4 tags. After these tags are added to this business all following instances of Business also share these tags. Here is my Business class-
from tag import *
class Business:
name = ""
website = ""
phone = ""
address = ""
city = ""
state = ""
postalCode = ""
tags = []
data = {}
def __init__(self, name):
self.setName(name)
# Modifiers
def setName(self, name):
self.name = name
def setWebsite(self, website):
self.website = website
def setPhone(self, phone):
self.phone = phone
def addTag(self, Tag):
self.tags.append(Tag)
def setAddress(self, address):
self.address = address
def setCity(self, city):
self.city = city
def setState(self, state):
self.state = state
def setPostalCode(self, postalCode):
self.postalCode = postalCode
def set(self, key, value):
self.data[key] = value
def unset(self, key):
del self.data[key]
# Accessors
def getWebsite(self):
return self.website
def getName(self):
return self.name
def getPhone(self):
return self.phone
def getTags(self):
return self.tags
def getAddress(self):
return self.address
def getCity(self):
return self.city
def getState(self):
return self.state
def getPostalCode(self):
return self.postalCode
def get(self, key):
return self.data[key]
def getKeys(self):
return self.data.keys()
# Helpers
And a tag is added to a business like this-
if len(categories) > 1:
for cat in categories:
B.addTag(Tag(cat))
Are the variables defined at the top of my business class global to all instances of Business? How do I fix this problem?

Yes, mutables assigned that way are "global" to the class. To make them "local," define them as instance variables. To do this for tags, for example, remove the global definition that you have and add instead a line to __init__ like:
def __init__(self, name):
self.setName(name)
self.tags = []
This assigns that value of tags to self rather than to the class generally.

You should be doing it this way instead:
from tag import *
class Business:
def __init__(self, name, website='', phone='', address='', city='', state='', postal_code='', tags=None, data=None):
self.name = name
self.website = website
self.phone = phone
self.address = address
self.city = city
self.state = state
self.postal_code = postal_code
self.tags = []
if tags is not None:
for tag in tags:
self.add_tag(tag)
self.data = {} if data is None else data
def add_tag(self, tag):
if not isinstance(tag, Tag):
tag = Tag(tag)
self.tags.append(tag)
def add_data(self, key, value):
self.data[key] = value
def remove_data(self, key):
del self.data[key]
def get_data(self, key):
return self.data[key]
def get_data_keys(self):
return self.data.keys()
Python generally avoids getters and setters unless some extra processing or error-checking is required

Related

Using class and lists in a very specific instance and adding the properties of a class in the list of another class

#so basically I have set up both of my classes here:
class item():
def __init__(self, name, value):
self.name = name
self.value = value
class person():
def __init__(self, name, money):
self.name = name
self.money = money
self.items = []
#And then I have the actual objects here:
sword = item("Sword", 10)
bow = item("Bow", 15)
flame = item("Flame", 20)
player = person("", 0)
#I appended the sword and bow to the player items list, but as an example not the flame:
player.items.append(sword)
player.items.append(bow)
#Add the value of all items on the persons item list, Best I can think of is player.money += player.items[ALL ITEMS AVAILABLE].value
#The idea is that not all items are appended to the list but I can still add them to make a sum to 'buy them', and add more later...
I suggest a little restructuring of the code to make it a bit more OO. Then you just need a function for the Person class that will return the total value of all its Items
class Item():
def __init__(self, name, value):
self.name = name
self.value = value
class Person():
def __init__(self, name, money=0):
self.name = name
self.money = money
self.items = []
def additem(self, item):
self.items.append(item)
def get_total_value(self):
return sum(i.value for i in self.items)
person = Person('gavviegoo')
person.additem(Item('Sword', 10))
person.additem(Item('Bow', 15))
print(person.get_total_value())
Output:
25

search and replace 2 items in a nested list in python

i have a list of until 3 items each item have a list of until 5 items. i need to replace 2 items from another lists.
i get only the strings to change.
without return anything
for example:
i have a class School that have a list of Class [size<=3]. and each class have a list of Student [size<=5]
i get two "name"s of Students, i need to search them in School by running on all Classes and all Students and swap them.
The Student class have a "name" field.
especially if their are not in same ClassRoom
class Student:
def __init__(self, id, name):
self.name = name
self.id = id
class ClassRoom:
def __init__(self):
self.Students[]
class School:
def __init__(self):
self.classes = []
def swap(self, name1, name2):
#???
scl.classes = [c1,c3]
s2 = Student(2,"John")
s6 = Student(6, "Ben")
c1.students = [s1,s2,s3]
c3.students = [s1,s4,s6]
scl.search_replace("John", "Ben")
thanks
You need three classes - School, Class and Student. A School has multiple classes. A Class has multiple students.
In order to be able to easily see what's going on it's a good idea to implement __str__ for each class.
Something like this:
class School:
def __init__(self, name):
self._name = name # name of the school
self._classes = [] # list of classes in the school
#property
def classes(self):
return self._classes
#property
def name(self):
return self._name
def add(self, clazz):
assert isinstance(clazz, Class)
self.classes.append(clazz)
def search(self, name):
for c, clazz in enumerate(self.classes):
if name in clazz.students:
return c, clazz.students.index(name)
return -1, -1
def replace(self, st1, st2):
c1, s1 = self.search(st1)
c2, s2 = self.search(st2)
if s1 >= 0 and s2 >= 0:
self.classes[c1].students[s1], self.classes[c2].students[s2] = self.classes[c2].students[s2], self.classes[c1].students[s1]
def __str__(self):
return f'{self.name}:\n' + '\n'.join(map(str, self.classes))
class Class:
def __init__(self, name):
self._name = name # name of the class
self._students = [] # list of students in the class
#property
def students(self):
return self._students
#property
def name(self):
return self._name
def add(self, student):
assert isinstance(student, Student)
self.students.append(student)
def __str__(self):
return f'{self.name}: ' + ', '.join(map(str, self.students))
class Student:
def __init__(self, name, ident):
self._name = name # student's name
self._ident = ident # student ID
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
#property
def ident(self):
return self._ident
def __str__(self):
return f'{self.name} ({self.ident})'
def __eq__(self, other):
if isinstance(other, str):
return other == self.name
if isinstance(other, Student):
return other.name == self.name
return False
school = School('Tel Aviv High School')
clazz = Class('Psychology')
school.add(clazz) # add the Psychology class to the school
student1 = Student('John', 1)
student2 = Student('Ben', 2)
clazz.add(student1) # add student to the class
clazz.add(student2)
clazz = Class('Chemistry') # add Chemistry class to the school
school.add(clazz)
clazz.add(Student('Haim', 3)) # add student to the class
print(school) # print the school, all of it classes and students within those classes
school.replace('Haim', 'John')
print(school) # print the school again and note that Haim and John have changed places
Output:
Tel Aviv High School:
Psychology: John (1), Ben (2)
Chemistry: Haim (3)
Tel Aviv High School:
Psychology: Haim (3), Ben (2)
Chemistry: John (1)

How can I use Python dependency injection by querying a unique tag (use annotation to register a specific class first)

I am a new user of Python annotation. I am trying to achieve dependency by annotation.
class Trie():
def __init__(self):
self.root = self.Node()
self.count = 0
class Node():
def __init__(self, value=None):
self.value = value
self.children = {}
def add(self, key, value):
path = key.split('.')
node = self.root
for token in path:
if token not in node.children:
node.children[token] = self.Node()
node = node.children[token]
node.value = value
self.count += 1
def get(self, key, default_value=None):
path = key.split('.')
node = self.root
for token in path:
if token not in node.children:
return default_value
node = node.children[token]
self.count -= 1
return node.value
_REGISTRY = Trie()
def register_cls(identifier):
def add_class(cls):
_REGISTRY.add(identifier, cls)
return cls
return add_class
def find_cls(identifier, default_value=None):
return _REGISTRY.get(identifier, default_value)
This is the code to register the class and find the class by class name.
But I do not know how to register a class from another file.
#register_cls('resnet18')
class ResNet18:
def __init__(self):
self.name = 'resnet18'
def get_name(self):
return self.name
if __name__ == '__main__':
name_18 = 'resnet18'
model = find_cls(name_18)
print(model().get_name())
assert model().get_name() == name_18
I can only use this function as this test. find_cls() and #register_cls() in the same file. But this code can store the path of the file, how can I use this function to read the class cross different files.

Don't know what I did wrong in class inheritance/special methods

I'm trying to solve a problem in my class, and I'm not sure what I'm doing wrong.
class Company:
def __init__(self, name=None):
self.name = name
class Travel(Company):
def __init__(self, name=None):
self.name = name
if name == None:
name = "Generic"
super().__init__(name)
def __str__(self, name=None):
self.name = name
return "Company name:{}".format(name)
def __repr__(self):
return "Travel('{self.name}')"
def set_name(self, new_name):
self.new_name = new_name
return new_name
bever = Travel('bever')
print(bever)
bever.set_name('beverly hills')
print(bever)
I want it to return
Company name: bever
Company name: beverly hills
but it just returns
Company name: None
Company name: None
any help is appreciated
You need to change a few things:
Check if name is None before you assign it to self.name
f"Travel('{self.name}')", you forgot to add an f while returning the string in __repr__
Assign new_name to self.name when you use .set_name()
class Company:
def __init__(self, name=None):
self.name = name
class Travel(Company):
def __init__(self, name=None):
if name == None:
name = "Generic"
self.name = name
super().__init__(name)
def __str__(self, name=None):
#self.name = name
return "Company name:{}".format(self.name)
def __repr__(self):
return f"Travel('{self.name}')"
def set_name(self, new_name):
self.name = new_name
return self.name
bever = Travel('bever')
print(bever)
bever.set_name('beverly hills')
print(bever)
This should do the trick
class Company:
def __init__(self, name=None):
self.name = name
class Travel(Company):
def __init__(self, name=None):
if name == None:
name = "Generic" # First set the local parameter
self.name = name # Then the attribute
super().__init__(name)
def __str__(self): # str() does not expect parameters
return f"Company name:{self.name}" # use the instance's attribute instead
def __repr__(self):
return f"Travel('{self.name}')"
def set_name(self, new_name):
self.name = new_name # Update the instance's attribute
return new_name
bever = Travel('bever')
print(bever)
bever.set_name('beverly hills')
print(bever)

How to override attribute in Base class Python3 , so that subsequent operations remains same verywhere?

I have a use case, where I have to override one attribute in base class init, but the operations after that ( by making use of that attribute ) remains the same.
class Person:
def __init__(self, name, phone, record_file = None):
self.name = name
self.phone = phone
if self.record_file:
self.contents = json.load(open(self.record_file))
else:
self.contents = {'person_specific_details': details}
#### Do some operations with self.contents
class Teenager(Person):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# If self.record_file is None:
# self.contents = new for Teenager
self.contents = {'teenager_specific_details': teenager_details}
# But further operations remains the same (#### Do some operations with self.contents)
t = Teenager(phone='xxxxxx', name='XXXXXXX')
I am not able to acheive it properly. Can anyone help?
Your main problem is that you want to change an intermediate value in the Person.__init__, which won't work. But you could create an optional argument for the contents and just use that instead of the default one.
Like this:
class Person:
def __init__(self, name, phone, record_file=None, contents=None):
self.name = name
self.phone = phone
if record_file:
with open(record_file) as fp:
self.contents = json.load(fp)
else:
if contents: # can be utilized by other subclasses
self.contents = contents
else:
self.contents = {"person_specific_details": details}
#### Do some operations with self.contents
class Teenager(Person):
def __init__(self, **kwargs):
contents = {"teenager_specific_details": teenager_details}
super().__init__(contents=contents, **kwargs)
t = Teenager(phone="xxxxxx", name="XXXXXXX")
This way you can pass the Teenager specific contents to the base initializaion, and it can proceed further with that one.

Categories

Resources