How to create a static class "property" object? - python

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)

Related

Circular attributes in Python

I am working with several classes, with each having it's own attributes.
Trying to avoid to pass a lot of variables when calling sub_functions, I would rather call classe's attributes.
As an example, let's concider 2 classes such as :
class Class_A(object):
def __init__(self, element_b):
self.value_specific_to_a = 1
self.element_b = element_b
def element_a_can_do(self):
print(self.element_b.value_specific_to_b)
class Class_B(object):
def __init__(self):
self.element_a = None
self.value_specific_to_b = 2
def add_a(self, element_a):
self.element_a = element_a
def element_b_can_do(self):
print(self.element_a.value_specific_to_a)
item_b = Class_B()
item_a = Class_A(item_b)
item_b.add_a(item_a)
I think that it is pointer's addresses of those classes that are save to each other, but I wonder if it can cause any issue/leak in my code.

Trouble with specific class inheritance behaviour

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!

How to initialise class attributes?

I currently have the following two ways:
class Venue:
store = Database.store()
ids = [vid for vid in store.find(Venue.id, Venue.type == "Y")]
def __init__(self):
self.a = 1
self.b = 2
OR
class Venue:
#classmethod
def set_venue_ids(cls):
store = Database.store()
cls.ids = [vid for vid in store.find(Venue.id, Venue.type == "Y")]
def __init__(self):
self.a = 1
self.b = 2
And before using/instantiating the class I would call:
Venue.set_venue_ids()
What would be the correct way of achieving this?
If it's the first way, what would I do if the instantiation of the attribute required more complex logic that could be done more simply through the use of a function?
Or is there an entirely different way to structure my code to accomplish what I'm trying to do?
From a purely technical POV, a class is an instance of its metaclass so the metaclass initializer is an obvious candidate for class attributes initialization (at least when you have anything a bit complex).
Now given the canonical lifetime of a class object (usually the whole process), I would definitly not use an attribute here - if anyone adds or removes venues from your database while your process is running, your ids attributes will get out of sync. Why don't you use a classmethod instead to make sure your data are always have up to date ?
Oh and yes, another way to construct your Venue.ids (or any other class attribute requiring non-trivial code) without having complex code at the class top-level polluthing the class namespace (did you noticed that in your first example store becomes a class attributes too, as well as vid if using Python 2.x ?) is to put the code in a plain function and call that function from within your class statement's body, ie:
def list_venue_ids():
store = Database.store()
# I assume `store.find()` returns some iterator (not a `list`)
# if it does return a list, you could just
# `return store.find(...)`.
return list(store.find(Venue.id, Venue.type == "Y"))
class Venue(object):
ids = list_venue_ids()
def __init__(self):
self.a = 1
self.b = 2

How to create "individual" objects

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.

Python decorate a class to change parent object type

Suppose you have two classes X & Y. You want to decorate those classes by adding attributes to the class to produce new classes X1 and Y1.
For example:
class X1(X):
new_attribute = 'something'
class Y1(Y):
new_attribute = 'something'
new_attribute will always be the same for both X1 and Y1. X & Y are not related in any meaningful way, except that multiple inheritance is not possible. There are a set of other attributes as well, but this is degenerate to illustrate.
I feel like I'm overcomplicating this, but I had thought to use a decorator, somewhat likeso:
def _xywrap(cls):
class _xy(cls):
new_attribute = 'something'
return _xy
#_xywrap(X)
class X1():
pass
#_xywrap(Y)
class Y1():
pass
It feels like I'm missing a fairly common pattern, and I'd be much obliged for thoughts, input and feedback.
Thank you for reading.
Brian
EDIT: Example:
Here is a relevant extract that may illuminate. The common classes are as follows:
from google.appengine.ext import db
# I'm including PermittedUserProperty because it may have pertinent side-effects
# (albeit unlikely), which is documented here: [How can you limit access to a
# GAE instance to the current user][1].
class _AccessBase:
users_permitted = PermittedUserProperty()
owner = db.ReferenceProperty(User)
class AccessModel(db.Model, _AccessBase):
pass
class AccessExpando(db.Expando, _AccessBase):
pass
# the order of _AccessBase/db.* doesn't seem to resolve the issue
class AccessPolyModel(_AccessBase, polymodel.PolyModel):
pass
Here's a sub-document:
class Thing(AccessExpando):
it = db.StringProperty()
Sometimes Thing will have the following properties:
Thing { it: ... }
And other times:
Thing { it: ..., users_permitted:..., owner:... }
I've been unable to figure out why Thing would sometimes have its _AccessParent properties, and other times not.
Use 3-arguments type:
def makeSomeNicelyDecoratedSubclass(someclass):
return type('MyNiceName', (someclass,), {'new_attribute':'something'})
This is indeed, as you surmised, a reasonably popular idiom.
Edit: in the general case if someclass has a custom metaclass you may need to extract and use it (with a 1-argument type) in lieu of type itself, to preserve it (this may be the case for your Django and App Engine models):
def makeSomeNicelyDecoratedSubclass(someclass):
mcl = type(someclass)
return mcl('MyNiceName', (someclass,), {'new_attribute':'something'})
This also works where the simpler version above does (since in simple cases w/no custom metaclasses type(someclass) is type).
Responding to your comments on voyager's answer:
from google.appengine.ext import db
class Mixin(object):
"""Mix in attributes shared by different types of models."""
foo = 1
bar = 2
baz = 3
class Person(db.Model, Mixin):
name = db.StringProperty()
class Dinosaur(db.polymodel.PolyModel, Mixin):
height = db.IntegerProperty()
p = Person(name='Buck Armstrong, Dinosaur Hunter')
d = Dinosaur(height=5000)
print p.name, p.foo, p.bar, p.baz
print d.height, d.foo, d.bar, d.baz
Running that results in
Buck Armstrong, Dinosaur Hunter 1 2 3
5000 1 2 3
Is that not what you had in mind?
Why can't you use multiple inheritance?
class Origin:
new_attribute = 'something'
class X:
pass
class Y:
pass
class X1(Origin, X):
pass
class Y1(Origin, Y):
pass

Categories

Resources