passing a dict of available classes to a function - python

I want to pass a dict with available classes to a function, so that I can construct them using their name, without importing them.
My idea was to do this:
from construct_classes import construct_classes
class A:
def __init__(self):
print('A')
class B:
def __init__(self):
print('B')
if __name__ == '__main__':
construct_classes({'A': A, 'B': B})
And in construct_classes.py:
def construct_classes(my_classes):
a = my_classes['A'].__init__(my_classes['A'])
b = my_classes['B'].__init__(my_classes['B'])
This seems to work, but it looks hacky to me.
Are there any arguments against using this and if so is there another way to accomplish this behaviour?

Based on what I feel your question is about, this is what occurs to me:
If it looks hacky to you, maybe it is. But downvotes might have happened also because of the __init__ call (follow Klaus comment fix).
I don't remember the use of expressions like "plug-ins map" or "plug-ins dict", although we know that creatures like that can exist. Now if you say the "list of installed plug-ins", that is another thing, if you see what I mean...
If you just want to add functionality without touching some class code, use a Decorator pattern (a Python decorator, that is).
If you are building a list of plug-ins for a user or client code to choose from and run, you need to abstract a common API for plugin management and use. So that you can choose from the list obtained with .list(), or iterate the list, and for example .run() any one of them.
Also check namespace packages. Don't think it applies directly here, but plug-ins seem mostly a name management issue, maybe you can structure your plug-ins ideas differently, and then make good use of that. They are just subfolders with common names and no __init__.py, bringing defined names/modules inside them into a common top name.

Related

Pylint w0212-Warning while doing unittests

