I have a Class Factory that generates classes with dynamic name assignment
I like to be able to access them from other modules which import a package A
currently I am loading the classes into a dictionary and updating the vars() of the init.py which to me seems not like a good idea, is there a better way of doing it?
class Model_Factory:
def __init__(self,list_of_names:list):
self._models={}
for name in list_of_names:
self.models[name]=Model_Factory.create_model(name)
#property
def models(self):
return self._models
#classmethod
def create_model(cls,cls_name):
def __init__(self, **kwargs):
super(type(self),self).__init__( **kwargs)
pass
return type(snake_case(cls_name), (parent),
{'__init__': __init__,
'aomething' : 'something',
'attribute_name':'value'})
then inside the package A's init.py
import whatever
some line of code
dic=Model_Factory().models
vars().update(dic)
Then when I want to access those classes all I have to do is to
from A import Dynamically_Created_Class_Name
This works perfectly fine and the other modules who need to import those classes know the dynamic names themselves alright, however this just does not seem to me the correct way of doing it, is there a method or built in method that would add class definition or a dictionary into the current module namespace?
I am trying to add a method to an existing Python scipy.stats class but it is generating a _construct_docstrings error.
import scipy.stats as stats
class myPoisson(stats.poisson) :
def myMethod(var, **kwargs) :
return var
I have tried adding an __init__ method with a call to super().__init__(self) but this has not changed the error.
What am I missing for extending existing Python classes?
hopefully the following example helps you out.
def myMethod(var, **kwargs):
return var
stats.poisson.myMethod = myMethod
stats.poisson.myMethod(2)
Refer to Adding a Method to an Existing Object Instance for further details on the topic.
Scipy.stats distributions are instances, not classes (for historic reasons). Thus, you need to inherit from e.g. poisson_gen, not poisson. Better still, inherit from rv_continuous or rv_discrete directly. See the docstring of rv_continuous for some info on subclassing distributions
I am new to python. I am using the anaconda prompt to run my code. I am trying to import a class from another module but I keep getting errors such as cannot find reference to the class.
P.S please don't negative mark this, or else I will lose the privilege of asking questions
I have already provided an __init__ function.
The module itself runs just fine.
I have used from parser import Parser
I have used from parser import * statement as well
My Parser class
class Parser(object):
def __init__(self, tokens):
self.tokens = tokens
self.token_index = 0
My main class
from parser import Parser
I expected it to normally import the class, but it is unable to.
I keep getting the cannot import name 'Parser' from 'parser' (unknown location) when I use from parser import Parser
parser is also the name of a Python module in the standard library.
It's likely there is a name conflict, and that Python is importing the module from the standard library.
I changed the module name to mparser and it works!
This question already has answers here:
How do I type hint a method with the type of the enclosing class?
(7 answers)
Closed 3 years ago.
class Node:
def append_child(self, node: Node):
if node != None:
self.first_child = node
self.child_nodes += [node]
How do I do node: Node? Because when I run it, it says name 'Node' is not defined.
Should I just remove the : Node and instance check it inside the function?
But then how could I access node's properties (which I would expect to be instance of Node class)?
I don't know how implement type casting in Python, BTW.
"self" references in type checking are typically done using strings:
class Node:
def append_child(self, node: 'Node'):
if node != None:
self.first_child = node
self.child_nodes += [node]
This is described in the "Forward references" section of PEP-0484.
Please note that this doesn't do any type-checking or casting. This is a type hint which python (normally) disregards completely1. However, third party tools (e.g. mypy), use type hints to do static analysis on your code and can generate errors before runtime.
Also, starting with python3.7, you can implicitly convert all of your type-hints to strings within a module by using the from __future__ import annotations (and in python4.0, this will be the default).
1The hints are introspectable -- So you could use them to build some kind of runtime checker using decorators or the like if you really wanted to, but python doesn't do this by default.
Python 3.7 and Python 4.03.10 onwards
PEP 563 introduced postponed evaluations, stored in __annotations__ as strings. A user can enable this through the __future__ directive:
from __future__ import annotations
This makes it possible to write:
class C:
a: C
def foo(self, b: C):
...
Starting in Python 3.10 (release planned 2021-10-04), this behaviour will be default.
Edit 2020-11-15: Originally it was announced to be mandatory starting in Python 4.0, but now it appears this will be default already in Python 3.10, which is expected 2021-10-04. This surprises me as it appears to be a violation of the promise in __future__ that this backward compatibility would not be broken until Python 4.0. Maybe the developers consider than 3.10 is 4.0, or maybe they have changed their mind. See also Why did __future__ MandatoryRelease for annotations change between 3.7 and 3.8?.
In Python > 3.7 you can use dataclass. You can also annotate dataclass.
In this particular example Node references itself and if you run it you will get
NameError: name 'Node' is not defined
To overcome this error you have to include:
from __future__ import annotations
It must be the first line in a module. In Python 4.0 and above you don't have to include annotations
from __future__ import annotations
from dataclasses import dataclass
#dataclass
class Node:
value: int
left: Node
right: Node
#property
def is_leaf(self) -> bool:
"""Check if node is a leaf"""
return not self.left and not self.right
Example:
node5 = Node(5, None, None)
node25 = Node(25, None, None)
node40 = Node(40, None, None)
node10 = Node(10, None, None)
# balanced tree
node30 = Node(30, node25, node40)
root = Node(20, node10, node30)
# unbalanced tree
node30 = Node(30, node5, node40)
root = Node(20, node10, node30)
If you just want an answer to the question, go read mgilson's answer.
mgilson's answer provides a good explanation of how you should work around this limitation of Python. But I think it's also important to have a good understanding of why this doesn't work, so I'm going to provide that explanation.
Python is a little different from other languages. In Python, there's really no such thing as a "declaration." As far as Python is concerned, code is just code. When you import a module, Python creates a new namespace (a place where global variables can live), and then executes each line of the module from top to bottom. def foo(args): code is just a compound statement that bundles a bunch of source code together into a function and binds that function to the name foo. Similarly, class Bar(bases): code creates a class, executes all of the code immediately (inside a separate namespace which holds any class-level variables that might be created by the code, particularly including methods created with def), and then binds that class to the name Bar. It has to execute the code immediately, because all of the methods need to be created immediately. Because the code gets executed before the name has been bound, you can't refer to the class at the top level of the code. It's perfectly fine to refer to the class inside of a method, however, because that code doesn't run until the method gets called.
(You might be wondering why we can't just bind the name first and then execute the code. It turns out that, because of the way Python implements classes, you have to know which methods exist up front, before you can even create the class object. It would be possible to create an empty class and then bind all of the methods to it one at a time with attribute assignment (and indeed, you can manually do this, by writing class Bar: pass and then doing def method1():...; Bar.method1 = method1 and so on), but this would result in a more complicated implementation, and be a little harder to conceptualize, so Python does not do this.)
To summarize in code:
class C:
C # NameError: C doesn't exist yet.
def method(self):
return C # This is fine. By the time the method gets called, C will exist.
C # This is fine; the class has been created by the time we hit this line.
Following a number of tutorials on the internet, I've created this example:
from abc import ABCMeta, abstractmethod
class Base(object):
__metaclass__ = ABCMeta
#abstractmethod
def Foo(self):
print('Foo base')
#abstractmethod
def Bar(self):
print('Bar base')
class Sub(Base):
def Foo(self):
print('Foo sub')
# no sub implementation of Bar
s = Sub() # why does this work?
s.Foo() # prints "Foo sub"
s.Bar() # prints "Bar base" (which makes sense if it's
# **not** inheriting from an abstract class)
It's my understanding that you need to override all abstract methods when you inherit from a class that contains abstract methods. Why does this work?
tl;dr: The problem is that you're using Python 2 syntax for abstract classes but executing in a Python 3 environment. Change your Base class declaration to class Base(metaclass=ABCMeta): (the Python 3 way of declaring an abstract class). You will now get a Type Error both on instantiating the Base class and instantiating the Sub class without overriding all abstract methods.
Slightly longer explanation - apparently this changed between Python 2 and 3, however the Python 2 version is still valid code in Python 3. It is not a breaking change in the sense that the code still executes (it just runs a little.... differenty). You are merely inheriting from the base object class. You will receive no warnings or errors and apparently the Python interpreter will just discard the #abstractmethod annotations.
Also, this change is not noted in any of the "Python 2 vs Python 3"/"Differences between Python 2 and 3" lists/articles that I have been able to find.