Calling a class function from a class inside the class - python

I have this code:
class CongressApi:
class apiKeyError(Exception):
pass
class Member:
def __init__(self):
print("self.makeRequest()?") # want to call the makeRequest function in the external class
def __init__(self, apiKey):
self.key = apiKey
def makeRequest(self, req):
ret = requests.get(f"https://api.propublica.org/congress/v1/{req}", headers={"X-API-Key": self.key})
return ret.content
I would like to be able to call that makeRequest() function from inside the memeber class. is this possible?

It is not common practice in Python to nest classes like this. I would recommend something like this instead:
class CongressApi:
def __init__(self, apiKey):
self.key = apiKey
def makeRequest(self, req):
ret = requests.get(f"https://api.propublica.org/congress/v1/{req}", headers={"X-API-Key": self.key})
return ret.content
class Member:
def __init__(self, congress_api_key):
self.C = CongressAPI(congress_api_key)
print(f"{self.C.makeRequest()}")
class apiKeyError(Exception):
pass # this is really unnecessary - it's easier just to implement try/except blocks at each point in the code where an exception might be triggered.
In general, it's good practice to separate out your classes.

If you want your internal class's instance methods to be able to access instance methods of the outer class, the internal class's instance needs access to an instance of the external class. For example:
class CongressApi:
class Member:
def __init__(self, api):
api.makeRequest("bar")
def __init__(self, apiKey):
self.key = apiKey
def makeRequest(self, req):
print(f"making request {req} with apiKey {self.key}")
def do_member_thing(self):
member = self.Member(self)
api = CongressApi("foo")
api.do_member_thing() # making request bar with apiKey foo
Note that this is not actually a sensible way to organize your classes -- typically the point of an inner class would be to encapsulate some piece of state that doesn't depend on the outer class, and further to abstract that implementation away from the rest of the outer class's implementation. Passing the inner class a reference to the outer class is permitted, but it also entirely defeats the purpose from an architectural standpoint.

Related

Share variables within the instance of a class without adding them as attributes

I need to create an instance specific URL based on the argument given to create the instance. This URL has to be available to all methods of my class, but I don't want the URL to be an attribute of the instance itself.
This is what I have:
class Person(object):
def __init__(self, name):
self.name = name
self.url = f'https://stackoverflow/{name}/'
def methodA(self):
self.result1 = parse(self.url, do sth)
def methodB(self):
self.result2 = parse(self.url, do sth else)
This would be an improvement but wouldn't fulfill the DRY principle:
class Person(object):
def __init__(self, name):
self.name = name
def methodA(self):
url = f'https://stackoverflow/{self.name}/'
self.result1 = parse(url, do sth)
def methodB(self):
url = f'https://stackoverflow/{self.name}/'
self.result2 = parse(url, do sth else)
Isn't there something in between?
I thought about defining a method which deletes unwanted runtime attributes after adding them to self, but that's probably not best practice?
For the context: The example above is heavily simplified. The real world example is about several parsed objects of the response which are being used multiple times.
In addition to making it private, as #plalx mentioned, it seems like you also want to make it dynamic relative to self.name, which you can do by making it a property. For example:
class Person(object):
def __init__(self, name):
self.name = name
#property
def _url(self):
return f'https://stackoverflow/{self.name}/'
def methodA(self):
self.result1 = parse(self._url)
def methodB(self):
self.result2 = parse(self._url)
Unfortunately there's no access modifiers in Python so you can't make the variable private to the class like you would in languages like Java for instance. However, you can still indicate that it's meant to be an internal variable by using the _ or __ prefixes.
Another option would be to nest your class declaration within an enclosing function which is an approach commonly used to create private scopes in JavaScript, but since the URL is dynamic based on the name you'd have to re-compute it every time:
def Person(name):
def urlOf(person):
return f'https://stackoverflow/{person.name}/'
class Person(object):
def __init__(self, name):
self.name = name
def test(self):
print(urlOf(self));
return Person(name)
Person('test').test()

Best practice for providing optional functions for a class in Python

