What I want to do is something like this:
Script1:
import script2
def calc():
instance = script2.User()
instance.user = "me"
script2.vital_function()
Script2:
class User():
user = ""
def vital_function():
# Complex function that uses the User class
So I want to be able to run script2.py inside script1.py with variables set in script1.py. I don't think I have explained myself very clearly. Ask me if something is unclear.
If user must be an object attribute, you can override the init method for the class (its constructor) and pass it the value you need it to store.
class User():
def __init__(self, user):
self.user = user
def vital_function():
...
If, instead, it must be some static value that you share among all the instances of User, either you monkey-patch it as you did, or you define a setter method
class User():
user = ""
#staticmethod
def set_user(user):
User.user = user
but I guess the first way makes more sense.
Are we missing something from your requirements?
Related
class Phone:
def install():
...
class InstagramApp(Phone):
...
def install_app(phone: "Phone", app_name):
phone.install(app_name)
app = InstagramApp()
install_app(app, 'instagram') # <--- is that OK ?
install_app gets a Phone object.
will it work with with InstagramApp object ?
The inheritance works correctly. install method is inherited from Phone class. But your code doesn't work. When you run it, it will say:
TypeError: Phone.install() takes 0 positional arguments but 2 were given
What are these two arguments that have been passed?
Second one is obviously the 'instagram' string. You passed that but no parameter expects it.
The first one is, Because you invoke that install() method from an instance, Python turns it into a "Method" and automatically fills the first parameter of it to a reference to the instance(this is how descriptors work). But again you don't have any parameter to receive it.
To make that work:
class Phone:
def install(self, name):
print(self)
print(name)
class InstagramApp(Phone):
...
def install_app(phone: "Phone", app_name):
phone.install(app_name)
app = InstagramApp()
install_app(app, "instagram")
Yes, methods are also inherited from classes. However, you will need to add a parameter to the install method so it can take the app name:
class Phone:
def install(self, app_name): # Allow the method to take an input app name
...
class InstagramApp(Phone):
...
def install_app(phone: "Phone", app_name):
phone.install(app_name)
app = InstagramApp()
install_app(app, 'instagram') # Yes, this will also work with the InstagramApp class
Yes - so long as the InstagramApp doesn't delete any of the methods that 'install_app', and the methods return the same types as the Phone class does then it will work.
I am curious as to why to pass the instance and pass the name as text - you could accomplish the sanme by simply ascessing the __name__ variable of the class - so for instance :
`app.__class_.__name__ will equal 'Instagram'
As others have pointed out you need to fix the various function calls.
install_app gets a Phone object. will it work with InstagramApp object?
the inheritance class will have the function
class Phone:
def install(app_name:str):# change type to str
pass
class InstagramApp(Phone):
pass
def install_app(phone: Phone, app_name):# change the type to Phone Class
phone.install(app_name)
app = InstagramApp()
install_app(app, 'instagram') #
I'm writing a wrapper for the GMAIL API. In this wrapper, I am trying to include subattributes in the "main class" so it more closely follows the below:
Previously, I was use methods such as:
class Foo:
def __init__(self, ...):
# add some attributes
def get_method(self, ...):
return some_stuff
This allows me to do foo.get_method(...). To follow the GMAIL API, I try to do:
class Foo:
def __init__(self, ...):
# add some attributes
#property
def method(self):
class _Method:
#staticmethod
def get(self, ...):
return some_stuff
return _Method()
Which allows me to do foo.method.get(...). The above has some problems, it redefines the class every time, and I have to add #staticmethod above every method as part of it. I do realise that I could create the class at the outer class level, and set a hidden variable for each which then .method returns or creates, but this seems like too much workaround.
tldr: Is it possible to make the instance passed to the inner class as self be the instance of the outer class (I do not wish to have to pass the attributes of the outer class to each inner class).
Instead of sharing the self parameter between classes, you are probably better off just passing the things you need to the constructor of the class you instantiate.
class Messages:
def __init__(self, name):
self.name = name
def method(self, other_arg):
return self.name + other_arg
class Test:
name = "hi"
def __init__(self):
self.messages = Messages(name=self.name)
If you need to pass a lot of information to the constructor and it starts becoming unwieldy, you can do something like split the shared code into a third class, and then pass that between the Test and Messages classes as a single object.
In Python there are all sorts of clever things that you can do with metaclasses and magic methods, but in 99% of cases just refactoring things into different classes and functions will get you more readable and maintainable code.
Users should have an instance of messages, which allows method get. The scetch for code is:
class Messages:
...
def get()
...
class Users:
...
messages = Messages(...)
allows
users = Users()
users.messages.get()
The bad thing in this API is plural names, which is a bad sign for class. If done from scratch you would rather have classes User and Message, which make more sense.
If you have a closer look at GET/POST calls in the API you link provided, you would notice the urls are like UserId/settings, another hint to implement User class, not Users.
self in the methods reference the self of the outer class
maybe this is what you want factory-method
Although the example code I'll provide bellow might be similar to the already provided answers, and the link above to another answer might satify you wish, because it is slight different formed I'll still provide my vision on what you asked. The code is self explanatory.
class User:
def __init__(self, pk, name):
self.pk = pk
self.name = name
self._messages = None
def messages(self):
if self.messages is None:
self._messages = Messages(self.pk)
return self._messages
class Messages:
def __init__(self, usr):
self.usr = usr
def get(self):
return self._grab_data()
def _grab_data(self):
# grab the data from DB
if self.usr == 1:
print('All messages of usr 1')
elif self.usr == 2:
print('All messages of usr 2')
elif self.usr == 3:
print('All messages of usr 3')
one = User(1, 'One')
two = User(2, 'Two')
three = User(3, 'Three')
one.messages().get()
two.messages().get()
three.messages().get()
The messages method approach practical would be the same for labels, history etc.
Edit: I'll give one more try to myself trying to understand what you want to achieve, even though you said that
I have tried numerous things with defining the classes outside of the container class [...]
. I don't know if you tried inheritance, since your inner class me, despite it quite don't represent nothing here, but still looks like you want to make use of its functionality somehow. You said as well
self in the methods reference the self of the outer class
This sounds to me like you want inheritance at the end.
Then the way to go would be (a proximity idea by using inheritance):
class me(object):
def __init__(self):
self.__other_arg = None # private and hidden variable
# setter and getter methods
def set_other_arg(self, new_other_arg):
self.__other_arg = new_other_arg
def get_other_arg(self):
return self.__other_arg
class Test(me):
name = 'Class Test'
#property
def message(self):
other_arg = self.get_other_arg()
if other_arg is not None:
return '{} {}'.format(self.name, other_arg)
else:
return self.name
t = Test()
t.set_other_arg('said Hello')
print(t.message)
# output >>> Class Test said Hello
I think this could be a preferable way to go rather than your inner class approach, my opinion, you'll decide. Just one side note, look up for getter and setter in python, it might help you if you want to stick with the inheritance idea given.
first I created some user management functions I want to use everywhere, and bound them to cherrypy, thinking I could import cherrypy elsewhere and they would be there. Other functions seem to import fine this way, when not used as decorators.
from user import validuser
cherrypy.validuser = validuser
del validuser
that didn't work, so next I tried passing the function into the class that is a section of my cherrypy site (/analyze) from the top level class of pages:
class Root:
analyze = Analyze(cherrypy.validuser) #maps to /analyze
And in the Analyze class, I referred to them. This works for normal functions but not for decorators. why not?
class Analyze:
def __init__(self, validuser):
self.validuser = validuser
#cherrypy.expose
#self.validuser(['uid'])
def index(self, **kw):
return analysis_panel.pick_data_sets(user_id=kw['uid'])
I'm stuck. How can I pass functions in and use them as decorators. I'd rather not wrap my functions like this:
return self.validuser(analysis_panel.pick_data_sets(user_id=kw['uid']),['uid'])
thanks.
ADDED/EDITED: here's what the decorator is doing, because as a separate issue, I don't think it is properly adding user_id into the kwargs
def validuser(old_function, fetch=['uid']):
def new_function(*args, **kw):
"... do stuff. decide is USER is logged in. return USER id or -1 ..."
if USER != -1 and 'uid' in fetch:
kw['uid'] = user_data['fc_uid']
return old_function(*args, **kw)
return new_function
only the kwargs that were passed in appear in the kwargs for the new_function. Anything I try to add isn't there. (what I'm doing appears to work here How can I pass a variable in a decorator to function's argument in a decorated function?)
The proper way in CherryPy to handle a situation like this is to have a tool and to enable that tool on the parts of your site that require authentication. Consider first creating this user-auth tool:
#cherrypy.tools.register('before_handler')
def validate_user():
if USER == -1:
return
cherrypy.request.uid = user_data['fc_uid']
Note that the 'register' decorator was added in CherryPy 5.5.0.
Then, wherever you wish to validate the user, either decorate the handler with the tool:
class Analyze:
#cherrypy.expose
#cherrypy.tools.validate_user()
def index(self):
return analysis_panel.pick_data_sets(user_id=cherrypy.request.uid)
Or in your cherrypy config, enable that tool:
config = {
'/analyze': {
'tools.validate_user.on': True,
},
}
The function/method is defined in the class, it doesn't make sense to decorate it with an instance variable because it won't be the same decorator for each instance.
You may consider using a property to create the decorated method when it is accessed:
#property
def index(self):
#cherrypy.expose
#self.validuser(['uid'])
def wrapped_index(**kw):
return analysis_panel.pick_data_sets(user_id=kw['uid'])
return wrapped_index
You may also consider trying to apply lru_cache to save the method for each instance but I'm not sure how to apply that with the property.
Let me give a brief explanation of the issue:
I have a server object with several functionalities.
all functionalities have some common code, so this warrants a functionalities base class
Each functionality has its own set of constants, defined in a constants class within the functionality.
The functionality base class has a set of common constants as well.
here is a sample code:
class server:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
class func1(base_func):
class consts:
new_name = base_func.common_consts.name #this is where the problem occurs
def get_result(self):
self.validate()
self.execute()
so when i try to use the common_consts from base_func, in func1.consts, I get the following error:
NameError: global name 'base_func' is not defined
I do not know why this happens. Can someone help?
Is there a limitation to the scope of nesting in python, especially 2.7
Also if i remove the top level server class, and have the functionality classes as independent classes, everything seems to work fine. The example of the working code is here:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
class func1(base_func):
class consts:
new_name = base_func.common_consts.name #this is where the problem occurs
def get_result(self):
self.validate()
self.execute()
This leads me to believe that there definitely exists some limitation to the nesting depth and namespace scopes in python. I just want to be sure before i make changes to my design.
class server:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
# base_func and func1 are at same, level. So, here you can directly use base_func and func1 anywhere
# at top level of the server class
class func1(base_func):
class consts:
new_name = base_func.common_consts.name # this is where the problem occurs
def get_result(self):
self.validate()
self.execute
For a class(classes have their own namespace), variable lookup works like this:
While parsing the class body any variable defined inside the class body can be access directly, but once
it is parsed it becomes a class attribute.
As, the class base_func is inside server class which is still being parsed the func1(base_func) will work fine.
But, for class consts base_func is not at the same level. So, after looking the variable in its body it will directly jump
to its enclosing scope, i.e global namespace in this case.
A fix will be to do the assignement like this:
class server:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
class func1(base_func):
class consts:
pass
def get_result(self):
self.validate()
self.execute
func1.consts.new_name = base_func.common_consts.name
You've hit a problem with class scope. The class scope is never made available except to operations that directly occur in the class scope. This is why you can't call method within another method without referencing self.
eg.
class A(object):
def f(self):
pass
def g(self):
f() # error, class scope isn't available
The same is true when you create a nested class. The initial class statement class ClassName(Base): has access to the class scope, but once in the nested class scope you lose access to the enclosing class scope.
Generally, there is no good reason to nest classes in python. You should try to create all classes at module level. You can hide internal classes by either placing them in a sub module or all prefixing them with an underscore.
class _BaseFunctionality(object):
# common constants
name = "name"
value = "value"
def execute(self):
return (self.name, self.value)
class _SpecificFunctionality(_BaseFunctionality):
# specific constants
# override value of value attribute
value = "another_value"
def get_result(self):
assert self.name == "name"
return self.execute()
class Server(object):
functionality = _SpecificFunctionality()
assert _BaseFunctionality.value == "value"
assert _SpecificFunctionality.value == "another_value"
assert Server().functionality.get_result() == ("name", "another_value")
I have an instance of a Python class that is creating another, and I'm wondering if the "created" class can access members of the "creator" without passing them in explicitly, or doing something like this:
class Creator(object):
def __init__(self, parameter):
self.parameter = parameter
self.created = Created(self)
class Created(object):
def __init__(self, creator):
self.creator = creator
self.parameter = self.creator.parameter
I guess what I'm trying to do is allow parameter to be accessed by both, except in practice there will be multiple parameters, so passing them all will result in a long list of arguments. My solution right now is to use a Creator as an argument to a Created. Is there a less awkward or smarter way to do this? Maybe put all the parameters in a dictionary?
You can do this, and you've almost done it, with one minor problem:
class Created():
def __init__(self, creator):
self.parameter = self.creator.parameter
There is no self.creator. If you never need to access it again after this __init__ call, just use the creator parameter directly:
class Created():
def __init__(self, creator):
self.parameter = creator.parameter
If you need it later, store it as self.creator, and then of course you can access it there:
class Created():
def __init__(self, creator):
self.creator = creator
self.parameter = self.creator.parameter
… although you probably don't even need to copy over parameter in that case, because you can always get to it as self.creator.parameter.
This is a very common pattern.
The only real downside to this is that if you keep the back-reference around (self.creator = creator), you can't have any __del__ methods. (Or you need to make it a weakref, or an indirect reference, like a key that can be used to look up the creator as needed.)
Another option
class Creator():
def __init__(self, parameter):
self.parameter = parameter
self.created = Created()
self.created.creator = self
IMHO it looks fine. If parameter is a class attribute instead of instance, you can use inheritance, but I don't think it is such an improvement.
def creator_factory(param):
class Creator(object):
parameter = param
return Creator
Creator = creator_factory(something)
class Created(Creator):
pass
>>> Created().parameter
'something'