Type hint an instance of a metaclass - python-3.x

I have a function which takes a class and returns an instance of that class. I'm trying to figure out how to typehint that, with a twist. Typically I would use the typing module and do something like
T = TypeVar("T", bound="BaseClass")
def foo(specific_type: Type[T]) -> T:
...
However, in my case I don't exactly want to take a class inheriting from a specific base class. What I really want to do is take a class with a specific metaclass and return an instance of that class, but I can't figure out a way to typehint that without adding some sort of dummy BaseClass. Ideally I would want the inverse of Type, something like:
M = TypeVar("M", bound="MyMetaclass")
def foo(specific_type: M) -> Instance[M]: # <-- Instance generic is made up
...
This lets me specify that foo should take an instance of MyMetaclass (which a class with metaclass=MyMetaclass is) and return an instance of that instance (an object whose class has metaclass=MyMetclass).
Is there anything in Python that lets me type hint something similar to the above?
To be clear, there is actually a base class with metaclass=MyMetaclass which I expect specific_type should probably always inherit from. However, I cannot import it into the current context without creating circular dependencies; MyMetaclass is already imported into the current context. I can work around this (I'm not asking how to organize my project), but I specifically want to know if I can type hint an instance of a class with a known metaclass like this.

Related

How to make a singleton that inherits a normal class, with predefined values, and comparable by `is` without the need of rounded brackets?

My attempt was to create the default instance from inside of a metaclass, but to no avail. At least the reported class is the singleton in the example bellow.
EDIT: Clarifying requirements here: a singleton comparable by using the is keyword, without having to instantiate/call it. Unfortunately, this well known question-answer here doesn't seem to address that.
class MyNormalClass:
def __init__(self, values):
self.values = values
class MySingleton(MyNormalClass, type):
def __new__(mcs, *args, **kwargs):
return MyNormalClass(["default"])
print(MySingleton)
# <class '__main__.MySingleton'>
print(MySingleton.values)
# AttributeError: type object 'MySingleton' has no attribute 'values'
Metaclasses for singletons are overkill. (Search my answers for that, and there should be about 10 occurrences of this phrase).
In your example code in the question, the code inside the class and the metaclass methods is not even being run, not once. There is no black-magic in Python - the program just runs, and there are a few special methods marked with __xx__ that will be called intrinsically by the language runtime. In this case, the metaclass __new__ will be called whenever you create a new class using it as the metaclass, which you code does not show. And also, it would create a new instance of your "singleton" class each time it were used.
In this case, if all you need is a single instance, just create that instance, and let that one be public, instead of its class. You can even us the instance itself to shadow the class from the module namespace, so no one can instantiate it again by accident. If you want values to be immutable, well, you can't
ensure that with pure Python code in any way, but you can make changing values do not work casually with = so that people will know they should not be changing it:
class MySingleton:
__slots__ = ("values",)
def __init__(self, values):
self.values = values
def lock(self, name, value):
raise TypeError("Singleton can't change value")
self.__class__.__setitem__ = lock
MySingleton = MySingleton(["values"])

Is it possible to overload the return of the type method?

Given the following example:
class Container:
def __init__(self, var):
self.var = var
class Test:
def __init__(self):
self.var = Container("123")
Is it possible to overload the type() method such as type(Test().var) would yield string rather than Container ?
EDIT : I am using the Container class in order to place restrictions on Test.var.
The idea is that Test is a class that contains many variables, some of witch have similar names. The Container class is there to ensure that the right types are used ( __eq__(), __str__(), __add__(), ... are overloaded in order to make the Container class as discreet as possible ) so that issues are diagnosed as fast as possible ( the code will by used by people with a very wide variety of expertise in python )
The other solution would have been to use the #property but as there are many variables, the code ends up being way bigger than it would otherwise and not as simple to maintain ( there is close to a hundred classes witch will have to implement the properties )
I would like to overload type(Test().var) in order to return type(Test().var.var) so that it would be as easy to use as possible
The short answer is "no."
From this official Python doc, it states:
Every object has an identity, a type and a value... The type() function returns an object’s type (which is an object itself). Like its identity, an object’s type is also unchangeable.

Mypy: How to create an alias type with all classes from a module

I have a module foothat defines a lot of classes, e.g.
class A():
...
class B():
...
class C():
...
...
I would like to create a "foo type" alias comprising all these classes, i.e.
my_foo_type = Union[A, B, C, ...]
Yet, there are so many classes that I don't want to type them but have programmatic solution. I access to all classes defined in the module via
for name, obj in inspect.getmembers(foo):
if inspect.isclass(obj):
print(obj)
How can I connect this with the type alias?
I don't think it's possible. I don't know what you want to do with your classes but depending on your use case, you could:
make your classes subclasses of a base class (it may also improve the design of your module);
use an external script that will generate the type variable for you (and run this script each time you add or remove a class in your module);
something else :)

Saving Object State with Pickle (objects containing objects)

