Using Python 3.3, I want to bind a class Test to another class called TestManager so that the manager creates instances of Test and stores them to give an access to them afterwards.
In a nutshell (I mean, Python shell...), I want to be able to do this (assuming name is an attribute of Test):
> t = Test.objects.get(id=3)
> t.name
# Returns 'Name 3'
The trick is that my collection of objects is a "static" collection, in a sense that it is created at first (not by any user) and then never modified or deleted, nor its records removed or edited. It's fixed.
So here is the code I tried:
class TestManager:
def __init__(self, *args, **kwargs):
self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]
def get(self, id):
return self._tests[id]
class Test:
objects = TestManager()
def __init__(self, name=''):
self.name = name
Aaaand, as expected, NameError: global name 'Test' is not defined due to the circular initialization. Ideally, I should have a create() method in the manager which would take care of adding elements in the list (instead of the __init__()), but that would mean that the creation is not done in the manager but elsewhere.
The "best" solution I came up with, so far, is to check first in the get() method if the list is empty, and thus call a fill_the_damn_list() method, but it seems very hackish to me. Another way to do that would be to use a dict instead of a list and to create the instances on the fly at first get(). The advantage of the latter one is that it does not create useless/never get()-ed instances, but with only an hundred of them in total, I am not sure it really matters, and the hackish-ness of this solution looks quite the same to me...
As I am quite new to Python (if it isn't clear enough...), I wonder if there is a better way to do that and to keep it simple. I am also OK to refactor if needed, but I didn't find any better solution yet...
Your design seems a little odd -- it's unclear why the Test class needs a reference to a TestManger instance. Regardless, I think the following will make that happen. It uses a metaclass to create the objects attribute of the Test class and adds the _tests attribute you want to the TestManger instance it created -- which all go into making this a rather peculiar answer...fitting, I suppose. ;-)
class TestManager:
def __init__(self, *args, **kwargs):
print('creating TestManager')
def get(self, id):
return self._tests[id]
class TestMetaClass(type):
def __new__(mcl, name, bases, classdict):
# add an "objects" attribute to the class being created
classdict['objects'] = tm = TestManager()
cls = type.__new__(mcl, name, bases, classdict)
# add a "_tests" attribute to the TestManager instance just created
# (can't use class's name, since it hasn't been returned yet)
tm._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
return cls
class Test(metaclass=TestMetaClass):
def __init__(self, name=''):
self.name = name
t = Test.objects.get(3)
print(t.name)
I completely agree with sean's comment: your design is strange and, I think, quite useless, and this is causing problems even before starting using it. Anyway, if you want to do that you can use a lot of different methods.
The simple way:
class TestManager:
def __init__(self, *args, **kwargs):
self._tests = [Test(name='Name {}'.format(i)) for i in range(100)]
def get(self, id):
return self._tests[id]
class Test:
objects = None
def __init__(self, name=''):
self.name = name
Test.objects = TestManager()
An other approach can be using a decorator:
>>> class TestManager(object):
... def __init__(self, *args, **kwargs):
... self._tests = []
... def init_class(self, cls):
... self._tests = [cls(name='Name {}'.format(i)) for i in range(100)]
... cls.objects = self
... return cls
... def get(self, id):
... return self._tests[id]
...
>>> manager = TestManager()
>>> #manager.init_class
... class Test(object):
... def __init__(self, name=''):
... self.name = name
...
>>> manager.get(5)
<__main__.Test object at 0x7f4319db8110>
The above recipe works if TestManager is a Singleton, but if it is not a singleton you simply have to remember to call TestManager.init_class(TheClass) before accessing the class instances, and that can be done anywhere in your code.
You can also use getters for this:
>>> class TheGetter(object):
... def __init__(self, cls):
... self._cls = cls
... self._inst = None
... def __get__(self, inst, owner):
... if self._inst is None:
... self._inst = self._cls()
... return self._inst
...
>>> class Test(object):
... objects = TheGetter(TestManager)
... def __init__(self, name):
... self.name = name
...
>>> Test.objects.get(5)
<__main__.Test object at 0x7f431690c0d0>
Related
Suppose that I have two classes:
a class named Swimmer
a class named Person
For my particular application, we can NOT have Swimmer inherit from Person, although we want something like inheritance.
Instead of class inheritance each Swimmer will have an instance of the Person class as a member variable.
class Person:
pass
class Swimmer:
def __init__(self, person):
self._person = person
def __getattr__(self, attrname:str):
try:
attr = getattr(self._person)
return attr
except AttributeError:
raise AttributeError
Perhaps the Person class has the following class methods:
kneel()
crawl()
walk()
lean_over()
lay_down()
The Swimmer class has all of the same methods as the Person class, plus some additional methods:
run()
swim()
dive()
throw_ball()
When it comes to kneeling, crawling, walking, and laying down, a Swimmer is meant to be a transparent wrapper around the Person class.
I want to write something like this:
swimmer_instance = SwimmerClass(person_instance)
I wrote a __getattr__() method.
However, I ran into many headaches with __getattr__().
Consider writing the code self.oops. There is no attribute of the _Swimmer class named oops. We should not look for oops inside of self._person.
Aanytime that I mistyped the name of an attribute of Swimmer, my computer searched for that attribute in the instance of the Person class. Normally, fixing such spelling mistakes is easy. But, with a __getattr__() method, tracking down the problem becomes difficult.
How can I avoid this problem?
Perhaps one option is create a sub-class of the Swimmer class. In the sub-class have have a method, the name of which is a misspelling of __getattr__. However, I am not sure about this idea; please advise me.
class _Swimmer:
def __init__(self, person):
self._person = person
def run(self):
return "I ran"
def swim(self):
return "I swam"
def dive(self):
# SHOULD NOT LOOK FOR `oops` inside of self._person!
self.oops
return "I dove"
def _getattrimp(self, attrname:str):
# MISSPELLING OF `__getattr__`
try:
attr = getattr(self._person)
return attr
except AttributeError:
raise AttributeError
class Swimmer(_Swimmer):
def __getattr__(self, attrname:str):
attr = self._getattrimp(attrname)
return attr
Really, it is important to me that we not look inside of self._person for anything except the following:
Kneel()
Crawl()
Walk()
Lean()
LayDown()
The solution must be more general than just something what works for the Swimmer class and Person class.
How do we write a function which accepts any class as input and pops out a class which has methods of the same name as the input class?
We can get a list of Person attributes by writing person_attributes = dir(Person).
Is it appropriate to dynamically create a sub-class of Swimmer which takes Person as input?
class Person:
def kneel(self, *args, **kwargs):
return "I KNEELED"
def crawl(self, *args, **kwargs):
return "I crawled"
def walk(self, *args, **kwargs):
return "I WALKED"
def lean_over(self, *args, **kwargs):
return "I leaned over"
################################################################
import functools
class TransparentMethod:
def __init__(self, mthd):
self._mthd = mthd
#classmethod
def make_transparent_method(cls, old_method):
new_method = cls(old_method)
new_method = functools.wraps(old_method)
return new_method
def __call__(self, *args, **kwargs):
ret_val = self._mthd(*args, **kwargs)
return ret_val
###############################################################
attributes = dict.fromkeys(dir(Person))
for attr_name in attributes.keys():
old_attr = getattr(Person, attr_name)
new_attr = TransparentMethod.make_transparent_method(old_attr)
name = "_Swimmer"
bases = (object, )
_Swimmer = type(name, bases, attributes)
class Swimmer(_Swimmer):
pass
If I understand your question correctly, you want a function that will combine two classes into one.
The way I did this was to create a blank container class with the 3 parameter type() constructor, then loop over every class passed to the function, using setattr to set new attributes of the container class. I had to blacklist the __class__ and __dict__ attributes because Python doesn't allow one to change these. Note that this function will overwrite previously added methods, such as the __init__() method, so pass the class with the constructor last.
I implemented this in the combineClasses function below. I also provided an example. In the example, I created the a basic Person class and a _Swimmer class. I called combineClasses on these two and stored the resulting class as Swimmer, so it can nicely be called as a wrapper class.
def combineClasses(name, *args):
container = type(name, (object,), {})
reserved = ['__class__', '__dict__']
for arg in args:
for method in dir(arg):
if method not in reserved:
setattr(container, method, getattr(arg, method))
return container
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print(f'Hi, I am {self.name}')
class _Swimmer:
def swim(self):
print('I am swimming')
class _Cashier:
def work(self):
print(f'I am working! My name is {self.name}')
Swimmer = combineClasses('Swimmer', _Swimmer, Person)
bob = Swimmer('Bob')
bob.swim() # => "I am swimming"
bob.sayHi() # => "Hi, I am Bob"
print(bob.name) # => "Bob"
print(type(bob)) # => "<class '__main__.Swimmer'>"
I'm trying to store specific actions that are defined within a class.
To reduce code duplication, I would like to make use of a mixin class that stores all the actions based on a decorator.
The idea is that it should be straightforward for other people to extend the classes with new actions. I especially want to avoid that these actions are explicitly listed in the source code (this should be handled by the decorator).
This is what I came up with. Unfortunately, in all .actions lists, all the actions from all the classes are listed.
However, I would like to have a solution that only the actions of the specific class are listed.
class ActionMixin:
actions = []
#staticmethod
def action(fun):
ActionMixin.actions.append(fun)
return fun
class Human(ActionMixin):
#ActionMixin.action
def talk(self):
pass
class Dog(ActionMixin):
#ActionMixin.action
def wuff(self):
pass
class Cat(ActionMixin):
#ActionMixin.action
def miau(self):
pass
if __name__ == "__main__":
party = [Human(), Dog()]
possible_actions = [action for memer in party for action in member.actions]
# I would like that possible_actions is now only Human.talk() and Dog.wuff()
# instead it is 2 times all actions
print(len(possible_actions)) # == 6
I would just write my own descriptor here. So:
class Registry:
def __init__(self):
self._registered = []
def __call__(self, func):
self._registered.append(func)
return func
def __get__(self, obj, objtype=None):
return self._registered
class Human:
actions = Registry()
#actions
def talk(self):
pass
class Dog:
actions = Registry()
#actions
def wuff(self):
pass
class Cat:
actions = Registry()
#actions
def miau(self):
pass
So, instead of inheriting from a mixin, just initialize the descriptor object. Then that object itself can be used as the decorator (the __call__ method!).
Note, the decorator would be whatever name you assigned it, and it would be the name of the attribute where the actions are stored.
In the REPL:
In [11]: party = [Human(), Dog()]
In [12]: [action for member in party for action in member.actions]
Out[12]: [<function __main__.Human.talk(self)>, <function __main__.Dog.wuff(self)>]
EDIT:
You would have to change the implementation if you want this to live in a base class. Basically, use a dict to keep track of the registries, unfortunately, we have to rely on the brittle __qualname__ to get the class in __call__:
class ActionsRegistry:
def __init__(self):
self._registry = {}
def __call__(self, func):
klass_name, func_name = func.__qualname__.rsplit('.', 1)
if klass_name not in self._registry:
self._registry[klass_name] = []
self._registry[klass_name].append(func)
return func
def __get__(self, obj, objtype=None):
if obj is None:
return self
return self._registry[objtype.__qualname__]
class Base:
actions = ActionsRegistry()
class Human(Base):
#Base.actions
def talk(self):
pass
class Dog(Base):
#Base.actions
def wuff(self):
pass
class Cat(Base):
#Base.actions
def miau(self):
pass
I have a big class which has a lot of functions and attributes.
the instances are created from data in a remote database.
the process of creating each instance is very long and heavy.
In performance sake ive created a bunch class from this heavy class.
so accessing the attributed is easy and works great .
the problem is how to use the methods from that class.
ex :
class clsA():
def __init__(self,obj):
self.attrA=obj.attrA
def someFunc(self):
print self
class bunchClsA(bunch):
def __getattr__(self, attr):
# this is the problem:
try:
#try and return a func
func = clsA.attr
return func
except:
# return simple attribute
return self.attr
Clearly this dosent work , Is there a way i could access the instance function staticly and override the "self" var ?
Found out a nice solution to the problem :
from bunch import Bunch
import types
#Original class:
class A():
y=6
def __init__(self,num):
self.x=num
def funcA(self):
print self.x
#class that wraps A using Bunch(thats what i needed .. u can use another):
class B(Bunch):
def __init__(self, data, cls):
self._cls = cls # notice, not an instance just the class it self
super(B, self).__init__(data)
def __getattr__(self, attr):
# Handles normal Bunch, dict attributes
if attr in self.keys():
return self[attr]
else:
res = getattr(self._cls, attr)
if isinstance(res, types.MethodType):
# returns the class func with self overriden
return types.MethodType(res.im_func, self, type(self))
else:
# returns class attributes like y
return res
data = {'x': 3}
ins_b = B(data, A)
print ins_b.funcA() # returns 3
print ins_b.y # returns 6
And this solves my issue, its a hack and if you have the privileges, redesign the code.
I have a Category class which has different names for each categories, the names of the categories can be unknown, good and bad, all categories share the same behavior so i don't want to create sub classes for each type of category, the problem comes when i am trying to
create the different categories in this way:
Category.GOOD
This statement should return a category object with his name setting to 'good' so i try
the following:
class Category(object):
def __init__(self, name):
self.name = name
#property
def GOOD(self):
category = Category(name='good')
return category
#property
def BAD(self):
category = Category(name='bad')
return category
Then i created and use the category with the following output:
c = Category.GOOD
c.name
AttributeError: 'property' object has no attribute 'name'
Realizing that this doesn't work i try a java like approach:
class Category(object):
GOOD = Category(name='good')
BAD = Category(name='bad')
def __init__(self, name):
self.name = name
What i get here is a undefined name "Category" error, so my question is if there is a pythonic way to create a category object like this.
You probably want to use classmethods:
class Category(object):
#classmethod
def GOOD(cls):
category = cls(name='GOOD')
return category
Now you can do c = Category.GOOD().
You cannot do this with a property; you either have to use a classmethod, or create your own descriptor for that:
class classproperty(property):
def __get__(self, inst, cls):
return self.fget(cls)
I'm abusing the property decorator here; it implements __set__ and __del__ as well, but we can just ignore those here for convenience sake.
Then use that instead of property:
class Category(object):
def __init__(self, name):
self.name = name
#classproperty
def GOOD(cls):
return cls(name='good')
#classproperty
def BAD(cls):
return cls(name='bad')
Now accessing Category.GOOD works:
>>> Category.GOOD
<__main__.Category object at 0x10f49df50>
>>> Category.GOOD.name
'good'
I'd use module variables for this. Consider you have the module category.py:
class Category(object):
# stuff...
now you put the two global objects in it:
GOOD = Category(name='good')
BAD = Category(name='bad')
You can use it like that:
from path.to.category import GOOD, BAD
I don't say that this is pythonic but I think this approach is elegant.
The main point that you could not use class definition inside that class definition itself. So the most straight way to achieve what you are want is to use class/static methods as shown below, or even package constants.
class Category(object):
def __init__(self, name):
self.name = name
#classmethod
def GOOD(cls):
return Category(name='good')
#classmethod
def BAD(cls):
return Category(name='bad')
print Category.GOOD().name
or
class Category(object):
def __init__(self, name):
self.name = name
#staticmethod
def GOOD():
return Category(name='good')
#staticmethod
def BAD():
return Category(name='bad')
print Category.GOOD().name
I'd like to do this:
class MyThing(object):
def __init__(self,owning_cls):
self.owning_cls = owning_cls
class MyClass(object):
thing = MyThing(self.__class__)
print MyClass.thing.owning_cls
This doesn't work - as there isn't a self to refer to in the class construction of MyClass.
Is there any way to achieve this (it's clearly trivial if we make thing an instance attribute, but I'd like to be a class attribute please!)?
Perform the call immediately after the class declaration:
class MyClass(object): pass
MyClass.thing = MyThing(MyClass)
Use a decorator. I find this to be a clean solution because it lets you keep more of the class definition together, rather than having to write additional class-related code after the class definition or forcing you to instantiate MyClass, etc.
class MyThing(object):
def __init__(self,owning_cls):
self.owning_cls = owning_cls
def set_thing(cls):
cls.thing = MyThing(cls)
return cls
#set_thing
class MyClass(object):
pass
>>> print MyClass.thing.owner_cls
<class '__main__.MyClass'>
Maybe you can initialize the class with __new__?
Use desciptor:
class Ownable(object):
def __init__(self, clz):
self._clz = clz
self._inst = None
def __get__(self, inst, owner_clz):
self._inst = self._inst or self._clz(owner_clz)
return self._inst
class MyThing(object):
def __init__(self, owner_clz):
self.owner_clz = owner_clz
class MyClass(object):
thing = Ownable(MyThing)
>>> print MyClass.thing.owner_clz
<class '__main__.MyClass'>
Ah, the use MetaClasses comment helps a lot here.
This looks like an "easy" way to achieve exactly what I want
class MyClassMetaclass(type):
def __new__(cls, name, bases, dct):
cls.thing = MyThing(name)
return super(MyClassMetaclass, cls).__new__(cls, name, bases, dct)
class MyThing(object):
def __init__(self,owning_cls):
self.owning_cls = owning_cls
class MyClass(object):
__metaclass__=MyClassMetaclass
print MyClass.thing.owning_cls