Currently I am writing a Python program with a plugin system. To develop a new plugin a new class must be created and inherit from a base plugin class. Now it should be possible to add optional functions via mixins. Some mixins provide new functions others access builtin types of the base class and can act with them or change them.
In the following a simplified structure:
import abc
import threading
class Base:
def __init__(self):
self.config = dict()
if hasattr(self, "edit_config"):
self.edit_config()
def start(self):
"""Starts the Plugin"""
if hasattr(self, "loop"):
self._loop()
class AMixin:
def edit_config(self):
self.config["foo"] = 123
class BMixin(abc.ABC):
def _loop(self):
thread = threading.Thread(target=self.loop, daemon=True)
thread.start()
#abc.abstractmethod
def loop(self):
"""Override this method with a while true loop to establish a ongoing loop
"""
pass
class NewPlugin(Base, AMixin, BMixin):
def loop(self):
while True:
print("Hello")
plugin = NewPlugin()
plugin.start()
What is the best way to tackle this problem?
EDIT: I need to make my question more specific. The question is whether the above is the Pythonic way and is it possible to ensure that the mixin are inherited exclusively in conjunction with the Base class. Additionally it would be good in an IDE like VSCode to get support for e.g. autocomplete when accessing builtin types of the Base class, like in AMixin, without inheriting from it of course.
If you want to allow but not require subclasses to define some behaviour in a method called by the base class, the simplest way is to declare the method in the base class, have an empty implementation, and just call the method unconditionally. This way you don't have to check whether the method exists before calling it.
class Base:
def __init__(self):
self.config = dict()
self.edit_config()
def start(self):
self.loop()
def edit_config(self):
pass
def loop(self):
pass
class AMixin:
def edit_config(self):
self.config["foo"] = 123
class NewPlugin(AMixin, Base):
def loop(self):
for i in range(10):
print("Hello")
Note that you have to write AMixin before Base in the list of superclasses, so that its edit_config method overrides the one from Base, and not the other way around. You can avoid this by writing class AMixin(Base): so that AMixin.edit_config always overrides Base.edit_config in the method resolution order.
If you want to require subclasses to implement one of the methods, then you can raise TypeError() instead of pass in the base class's method.
I would move the calls to the methods provided by the mix-ins to __init__ methods defined by those classes.
import abc
import threading
class Base:
def __init__(self, **kwargs):
super.__init__(**kwargs)
self.config = dict()
class AMixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.edit_config()
def edit_config(self):
self.config["foo"] = 123
class BMixin(abc.ABC):
def __init__(self, **kwargs):
super().__init__(**kwargs):
self.loop()
def _loop(self):
thread = threading.Thread(target=self.loop, daemon=True)
thread.start()
#abc.abstractmethod
def loop(self):
"""Override this method with a while true loop to establish a ongoing loop
"""
pass
class NewPlugin(Base, AMixin, BMixin):
pass
When you instantiate a concrete subclass of NewPlugin, Base.__init__, AMixin.__init__, and BMixin.__init__ will be called in that order.

How to use self in an abstract class implementation in Python?

I'm working on a project using abstract classes in Python (specifically, the abc module).
I have a few implementations of this abstract class, which have their own constructors and need to use self.
This is what my code looks like, but simplified:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = [] # not meant to be passed in, that's why it isn't an argument in __init__
#classmethod
def display(cls):
print(cls.get_contents())
#abstractmethod
def get_contents():
pass
class ImplementationOne(Base):
def __init__(self, url):
self.url = url
def get_contents(self):
return "The url was: " + url
class ImplementationTwo(Base):
def get_contents():
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
When I run this, however, I get the error TypeError: get_contents() missing 1 required positional argument: 'self'.
I figured that this is because get_contents() in ImplementationOne takes self, but it's not specified in the abstract method.
So, if I changed:
#abstractmethod
def get_contents():
pass
to
#abstractmethod
def get_contents(self):
pass
But I get the same error.
I've tried many combinations, including putting self as an argument to every occurrence or get_contents, and passing in cls to get_contents in the abstract class - but no luck.
So, pretty much, how can I use the self keyword (aka access attributes) in only some implementations of an abstract method, that's called within a class method in the abstract class itself.
Also, on a side note, how can I access self.sublinks from within all implementations of BaseClass, while having its values different in each instance of an implementation?
There are a few things wrong here. One is that the #classmethod decorator should only be used when you need it to be called on a class.
Example:
class ImplementationOne:
#classmethod
def display(cls):
print(f'The class name is {cls.__name__}.')
ImplementationOne.display()
There is nothing special about the name self. It's just what is used by everyone to refer to the instance. In python the instance is implicitly handed to the first argument of the class unless you have a #classmethod decorator. In that case the class is handed as the first argument.
That is why you are getting the TypeError. Since you are calling the method on the instance test_one.display() you are essentially calling it as an instance method. Since you need to access the instance method get_contents from within it that is what you want. As a classmethod you wouldn't have access to get_contents.
That means you need both the ABC and ImplementationOne to have those methods implemented as instance methods.
Since it is now an instance method on the ABC it also should be an instance method in ImplementationTwo.
Your other question was how to get self.sublinks as an attribute in both subclasses.
Since your are overriding __init__ in ImplementationOne you need to call the parent class's __init__ as well. You can do this by using super() to call the Super or Base class's methods.
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
Full working code:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = []
def display(self):
print(self.get_contents())
#abstractmethod
def get_contents(self):
pass
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
def get_contents(self):
return "The url was: " + self.url
class ImplementationTwo(BaseClass):
def get_contents(self):
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
test_two.display()
print(test_one.sublinks)

Use outer class instance as self in inner class?

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.

Multi-Level nested classes with inheritance among inner classes

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")

Categories