I'm trying to figure out how to serialize an object with Pickle to a save file. My example is an object called World and this object has a list (named objects) of potentially hundreds of instantiated objects of different class types.
The problem is that Pickle won't let me serialize the items within the World.objects list because they aren't instantiated as attributes of World.
When I attempt to serialize with:
with open('gsave.pkl', 'wb') as output:
pickle.dump(world.objects, output, pickle.DEFAULT_PROTOCOL)
I get the following error:
_pickle.PicklingError: Can't pickle <class 'world.LargeHealthPotion'>:
attribute lookup LargeHealthPotion on world failed
So, my question is: what is an alternative way of storing the world.objects list items so that they are attributes of world rather than list items that don't get saved?
UPDATE
I think my issue isn't where the objects are stored; but rather that the class LargeHealthPotion (and many others) are dynamically created within the World class by operations such as this:
def __constructor__(self, n, cl, d, c, h, l):
# initialize super of class type
super(self.__class__, self).__init__(name=n, classtype=cl, description=d, cost=c,
hp=h, level=l)
# create the object class dynamically, utilizing __constructor__ for __init__ method
item = type(item_name,
(eval("{}.{}".format(name,row[1].value)),),
{'__init__':__constructor__})
# add new object to the global _objects object to be used throughout the world
self._objects[item_name] = item(obj_name, obj_classtype, obj_description, obj_cost,
obj_hp, obj_level)
When this finishes, I will have a new object like <world.LargeHealthPotion object at 0x103690ac8>. I do this dynamically because I don't want to explicitly have to create hundreds of different types of classes for each different type of object in my world. Instead, I create the class dynamically while iterating over the item name (with it's stats) that I want to create.
This introduces a problem though, because when pickling, it can't find the static reference to the class in order to deconstruct, or reconstruct the object...so it fails.
What else can I do? (Besides creating literal class references for each, and every, type of object I'm going to instantiate into my world.)
Pickle does not pickle classes, it instead relies on references to classes which doesn't work if the class was dynamically generated. (this answer has appropriate exert and bolding from documentation)
So pickle assumes that if your object is from the class called world.LargeHealthPotion then it check that that name actually resolves to the class that it will be able to use when unpickling, if it doesn't then you won't be able to reinitialize the object since it doesn't know how to reference the class. There are a few ways of getting around this:
Define __reduce__ to reconstruct object
I'm not sure how to demo this method to you, I'd need much more information about your setup to suggest how to implement this but I can describe it:
First you'd make a function or classmethod that could recreate one object based on the arguments (probably take class name, instance variables etc.) Then define __reduce__ on the object base class that would return that function along with the arguments needed to pass to it when unpickling.
Put the dynamic classes in the global scope
This is the quick and dirty solution. Assuming the class names do not conflict with other things defined in the world module you could theoretically insert the classes into the global scope by doing globals()[item_name] = item_type, but I do not recommend this as long term solution since it is very bad practice.
Don't use dynamic classes
This is definitely the way to go in my opinion, instead of using the type constructor, just define your own class named something like ObjectType that:
Is not a subclass of type so the instances would be pickle-able.
When an instance is it called constructs a new game-object that has a reference to the object type.
So assuming you have a class called GameObject that takes cls=<ObjectType object> you could setup the ObjectType class something like this:
class ObjectType:
def __init__(self, name, description):
self.item_name = name
self.base_item_description = description
#other qualities common to all objects of this type
def __call__(self, cost, level, hp):
#other qualities that are specific to each item
return GameObject(cls=self, cost=cost, level=level, hp=hp)
Here I am using the __call__ magic method so it uses the same notation as classes cls(params) to create instances, the cls=self would indicate to the (abstracted) GameObject constructor that the class (type) of GameObject is based on the ObjectType instance self. It doesn't have to be a keyword argument, but I'm not sure how else to make a coherent example code without knowing more about your program.

Haskell Inferred instance declaration on inherited classes

I've seen cases of chains of Haskell classes that all "extend" each other (see for example, the widget/container/etc classes in gtk2hs)
class Class1 a where....
class (Class1 a)=>Class2 a where....
class (Class2 a)=>Class3 a where....
....and so on....
where all the class functions have default values that depend on one Class1 function. This works great, but makes for a really ugly "instantiation" of ClassN
Instance Class1 Object where
func x = ....
Instance Class2 Object
Instance Class3 Object
Instance Class4 Object
Instance Class5 Object
....and so on....
(I've seen code just like this in popular hackage libraries, so I'm pretty sure that at the time of the writing of the code this was a proper way to do this).
My question- Are there any newer GHC extensions that would clean this up. I've looked a bit and haven't found any. Ideally, all you really need is to decleare Object as an instance of ClassN, and give the Class1 function, the rest would be inferred.
[preemptive snarky comment :)- This indicates an "object oriented" way of thinking, you should really learn how to program functionally.
My response- I agree it is very object oriented, but code like this exists in the ecosystem today, and might very well be needed, GUI libs like gtk2hs, for example. From a practical viewpoint I need to write code like this sometimes, and I just want to simplify it.]
It is a discussed proposal to add Synonym Instances.
For example it would be possible to write next code:
type Stringy a = (Read a, Show a)
instance Stringy a where
read = ...
show = ...
in this case it would be possible to declare
type ClassAll a = (Class1 a, Class2 a, Class3 a, Class4 a)
instance ClassAll a where
foo = ...
But for now, type constraint could be used in function's signatures only, not in instances.
UPDATED
As Vittor mentions, you can find proposal here: Multi-headed instance declarations
The original proposal is a part of class aliases proposal

Resources