my task is actually pretty simple. Maybe I'm too much used to c++ to not see my fault.
I have two classes and a list.
The list should include all objects made of class1, while class1 also includes a list for all objects of class2.
So we have:
All_Objects1 = [] # For class1 objects
class class1 (object):
All_Objects2 = [] # For class2 objects
class class2 (object):
name = ""
number = 0
Now I do this:
# class1 objects:
obj1= class1()
obj2= class1()
# class2 objects
obj3 = class2()
obj3.name, obj3.number = "hello world", 10
obj4 = class2()
obj4.name, obj3.number = "hello europe", 20
obj5 = class2()
obj5.name, obj3.number = "hello asia", 30
obj6 = class2()
obj6.name, obj3.number = "hello africa", 40
# Attach object3 and object4 to object1
obj1.All_Objects2.append(obj3)
obj1.All_Objects2.append(obj4)
# Attach object5 and object6 to object2
obj2.All_Objects2.append(obj5)
obj2.All_Objects2.append(obj6)
# Attach obj1 and obj2 to the global list.
All_Objects1.append(obj1)
All_Objects1.append(obj2)
And finally I do a print for checking if everything is where it belongs:
print (len(All_Objects1[0].All_Objects2)) # Should be 2.
for i in All_Objects1[0].All_Objects2:
print (i.name) # Should be world and europe.
print (len(All_Objects1[1].All_Objects2)) # Should be 2.
for i in All_Objects1[1].All_Objects2: # Should be asia, africa.
print (i.name)
Now the problem is, that every object2 is in every object1 and I have no clue why.
In my actual program I do something like this, what would actually work in c++:
#pseudo
for i in all_information:
if (i==Keyword):
currentObject = class1()
All_objects.append(currentObject)
And then I will have some independent objects in my list. But in Python I think I somehow can't overwrite "currentObject".
Thank you so much for your help.
In Python somethings could be making this error, first which version×of Python are you using?
I have not tested on my console yet but I would guess that it's a initialization issue, for how you are declaring the list, I would rather suggest to use a more Pythonic approach, I mean, build a constructor and use keyword self for instance variables, if this works, I can extend my answer explaining why this happened.
Create a method like this in class 1 and class 2:
def __init__(self, object_list=None) : # use corresponding classes attributes.
if self.name_of_your_variable:
self.name_of_your_variable= [] # or proper value
Adapt this to your classes and let me know, if it works, as soon I get home I'll extend it
With Python, all class members declared outside any function are static members. So they are shared by each object instantiated from the class.
What you want is the following:
class class1 (object):
def __init__(self):
self.All_Objects2 = [] # For class2 objects
class class2 (object):
def __init__(self):
self.name = ""
self.number = 0
You need just to initialized your class. init and you need only one All objects list. An example with class you can find below.
class firstA():
def __init__(self):
self.All_Objects = []
class secondB():
def __init__(self):
self.name ="None"
self.number = 0
When you are calling the class the initialization will be done :-) That is very nice in python2/3.
Whatever you initialized outside the class will be considered as a static variable! So in your example the All_Objects1 list for instance.
Hope this clarify your doubts! Have a nice day.
Related
class Person:
number_of_people = 0 #class atribute,define for the entire class
def __init__(self,name):
self.name=name
p1 = Person('tim') # adding of object to class
p2 = Person('jill')
p3 = Person('Bill')
for x in range(Person.number_of_people): #will loop 3 time this case
print(Person.name) # how do i print all the names in a class
i cant seem to get this working
You would need a global variable to keep track of each instance this way, but more likely you would define a parent class, like People, and then have your Person class inherit from People. People would instead be in charge of tracking how many Person instances you've created. The latter option would be best if you have to look at more than just this one relationship between your Person instances. If you wanted to iterate through your Persons, for example, that could be a methods of your People class.
You could initialize a variable NUMBER_OF_PEOPLE=0 outside your class declaration and then each time someone call __init__ you can add one:
class Person:
# Declare class variables
NUMBER_OF_PEOPLE = 0
LIST_OF_PEOPLE = []
def __init__(self, name):
self.name = name
# Change the class variables
Person.LIST_OF_PEOPLE.append(self)
Person.NUMBER_OF_PEOPLE += 1
#classmethod
def get_number_of_people(cls):
return Person.NUMBER_OF_PEOPLE
p1 = Person("tim")
p2 = Person("jill")
people = [p1, p2] # create a list o two people
# Iterate through the list
for p in Person.LIST_OF_PEOPLE:
# Access the name by calling p.name
print("Name of the current person is: {}.".format(p.name))
# You can still access the NUMBER_OF_PEOPLE variable either by calling Person.get_number_of_people() (since it is a class method)
# or by simply using the NUMBER_OF_PEOPLE variable.
print("Currently, there are {} number of people in the class!".format(Person.get_number_of_people()))
# This will give 1 person.
Your issue here is that you don't completely understand object-oriented programming. You will get better by practising.
First off I apologize if my terminology is way off and this is a basic question that has been answered a million times! I am trying to figure this out without knowing what it is called, so my searches have not been turning anything useful up...
I often find myself assigning certain "properties" to class instances in python which I will want to modify and reference later. A good example would be the "status" of an instance like in the following code:
class Example:
def __init__():
self.status = "NORMAL"
a = Example()
print(a.status)
a.status = "CANCELLED"
print(a.status)
While this certainly works it requires that the property is a string, which is not very maintainable and is quite prone to error. Is there some way of assigning an object to the class which can be passed to an attribute? For example (and I know this does not work):
class ExampleWithProperty:
NORMAL
CANCELLED
def __init__()
self.status = self.NORMAL
b = Example()
print(b.status)
# would expect: ExampleWithProperty.NORMAL or b.NORMAL
b.status = b.CANCELLED
print(b.status)
# would expect: ExampleWithProperty.CANCELLED or b.CANCELLED
I believe I've seen a similar functionality in other languages but I wasn't able to think of how to do this in python!
I think you're looking for Enums
>>> from enum import Enum
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
...
https://docs.python.org/3/library/enum.html
Edit:
from enum import Enum
class Status(Enum):
NORMAL = 1
CHANGED = 2
class MyClass:
def __init__(self):
self.status = Status.NORMAL
instance = MyClass()
instance.status = Status.CHANGED
To add to sergenp's helpful answer, this is how I would add an Enum to an existing class in a visually "cleaner" way which will be easier to reference from outside the class:
class Example():
class StatusOptions(Enum):
NORMAL = 0
CANCELLED = 1
def __init__(self):
self.NORMAL = self.StatusOptions.NORMAL
self.CANCELLED = self.StatusOptions.CANCELLED
self.status = self.StatusOptions(self.NORMAL)
a = Example()
print(a.status)
a.status = a.CANCELLED
print(a.status)
print(a.status == a.CANCELLED)
So I am trying to get my data structure set up for an automated generator I am writing for a roleplaying game and I am having trouble with some specific inheritance quirks. Here is an excerpt of the data structure.
class data():
def __init__(self):
self.races = Races()
class Races(data):
def __init__(self):
self.humans = Humans()
class Humans(Races):
def __init__(self):
self.Characteristics = {
'Brawn':2,
'Agility':2,
'Intellect':2,
'Cunning':2,
'Willpower':2,
'Presence':2
}
There is a lot more in the structure but this is just a bottom to top overview. I also know it is indented weirdly but that is strictly stack overflow.
Now I wish to have two behaviors from this object.
The ability to call any characteristic with
data.races.humans.Characteristic['brawn']
as the calling format.
And too also be able to iterate through subclasses with a generator like:
(subclass for subclass in data.races.__subclasses__())
obviously after I have instantiated the object.
Now I have tried changing the structure several times and I can get it so EITHER I can call it with dot notation, but it returns AttributeError: 'Races' object has no attribute '__subclasses__'
Or vice versa by completely separating it into a more traditional structure but then I cannot call in dot notation and this makes it very hard to keep everything organized and readable.
Can anyone suggest what I am doing wrong or a more Pythonic way to approach the problem?
Let's start in the middle. Presumably, a character of any race has the same attributes, just different values for those attributes.
class Race:
def __init__(self):
self.life = 100 # 100% healthy
class Humanoid(Race):
def __init__(self):
super().__init__()
self.legs = 2
class Insectoid(Race):
def __init__(self):
super().__init__()
self.legs = 8
class Human(Humanoid):
def __init__(self):
super().__init__()
self.brawn = 2
self.agility = 2
self.intellect = 2
self.cunning = 2,
self.willpower = 2
self.presence = 2
class Elf(Humanoid):
def __init__(self):
super.__init__()
self.brawn = 1
self.agility = 3
self.intellect = 3
self.cunning = 2
self.willpower = 3
self.presence = 1
Now, any particular character would be instantiated as the correct class:
some_elf_1 = Elf()
some_human_1 = Human()
some_human_2 = Human()
for character in [some_elf_1, some_human_1, some_human_2]:
print("Brawn: ", character.brawn)
In the preceding, it doesn't matter what the actual type of each character is; as long as you know that it is some subclass of Race (or an instance of Race itself), it will have a brawn attribute that you can access.
You data class doesn't really seem necessary without more detail.
So, While the answer given put me on the right track I realized what I needed and am just throwing in my lot for any poor souls.
Firstly - I realized what was wrong with my generator, I was calling on the initialized object instead of the class object. Objects do not have a subclasses attrib and I was mis-informed by most of the guides I read!
Secondly, I considered using a metaclass to get the iterating behavior I wanted from my objects can simply be achieved with a registry attribute that is a dict of all the initialized subclasses.
lass Races(data):
def __init__(self):
self.humans = Humans()
self.droids = Droids()
self.twileks = Twileks()
self.registry = {
'humans':self.humans,
'droids':self.droids,
'twileks':self.twileks
}
This allows me to iterate through certain values for different races after they have been initialized.
Thanks for all the great answers!
Let's say I have a class called Test with an attribute items. Then I create a subclass called Best. Which has a method that modifies the classes attribute items. But it even modifies Test's items and I what it to modify items only for Best.
class Test():
items = []
class Best(Test):
def method(self):
type(self).items.append("a test")
>>> Best().method()
>>> Best.items
["a test"]
>>> Test.items
["a test"] # This is what I don't want.
You have declared items as an attribute of the superclass itself, so all instances of Test and it's subclasses will share the same list. Instead declare it in Test's __ init __ method, so there is one list per instance.
In Best, just append to self.items, and only the Best instance's list will be updated.
class Test(object):
def __ init __(self)
self.items = []
class Best(Test): # Best must inherit from Test
def method(self):
self.items.append("a test")
In Python you can get what you are asking by using "private" members...
class Base(object):
def __init__(self):
self.__mine = 42 # note the double underscore
def baseMethod(self):
return self.__mine
class Derived(Base):
def __init__(self):
Base.__init__(self)
self.__mine = 99
def derivedMethod(self):
return self.__mine
obj = Derived()
print(obj.baseMethod(), obj.derivedMethod()) ## ==> 42, 99
this works because at compile time Python will replace the name __mine with _Base__mine when compiling Base and with _Derived__mine when compiling Derived.
Note however that in Python while this is possible in my experience it's not used very often. Deriving a class in many cases is just not needed thanks to "duck typing" and to delegation, something that is not possible in languages like C++ or Java.
The only possible way to do this is to create a new items on the subclass -- where else is this new list meant to come from? Also type(self) is redundant. The lookup machinery looks up attributes on the class if it cannot find the attribute on the instance. Better yet, if you don't need an instance then declare the method to be a class method.
eg.
class Test:
items = []
#classmethod
def method_test(cls):
cls.items.append('test')
class Best(Test):
items = []
#classmethod
def method_best(cls):
cls.items.append('best')
Test.method_test()
assert Test.items == ['test']
assert Best.items == []
Test.items = []
Best.method_test()
Best.method_best()
assert Test.items == []
assert Best.items == ['test', 'best']
Note that method_test works on the Best class when called from the Best class.
Your Best class is modifying Test (which I assume it's supposed to be inheriting from) because Best doesn't have its own items list. When you access Best.items, you're accessing the list where it is inherited from (i.e. from Test class). If you want a different list, you need to create it explicitly in the subclass Best:
class Best(Test):
items = [] # hide the inherited list with our own list
# ...
Your code doesn't do what you describe.
For one thing, Best is not a subclass of Test.
For another Best.method() produces
NameError: name 'self' is not defined
items is a Test class attribute.
t = Test()
t.items.append(1)
changes Test.items.
As defined B.items gives an AttributeError.
Even if I change:
class Best():
def method(self):
...
Best.method() does not run; method is an instance method. I need to use Best().method(). But then I get the items AttributeError.
class Best(Test):
def method(self):
...
does what you desribe. Best().method() modifies the Test.items - because the Test class attribute is shared with the subclass.
As shown in other answers, simply defining items for Best decouples its value from the Test class attribute
class Best(Test):
items = ['other']
...
In python, I want to make a class variable static so I can to use it from a different instance. is there any solution?
I don't follow your question exactly, but it seems to me you're asking how to make instance variables in Python. The answer is to set them inside a method, preferably __init__() using the self reference.
class Foo(object):
classVar = 0 #this is a class variable. It is shared between all instances
def __init__(self, instanceVar):
self.someVar = instanceVar
obj1 = Foo(10)
obj2 = Foo(42)
print obj1.classVar # prints 0
print obj2.classVar # prints 0
print obj1.someVar #prints 10
print obj2.someVar #prints 42