why inheritance doesn't work well for this - python

1、I first used Python version 2.7, and through pip installed enum module.
from enum import Enum
class Format(Enum):
json = 0
other = 1
#staticmethod
def exist(ele):
if Format.__members__.has_key(ele):
return True
return False
class Weather(Enum):
good = 0
bad = 1
#staticmethod
def exist(ele):
if Weather.__members__.has_key(ele):
return True
return False
Format.exist('json')
Which works well, but I want to improve the code.
2、So I thought a better way might be like this:
from enum import Enum
class BEnum(Enum):
#staticmethod
def exist(ele):
if BEnum.__members__.has_key(ele)
return True
return False
class Format(Enum):
json = 0
other = 1
class Weather(Enum):
good = 0
bad = 1
Format.exist('json')
However this results in an error, because BEnum.__members__ is a class variable.
How can I get this to work?

There are three things you need to do here. First, you need to make BEnum inherit from Enum:
class BEnum(Enum):
Next, you need to make BEnum.exist a class method:
#classmethod
def exist(cls,ele):
return cls.__members__.has_key(ele)
Finally, you need to have Format and Weather inherit from BEnum:
class Format(BEnum):
class Weather(BEnum):
With exist being a static method, it can only operate on a specific class, regardless of the class that it is called from. By making it a class method, the class it is called from is passed automatically as the first argument (cls), and can be used for member access.
Here is a great description about the differences between static and class methods.

Related

How can a method directly access its class variables without using self?

I recently switched to Python from Java for development and is still not used to some of the implicitness of Python programming.
I have a class which I have defined some class variables, how can I access the class variables within a method in Python?
class Example:
CONSTANT_A = "A"
#staticmethod
def mymethod():
print(CONSTANT_A)
The above code would give me the error message: "CONSTANT_A" is not defined" by Pylance.
I know that I can make this work using self.CONSTANT_A, but self is referring to the Object, while I am trying to directly access to the Class variable (specifically constants).
Question
How can I directly access Class variables in Python and not through the instance?
In python, you cannot access the parent scope (class)'s fields from methods without self. or cls..
Consider using classmethod:
class Example:
CONSTANT_A = "A"
#classmethod
def mymethod(cls):
print(cls.CONSTANT_A)
or directly accessing it like Classname.attribute:
class Example:
CONSTANT_A = "A"
#staticmethod
def mymethod():
print(Example.CONSTANT_A)
for static method, you can access the class variable by <class_name>.<variable>.
>>> class Example:
... CONSTANT_A = "A"
... #staticmethod
... def mymethod():
... print(Example.CONSTANT_A)
...
>>>
>>> x = Example.mymethod()
A # print value

Passing python class object to bottle template

My class looks like this:
class Person:
def __init__(name=None, id_=None):
self.name = name
self.id_ = id_
# I'm currently doing this. member object is of Person type.
return template('index.html', name=member.name, id_=member.id_)
# What I want to do
return template('index.html', member=member)
First way is fine when we don't have many attributes to deal, but my class currently has around 10 attributes and it doesn't look good to pass so many parameters to template function. Now I want to pass an object of this class to bottle template and use it there. How can I do it?
# What I want to do
return template('index.html', member=member)
Just do that. It should work fine. In your template, you'll simply reference member.name, member.id_, etc.
If you have python 3.7+
from dataclasses import dataclass, asdict
#dataclass
class Person:
name: str
id_: str
member = Person('toto', '1')
return template('index.html', **asdict(member))
But maybe its more interesting to inject your object directly in your template.

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.

Check if a function raises NotImplementedError before calling it in Python

I have the following simplified scheme:
class NetworkAnalyzer(object):
def __init__(self):
print('is _score_funct implemented?')
#staticmethod
def _score_funct(network):
raise NotImplementedError
class LS(NetworkAnalyzer):
#staticmethod
def _score_funct(network):
return network
and I am looking for what I should use instead of print('is _score_funct implemented?') in order to figure out if a subclass has already implemented _score_funct(network) or not.
Note: If there is a more pythonic/conventional way of structuring the code, I would also appreciate its mention. The reason I defined it this way is, some NetworkAnalyzer subclasses have _score_funct in their definition, and the ones that dont have it will have different initialization of variables although they will have the same structure
Use an abstract base class and you won't be able to instantiate the class unless it implements all of the abstract methods:
import abc
class NetworkAnalyzerInterface(abc.ABC):
#staticmethod
#abc.abstractmethod
def _score_funct(network):
pass
class NetworkAnalyzer(NetworkAnalyzerInterface):
def __init__(self):
pass
class LS(NetworkAnalyzer):
#staticmethod
def _score_funct(network):
return network
class Bad(NetworkAnalyzer):
pass
ls = LS() # Ok
b = Bad() # raises TypeError: Can't instantiate abstract class Bad with abstract methods _score_funct
I'm not a metaclass/class specialist but here's a method that works in your simple case (not sure it works as-is in a complex/nested class namespace):
To check if the method was overridden, you could try a getattr on the function name, then check the qualified name (class part is enough using string partitionning):
class NetworkAnalyzer(object):
def __init__(self):
funcname = "_score_funct"
d = getattr(self,funcname)
print(d.__qualname__.partition(".")[0] == self.__class__.__name__)
if _score_funct is defined in LS, d.__qualname__ is LS._score_funct, else it's NetworkAnalyzer._score_funct.
That works if the method is implemented at LS class level. Else you could replace by:
d.__qualname__.partition(".")[0] != "NetworkAnalyzer"
Of course if the method is overridden with some code which raises an NotImplementedError, that won't work... This method doesn't inspect methods code (which is hazardous anyway)