we often use this double underscore prefix for internal methods of our classes. This usually raises a W0212 during unit-testing, because we call the proctected methods directly e.g. TestClass().__my_private_method().
I know that in Python there are no private methods. Nevertheless I find this practice of using the underscore prefix good for structural reasons, e.g., it makes it quite obvious to other developers how to use a class.
Now I found this fix for the W0212-Warning from the phoenix-github-page:
class Foo:
def __bar(self):
pass
def baz(self):
return self.__bar()
foo = Foo()
foo.baz()
Based on this you could create a method for unittest without disabling W0212 like this:
class SomeClass:
""" some docstring
"""
def __init__(self) -> None:
self.myattr = 1
def __my_protected_method(self):
return self.myattr + 1
def __another_protected_method(self):
return self.myattr + 2
def method_for_unittests(self, method_name):
if method_name == "my_protected_method":
return self.__my_protected_method()
if method_name == "another_protected_method":
return self.__another_protected_method()
return None
This seems like a nicer solution than using a seperate .pylintrc (suggested here). This begs the following questions:
Does my solution make sense or should we just stick with #pylint: disable=protected-access?
Or do you maybe have a better solution using a special decorator? I saw something here, which made me curious. I have little experience writing decorators, therefore the comparatively naive question.
With pylint it's always possible to disable the message, or to make it disappear by using a hack. But it's better to simply disable messages than to hack something that will make pylint stop complaining (but won't make the code better). The best thing to do is to understand the underlying issue to fix it.
If you're creating a function that will be used only for tests (a test only API) you're doing a hack to make pylint think you're using a public API. What you should do instead is to test private/protected methods through the public interface of your function (through the real API used everywhere) as pointed out by #jonrscharpe in comment.
If you can't do that, then it means that a private class is hiding inside your code waiting to be created.
Advertisement: We're trying to include and improve the documentation work of valid-phoenix that you linked in the question into pylint. You can help the pylint team make better suggestions of fixes, see https://github.com/PyCQA/pylint/issues/5953

Best practice for using argument's class method

I am trying to figure out the solution for the following problem:
#ExampleA.py
class a:
def my_great_method_A(self):
pass
#ExampleB.py
def functionX(inst_a): #Argument 'inst_a' will be always ExampleA.py's class a.
inst_a.my_great_method_A() #<---
I use Liclipse as a python editor. When I am typing the last line, "a.my_gr...", I want to have the editor's auto filling feature kicks in to suggest to use "my_great_method_A()". However, it actually does not suggest anything.
I understand why, because the editor doesn't have any clue if 'inst_a' is class 'a'. To deal with this issue, I could do the following to make the autofiller work:
#ExampleA.py
class a:
def my_great_method_A(self):
pass
#ExampleB.py
import ExampleA
def functionX(inst_a): #Argument 'inst_a' will be always ExampleA.py's class a.
ExampleA.a.my_great_method_A(inst_a) #<--- then autofilling works
However, for the code's readability, I would rather use the . format and I believe everyone the same way. But I do not know how everyone deals with this. Many times I have to go into the imported file and copy & paste the method name, which is tedious. Obviously I am missing something that everyone is aware of. By the way this is my first time to post on stackoverflow. I hope this is a valid thing to pose here.
LiClipse/PyDev can recognize type hints in docstrings (as explained in http://www.pydev.org/manual_adv_type_hints.html) or using the new PEP 484 type hints (https://www.python.org/dev/peps/pep-0484/)... So, if you use one of those, it should work.
Note: I personally like docstrings better, but it's probably a matter of taste and both should be recognizable by LiClipse/PyDev.
I don't know of a way to make this editor guess the type you're expecting. But since Python is untyped it will always only be guessing.
However notice your workaround of using the class explicit method is not a good practice. It will not allow you to pass extensions of ExampleA in the future in case your code will evolve some day.
So it's more than just readability

Is it possible to iterate through class trait in order of declaration using Enthought traits?

We use Enthought Traits to declare some python classes that are use to create database schema and the UI to add records. So we have code to iterate through the class traits and do some actions. One common issue is that the order of declaration is usually significant or very helpful to understand the schema and the UI but this order is lost in class_traits (because it's a python dict).
Is there a way to automatically keep the declaration order in class_traits? Maybe by overriding some methods in HasTraits?
We use python 2 right now (we are in the process of moving to python 3 but it will take time).
EDIT: Before posting, I found this question which suggested a trick similar to what Robert Kern suggested but without snippet. I was expecting that Traits would provide some help there. Robert's answer is useful anyway.
Not easily in Python 2. Python 2 simply doesn't preserve that information.
If you are running with .py sources available, then it is possible to reparse the class definition from that file and reconstruct the order that way. If you aren't, then I suppose you could try to parse the bytecode, but you're on your own there.
import ast
import inspect
def ordered_class_traits(cls):
source = inspect.getsource(cls)
mod_ast = ast.parse(source)
class_trait_names = cls.class_trait_names()
class_ast = mod_ast.body[0]
for node in class_ast.body:
# This probably doesn't capture every possible trait declaration
# out there, but it does the job for most of them.
if isinstance(node, ast.Assign):
target = node.targets[0]
if isinstance(target, ast.Name):
if target.id in class_trait_names:
yield target.id

Block of code as a separate module in Python

Assume I have a list my_list, a variable var, and a block of code that modifies the list using the variable
my_list = ['foo']
var = 'bar'
my_list.append(var)
In the actual task I have a lot of variables like var and a lot of commands like append which modify the list. I want to relegate those commands to another module. In the case at hand I would like to have two modules: modify.py which contains the modifying commands
my_list.append(var)
and main.py which defines the list and the variable and somehow uses the code from the modify.py
my_list = ['foo']
var = 'bar'
import_and_run modify
The goal is to make the main file more readable. Modifying commands in my case can be nicely grouped and would really be good as separate modules. However, I am only aware of the practice when one imports a function from a module, not a block of code. I do not want to make the whole modify.py module a function because
1) I don't want to pass all the arguments needed. Rather, I want modify.py to directly have access to main.py name space.
2) code in modify.py is not really a function. It runs only once. Also, I do not the whole module to be a body of a function, that just does not feel right.
How do I achieve that? Or the whole attitude is wrong?
If your goal is to make the code more readable, I'd suggest taking these steps.
Decompose your problem into a series of separate actions.
Give these actions names.
Define a function main in your module that calls functions named
after the actions:
def main():
do_setp1()
do_step2()
# etc
return
Separate you existing code into the functions that you're calling in
main()
As #flaschbier suggested, collect related, common parameters into dictionaries to make passing the around easier to manage.
Consider repeating these steps on your new functions, decomposing
them into sub-functions.
Done well, you should be left with a file that's easier to look at, because the function definitions and their indented bodies break up the flow of text.
The code should be easier to reason about because you only need to understand one function at a time, instead of the entire script.
Generally you want to keep all the code related to a particular task in a single module, unless there's more than say 500 lines. But before moving code into separate modules see if you can reduce the total lines of code by factoring repeated code into functions, or making your code more succinct: for example see if for loops can be replaced by list comprehensions.
Consider using code linting tools to help you make the code well-formatted.
So in summary: don't go against the grain of Python by hiding code in another
module and going down the import_and_run route. Instead use good code organisation and Python's inherent good visual structure to make your code readable.
By the way, seems like you still haven't grasped the concept of Python modules.
Well, modules in Python are the .py files. Each function, class or even variables in a .py file can be imported into another program.
Consider a (perhaps crazy) example like this crazy.py:
class crazyCl:
# crazy stuffs
pass
def crazyFn():
# some another crazy stuffs
crazyVar = 'Please do not try this at home'
Now, to import any of these, into another program, say goCrazy.py in the same folder, simply do this
import crazy # see ma, no .py
if __name__ == '__main__':
print crazy.crazyVar # Please do not try this at home
This is a simple introduction to Python modules. There are many other features like packages that have to be tried out.
As a simple introduction, this should do. Hope you got some idea.

Explanation of importing Python classes

So I know this could be considered quite a broad quesiton, for which I am sorry, but I'm having problems understanding the whole importing and __init__ and self. things and all that... I've tried reading through the Python documentation and a few other tutorials, but this is my first language, and I'm a little (a lot) confused.
So far through my first semester at university I have learnt the very basics of Python, functions, numeric types, sequence types, basic logic stuff. But it's moving slower than I would like, so I took it upon myself to try learn a bit more and create a basic text based, strategy, resource management sorta game inspired by Ogame.
First problem I ran into was how to define each building, for example each mine, which produces resources. I did some research and found classes were useful, so I have something like this for each building:
class metal_mine:
level = 1
base_production = 15
cost_metal = 40
cost_crystal = 10
power_use = 10
def calc_production():
metal_mine.production = A formula goes here
def calc_cost_metal():
etc, same for crystal
def calc_power_use():
metal_mine.power_use = blah blah
def upgrade():
various things
solar_plant.calc_available_power()
It's kinda long, I left a lot out. Anyway, so the kinda important bit is that last bit, you see when I upgrade the mine, to determine if it has enough power to run, I calculate the power output of the solar plant which is in its own class (solar_plant.calc_output()), which contains many similar things to the metal mine class. If I throw everything in the same module, this all works fantastically, however with many buildings and research levels and the likes, it gets very long and I get lost in it.
So I tried to split it into different modules, so one for mines, one for storage buildings, one for research levels, etc. This makes everything very tidy, however I still need a way to call the functions in classes which are now part of a different module. My initial solution was to put, for example, from power import *, which for the most part, made the solar_plant class available in the metal_mine class. I say for the most part, because depending on the order in which I try to do things, sometimes it seems this doesn't work. The solar_plant class itself calls on variables from the metal_mine class, now I know this is getting very spagetti-ish..but I don't know of any better conventions to follow yet.
Anyway, sometimes when I call the solar_plant class, and it in turn tries to call the metal_mine class, it says that metal_mine is not defined, which leads me to think somehow the modules or classes need to be initialized? There seems to be a bit of looping between things in the code. And depending on the order in which I try and 'play the game', sometimes I am unintentionally doing this, sometimes I'm not. I haven't yet been taught the conventions and details of importing and reloading and all that..so I have no idea if I am taking the right approach or anything.
Provided everything I just said made sense, could I get some input on how I would properly go about making the contents of these various modules freely available and modifiable to others? Am I perhaps trying to split things into different modules which you wouldn't normally do, and I should just deal with the large module? Or am I importing things wrong? Or...?
And on a side note, in most tutorials and places I look for help on this, I see classes or functions full of self.something and the init function..can I get a explanation of this? Or a link to a simple first-time-programmer's tutorial?
==================UPDATE=================
Ok so too broad, like I thought it might be. Based on the help I got, I think I can narrow it down.
I sorted out what I think need to be the class variables, those which don't change - name, base_cost_metal, and base_cost_crystal, all the rest would depend on the players currently selected building of that type (supposing they could have multiple settlements).
To take a snippet of what I have now:
class metal_mine:
name = 'Metal Mine'
base_cost_metal = 60
base_cost_crystal = 15
def __init__(self):
self.level = 0
self.production = 30
self.cost_metal = 60
self.cost_crystal = 15
self.power_use = 0
self.efficiency = 1
def calc_production(self):
self.production = int(30 + (self.efficiency * int(30 * self.level * 1.1 * self.level)))
def calc_cost_metal(self):
self.cost_metal = int(metal_mine.base_cost_metal * 1.5 ** self.level)
So to my understanding, this is now a more correctly defined class? I define the instance variables with their starting values, which are then changed as the user plays.
In my main function where I begin the game, I would create an instance of each mine, say, player_metal_mine = metal_mine(), and then I call all the functions and variables with the likes of
>>> player_metal_mine.level
0
>>> player_metal_mine.upgrade()
>>> player_metal_mine.level
1
So if this is correctly defined, do I now just import each of my modules with these new templates for each building? and once they are imported, and an instance created, are all the new instances and their variables contained within the scope(right terminology?) of the main module, meaning no need for new importing or reloading?
Provided the answer to that is yes, I do just need to import, what method should I use? I understand there is just import mines for example, but that means I would have to use mines.player_metal_mine.upgrade() to use it, which is a tiny bit more typing thanusing the likes of from mines import *, or more particularly, from mines import metal_mine, though that last options means I need to individually import every building from every module. So like I said, provided, yes, I am just importing it, what method is best?
==================UPDATE 2================= (You can probably skip the wall of text and just read this)
So I went through everything, corrected all my classes, everything seems to be importing correctly using from module import *, but I am having issues with the scope of my variables representing the resource levels.
If everything was in 1 module, right at the top I would declare each variable and give it the beginning value, e.g. metal = 1000. Then, in any method of my classes which alters this, such as upgrading a building, costing resources, or in any function which alters this, like the one which periodically adds all the production to the current resource levels, I put global metal, for example, at the top. Then, within the function, I can call and alter the value of metal no problem.
However now that I am importing these classes and functions from various modules all into 1 module, functions cant find these variables. What I thought would happen was that in the process of importing I would basically be saying, take everything in this module, and pretend its now in this one, and work with it. But apparently that's not what is happening.
In my main module, I import all my modules using from mines import * for example and define the value of say, metal, to be 1000. Now I create an instance of a metal mine, `metal_mine_one = metal_mine(), and I can call its methods and variables, e.g.
>>> metal_mine_one.production
30
But when I try call a method like metal_mine_one.upgrade(), which contains global metal, and then metal -= self.cost_metal, it give me an error saying metal is not defined. Like I said, if this is all in 1 module, this problem doesn't happen, but if I try to import things, it does.
So how can I import these modules in a way which doesn't cause this problem, and makes variables in the global scope of my main module available to all functions and methods within all imported modules?
First a little background on object oriented programming. i.e. classes. You should think of a class like a blueprint, it shows how to make something. When you make a class it describes how to make an object to the program. a simple class in python might look like this.
class foo:
def __init__(self, bars_starting_value):
self.bar = bars_starting_value
def print_bar(self):
print(self.bar)
This tells python how to make a foo object. The init function is called a constructor. It is called when you make a new foo. The self is a way of referencing the foo that is running the function. In this case every foo has its own bar which can be accessed from within a foo by using self.bar. Note that you have to put a self as the first argument of the function definition this makes it so those functions belong to a single foo and not all of them.
One might use this class like this:
my_foo = foo(15)
my_other_foo = foo(100)
foo.print_bar()
foo.bar = 20
print(foo.bar)
my_other_foo.print_bar()
This would output
15
20
100
As far as imports go. They take all things that are defined in one file and move them to be defined in another. This is useful if you put the a class definition in a file you can import it into your main program file and make objects from there.
As far as making variables available to others, you could pass the power that has been generated from all the generators to the mine's function to determine if it has enough power.
Hope this helps.
A lot of things to cover here.. init is a builtin method that is automatically called when an instance of a class is created. In the code you provided you've created a class, now you need to create an instance of that class. A simpler example:
class Test:
def __init__(self):
print "this is called when you create an instance of this class"
def a_method(self):
return True
class_instance = Test()
>>> "this is called when you create an instance of this class"
class_instance.a_method()
>>> True
The first argument in a class method is *always itself. By convention we just call that argument 'self'. Your methods did not accept any arguments, make sure they accept self (or have the decorator #staticmethod above them). Also, make sure you refer to attributes (in you case methods) by self.a_method or class_instance.a_method

Categories

Resources