I'm trying to create a class that only creates an instance if the arguments passed in during instantiation are a unique combination. If the combination of arguments have previously been passed in, then return the instance that has already been previously created.
I'd like for this class to be inherited by other classes so they inherit the same behavior. This is my first attempt at a solution,
The base/parent class to be inherited:
class RegistryType(type):
def __init__(cls, name, bases, namespace, *args):
cls.instantiated_objects = {}
class AdwordsObject(object, metaclass=RegistryType):
api = AdWordsAPI()
def __new__(cls, *args):
object_name = '-'.join(args)
if object_name in cls.instantiated_objects:
return cls.instantiated_objects[object_name]
else:
obj = super(AdwordsObject, cls).__new__(cls)
cls.instantiated_objects[object_name] = obj
# cls.newt_connection.commit()
return obj
And this is how it's being used in the child class:
class ProductAdGroup(AdwordsObject):
# init method only called if object being instantiated hasn't already been instantiated
def __init__(self, product_name, keyword_group):
self.name = '-'.join([product_name, keyword_group])
#classmethod
def from_string(cls, name: str):
arguments = name.split('-')
assert len(arguments) == 2, 'Incorrect ad group name convention. ' \
'Use: Product-KeywordGroup'
ad_group = cls(*arguments)
return ad_group
I've ran the program with this setup but it seems like a new dict is being created every time ProductAdGroup() is being created so the memory is exploding... even though the program returns the instance that had already been previously instantiated.
Is there anyway to fix this?
Thanks!!!
Your code seems to be right - the only thing incorrect above is that your __init__ method will always be called when instantiating a new class, regardless of a previous instance being returned by __new__ or not.
So, if you create extra objects in your __init__ method, that may be the cause of your memory leak - however, if you bind these new objects to the instane (self), they shuld just override a previously created object in the same place - which would them be freed. . In the code posted here, that happens with self.name- it may be that your real __init__ does more things, and associate new objects to other places than the instance (like, apending them to a list). If your __init__ methods are just as shown the cause for your memory growing is not evident in the code you supply.
As an extra advice, but not related to the problem you relate, I add that you don't need a metaclass for this at all.
Just check for the existence of an cls.instantiated_objects dict in the __new__ method itself. Not writting an unneeded metaclass will simplify your codebase, avoid metaclass conflicts if your class hierarchy evolves, and may even do away with your problem if there is more code on your metaclass than you are showing here.
The base class __new__ method can be rewritten something like this:
class AdwordsObject(object):
def __new__(cls, *args):
if not cls.__dict__.get("instantiated_objects"):
cls.instantiated_objects = {}
name = '-'.join(args)
if name in cls.instantiated_objects:
return cls.instantiated_objects[name]
instance = super().__new__(cls)
cls.instantiated_objects[name] = instance
return instance
And there is no more need for a custom metaclass.
Related
I am writing a server/client code with PyQt5 sockets and I met a strange behavior
First, I derived a class from QTCPSocket, so that I abstract the usage of socket to my data frame, use encryption,..etc before sending the data
So, let this class = mySocket which is an inherited class from QTCPSocket
mySocket has some variables in its init, Ex: self.key. And as I do in all sockets, I connected its readyread signal to my slot of name: rxdata
Now, the problem.
inside rxdata, when I try to get the sender object ( using self.sender() ), what it returns is object of type QTCPSocket not as I was expecting a mySocket object. Which I don't understand
I tried to cast the QTCPsocket returned using qtcpsocketObj.class =mySocket
but the problem now, is mySocket.init() obviously not called, this the variables like self.key won't be defined.
What can I do to overcome this issue?
After a lot of search and debugging,
the problem wasn't from self.sender(). the problem was that the QTCPServer object returns QTCPSocket, and casting it using _ class _() as I did wasn't the right way.
The solution was to derive a class from QTCPServer and instead of making it return QTCPSocket, it will return mySocket class object ( the details is well explained in documentation)
Here is a sample code:
class myQTCPServer(QTcpServer):
def __init__(self,parent=None):
super(myQTCPServer, self).__init__(parent)
def incomingConnection(self,socketDescriptor):
newSock = mySocket(self)
newSock.setSocketDescriptor(socketDescriptor)
self.addPendingConnection(newSock)
Say we have the following set up:
open class Foo(open val img: Image) {
val use = img.graphics
}
class Bar(override val img: BufferedImage) : Foo(img)
On initialization, the use of img.width creates a NPE. What I think the issue is, is that apparently even though img is passed in the constructor of Foo directly in Bar, when it is used in Foo it doesn't point to it, instead it points to the overridden variable in the Bar class. How can I avoid this?
This behavior is caused by the fact that the getter of img is overridden and returns the value of a different field (since Bar overrides img with a different type, it requires creating an additional field of type BufferedImage). The Foo constructor is executed before that field is assigned in Bar.
In general, you should avoid using open members in the initialization logic of your classes, because they may be overridden in the subclasses and may rely on some state that, upon the superclass initialization time, is not properly initialized yet.
For your particular case, make img in the Foo constructor a simple parameter and use the parameter explicitly:
open class Foo(img: Image) {
open val img = img
val use = img.graphics
}
I'm facing a problem and studying the OCaml documentation did not enable me to find a satisfying solution yet.
The following snippet illustrates my problem:
class A = object (self)
(* this should not be overwrittable in subclass B, but callable
on objects of type B!
*)
method dangerous_one input =
(do dangerous stuff...)
let safe_output = safe_dangerous_one input in
(... more dangerous things done with safe_output ...)
(* This is safe, should be overwrittable and callable in subclass *)
method safe_dangerous_one input = (...)
end
class B = object(self) inherit A as super
method! safe_dangerous_one input = (* subclass behaviour ... *)
end
To sum up the snippet: class A is base class to subclass B.
It has a dangerous method that is complex and has some dark corners I don't want client code to have to deal with.
In fact, I want to prohibit subclasses from overwriting method "dangerous_one".
Instead, they should overwrite the function "safe_dangerous_one".
Furthermore, it should be possible to CALL "b#dangerous_one" where "b : B" which uses the (new) definition of the "safe_dangerous"-parts as specified in class B.
My dilemma appears to be: if I simply make method "dangerous_one" private, nothing keeps the client code in class B from overwriting it, potentially even making it public.
If I hide its implementation from the signature, it can not be overwritten anymore, but I cannot call "b#dangerous_one" anymore - the code becomes inaccessible to calls also.
Is there any way to achieve what I aim to do?
Best,
Nablezen
If I hide its implementation from the signature, it can not be overwritten anymore, but I cannot call "b#dangerous_one" anymore - the code becomes inaccessible to calls also.
You can, you just need to make it private, you can't hide public methods:
class type safe = object
method safe_dangerous_one : in_channel -> int
end
class a : safe = object (self)
method private dangerous_one input = input_binary_int input
method safe_dangerous_one input =
max 255 (self#dangerous_one input)
end
class b parameters = object(self)
inherit a parameters as super
method! safe_dangerous_one input =
super#safe_dangerous_one input + 1
end
If you want unsafe method to be accessible, but not overridable, then just re-publish it at another name (kind of NVI):
class type safe = object
method unsafe_dangerous_one : in_channel -> int
method safe_dangerous_one : in_channel -> int
end
class a : safe = object (self)
method private dangerous_one input = input_binary_int input
method unsafe_dangerous_one input = self#dangerous_one input
method safe_dangerous_one input =
max 255 (self#dangerous_one input)
end
class b = object(self)
inherit a as super
method! safe_dangerous_one input =
super#safe_dangerous_one input + 1
end
And a piece of free advice. In other languages, classes and methods are used as a tool for structuring programs, because they have no better tools. In OCaml you have first class functions, records, structures, etc. So it is better to use a proper tool for at each situation. When you design a class, you should understand, that the method by its original definition (not spoiled by C++/Java/Python/etc) is something overridable. A method is an operation that has an implementation that varies across some genera. So, if you define something as a method, and then trying hard to prevent people from overriding it, then chances are high that you're doing something wrong. If you don't want it to be overridable, then just don't define it as a method at all. In your case you should put dangerous_one operation into a let-bound function. You can bound it in the context of the class, so that you will have an access to all parameters, or you can bind it on a toplevel, the choice is yours:
class a parameters =
let dangerous_one input = input_binary_int input in
object (self)
method safe_dangerous_one input =
max 255 (dangerous_one input)
end
class b = object(self)
inherit a as super
method! safe_dangerous_one input =
super#safe_dangerous_one input + 1
end
Also, a very good source of documentation about OCaml class system is Jason Hickey's Introduction to Objective Caml. It is slightly outdated, but is still very good.
I currently stuck on this with a corona app I'm creating.
I have a file structure like below:
App -> Classes -> Objects -> Ships
In the App folder is the main.lua, menu.lua, level.lua and Class.lua. In the Classes folder there is Object.lua. In Objects, ship.lua and finally in the Ships are my different ships i.e. player and enemy.
I followed this tutorial and my code is almost completely identical to his (bar player and enemys classes), but still am receiving this error in the Class.lua is
"bad argument #2 to 'setetatable'(nil or table expected)"
The code I receive the error on is
function Class(Super)
Super = Super or Base
local prototype = setmetatable({}, Super) -- receive error here
prototype.class = prototype
prototype.super = Super
prototype.__index = prototype
return prototype
end
Base = Class()
function Base:new(...)
local instance = setmetatable({}, self)
instance:initialize(...)
return instance
end
function Base:initialize() end
function Base:get()
local Instances = self.Instances
if (not Instances[1]) then local obj = self:new() end
return table.remove(Instances, 1)
end
function Base:dispose()
table.insert(self.Instances, self)
end
I've tried changing the classes and changing the "setmetatable({},Super)" to "setmetatable(Super, self), putting all the classes in one file, I've read the lua docs, requiring the Class.lua in the mai, menu and the level.lua etc. and nothing has worked.
Any help would be greatly appreciated.
Thanks
function Class(Super)
Super = Super or Base
local prototype = setmetatable({}, Super) -- receive error here
prototype.class = prototype
prototype.super = Super
prototype.__index = prototype
return prototype
end
Base = Class()
Follow the execution of the code above.
You declare a function Class and then call it (and assign its returned value to Base).
Step through the execution of Class from the Base = Class() line.
function Class(Super)
The function takes one argument named Super
Super = Super or Base
You are allowing the Super argument to be nil/unpassed by using a default value of Base.
This call Base = Class() is not passing a value so this line Super = Super or Base has Super as nil and so evaluates to Super = nil or Base however the global Base is also nil as it has not yet been assigned to so you get Super = nil.
local prototype = setmetatable({}, Super)
This line then attempts to use Super (assigned from the line before) only it is, as we just saw, nil hence your error.
The bit from the tutorial that you missed (or at least missed in your posted snippet) is the crucially important local Base line above the Class function definition.
I have a question regarding the traitsui tutorial by Gael Varoquaux.
In code snippet 7 he makes a CaptureThread class for producing a thread for taking images from a camera. He also make a Camera class.
class TextDisplay(HasTraits):
string = String()
view = View(Item('string', show_label=False, springy=True, style='custom'))
class CaptureThread(Thread):
def run(self):
#self.display is set outside the class definition by the caller
self.display.string = 'Camera started\n' + self.display.string
n_img = 0
while not self.wants_abort:
sleep(0.5)
n_img += 1
self.display.string = ' %d image captured\n' % n_img \
+ self.display.string
self.display.string = 'Camera stopped\n' + self.display.string
class Camera(HasTraits):
start_stop_capture = Button()
display = Instance(TextDisplay)
capture_thread = Instance(CaptureThread)
view = View( Item('start_stop_capture', show_label=False))
def _start_stop_capture_fired(self):
if self.capture_thread and self.capture_thread.isAlive():
self.capture_thread.wants_abort = True
else:
self.capture_thread = CaptureThread()
self.capture_thread.wants_abort = False
self.capture_thread.display = self.display
self.capture_thread.start()
I have two questions about this code:
1) Why in the Camera class definition does he make capture_thread a Trait, by calling Instance(CaptureThread)? CaptureThread is just a thread class, why should we make a trait instance out of it?
2) In the CaptureThread class he makes use of a field self.display.string and of self.wants_abort. These two fields are not passed in via a constructor method, rather they are assigned outside of the class definition by the Camera class. Is this the best practise? Since if the user of the CaptureThread forgot to set these two fields, then an error would occur. Are there some sensible guidelines to know when I can assign thing like that, or I should use a constructor to assign them?
I hope that these questions make sense, and that this is the right place to ask them!
Thanks, labjunky
capture_thread = Instance(CaptureThread) doesn't make an instance of CaptureThread. It is more of a declaration that gets consumed by the Camera class when the class gets created. It tells that Camera class that it will have an attribute named capture_thread that should be an instance of CaptureThread or None and will default to None. This default lets the "test if self.capture_thread is initialized, otherwise create it" logic in _start_stop_capture_fired() a little cleaner, at least to some people's tastes.
For threading.Thread subclasses, yes, it's one idiomatic way to do it, though not the only one. Thread already has a specific __init__ implementation, and you could override it to do something else, but it is understandable that the author would avoid doing so in this case.
This is not the idiomatic way to initialize HasTraits subclasses which is indeed to use keyword arguments.