Using base class constructor as factory in Python?

I'm using base class constructor as factory and changing class in this constructor/factory to select appropriate class -- is this approach is good python practice or there are more elegant ways?
I've tried to read help about metaclasses but without big success.
Here example of what I'm doing.
class Project(object):
"Base class and factory."
def __init__(self, url):
if is_url_local(url):
self.__class__ = ProjectLocal
else:
self.__class__ = ProjectRemote
self.url = url
class ProjectLocal(Project):
def do_something(self):
# do the stuff locally in the dir pointed by self.url
class ProjectRemote(Project):
def do_something(self):
# do the stuff communicating with remote server pointed by self.url
Having this code I can create the instance of ProjectLocal/ProjectRemote via base class Project:
project = Project('http://example.com')
project.do_something()
I know that alternate way is to using fabric function that will return the class object based on url, then code will looks similar:
def project_factory(url):
if is_url_local(url):
return ProjectLocal(url)
else:
return ProjectRemote(url)
project = project_factory(url)
project.do_something()
Is my first approach just matter of taste or it has some hidden pitfalls?
You shouldn't need metaclasses for this. Take a look at the __new__ method. This will allow you to take control of the creation of the object, rather than just the initialisation, and so return an object of your choosing.
class Project(object):
"Base class and factory."
def __new__(cls, url):
if is_url_local(url):
return super(Project, cls).__new__(ProjectLocal, url)
else:
return super(Project, cls).__new__(ProjectRemote, url)
def __init__(self, url):
self.url = url
I would stick with the factory function approach. It's very standard python and easy to read and understand. You could make it more generic to handle more options in several ways such as by passing in the discriminator function and a map of results to classes.
If the first example works it's more by luck than by design. What if you wanted to have an __init__ defined in your subclass?
The following links may be helpful:
http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#factory
http://code.activestate.com/recipes/86900/
In addition, as you are using new style classes, using __new__ as the factory function (and not in a base class, a separate class is better) is what is usually done (as far as I know).
A factory function is generally simpler (as other people have already posted)
In addition, it isn't a good idea to set the __class__ attribute the way you have done.
I hope you find the answer and the links helpful.
All the best.
Yeah, as mentioned by #scooterXL, factory function is the best approach in that case, but I like to note a case for factories as classmethods.
Consider the following class hierarchy:
class Base(object):
def __init__(self, config):
""" Initialize Base object with config as dict."""
self.config = config
#classmethod
def from_file(cls, filename):
config = read_and_parse_file_with_config(filename)
return cls(filename)
class ExtendedBase(Base):
def behaviour(self):
pass # do something specific to ExtendedBase
Now you can create Base objects from config dict and from config file:
>>> Base({"k": "v"})
>>> Base.from_file("/etc/base/base.conf")
But also, you can do the same with ExtendedBase for free:
>>> ExtendedBase({"k": "v"})
>>> ExtendedBase.from_file("/etc/extended/extended.conf")
So, this classmethod factory can be also considered as auxiliary constructor.
I usually have a seperate factory class to do this. This way you don't have to use meta classes or assignments to self.__class__
I also try to avoid to put the knowledge about which classes are available for creation into the factory. Rather, I have all the available classes register themselves withe the factory during module import. The give there class and some information about when to select this class to the factory (this could be a name, a regex or a callable (e.g. a class method of the registering class)).
Works very well for me and also implements such things like encapsulation and information hiding.
I think the second approach using a factory function is a lot cleaner than making the implementation of your base class depend on its subclasses.
Adding to #Brian's answer, the way __new__ works with *args and **kwargs would be as follows:
class Animal:
def __new__(cls, subclass: str, name: str, *args, **kwargs):
if subclass.upper() == 'CAT':
return super(Animal, cls).__new__(Dog)
elif subclass.upper() == 'DOG':
return super(Animal, cls).__new__(Cat)
raise NotImplementedError(f'Unsupported subclass: "{subclass}"')
class Dog(Animal):
def __init__(self, name: str, *args, **kwargs):
self.name = name
print(f'Created Dog "{self.name}"')
class Cat(Animal):
def __init__(self, name: str, *args, num_whiskers: int = 5, **kwargs):
self.name = name
self.num_whiskers = num_whiskers
print(f'Created Cat "{self.name}" with {self.num_whiskers} whiskers')
sir_meowsalot = Animal(subclass='Cat', name='Sir Meowsalot')
shadow = Animal(subclass='Dog', name='Shadow')

Categories