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

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

Related

Calling subsclass #classmethod from parent class

I'm trying to do the following:
class A:
#classmethod
def test_function(cls, message):
cls.__get_the_function()
class B(A):
#classmethod
def __get_the_function(cls):
return print("BBBB")
class C(A):
#classmethod
def __get_the_function(cls):
return print("CCCC")
however when I call:
B.test_function("Test")
I get the following:
AttributeError: type object 'B' has no attribute '_A__get_the_function'
I want class A to __get_the_function from the subclass (either class B or C depends on which one I use), but it looks like it is trying to look for it in itself.
NOTE: I'm using Python 3.8.2
__-prefixed names are handled specially during class creation. The name is replaced when the function is defined by a mangled name, as if you had defined the function as
#classmethod
def test_function(cls, message):
cls._A__get_the_function()
in the first place.
This is done to explicitly provide a way to hide a name from a subclass. Since you want to override the name, __get_the_function isn't an appropriate name; use an ordinary _-prefixed name if you want to mark it as private:
class A:
#classmethod
def test_function(cls, message):
cls._get_the_function()
# Define *something*, since test_function assumes it
# will exist. It doesn't have to *do* anything, though,
# until you override it.
#classmethod
def _get_the_function(cls):
pass

Python 2.7 Ineritance get parent method properties

I am a newbie and have confused learning OOP on python. I am trying to inherit class also using super, but it didn't work as expected.
here my code.
parent.py
class Sale(http.Controller):
def cart(self, **post):
order = request.website.sale_get_order()
....
return request.render("website_sale.cart", values)
child.py
import Sale as sale
class SaleExtend(sale):
def cart(self, **post):
if order:
# do something
....
return super(SaleExtend, self).cart(**post)
I got an error,
AttributeError: 'Sale (extended by SaleExtend)' object has no attribute 'order'
if I just use pass its work correctly, but how to get order value from a parent?
or I did it wrong.
You have no instance nor a class variable order:
class Sale(http.Controller):
def cart(self, **post):
# FUNCTION SCOPE - exists only inside the function
order = request.website.sale_get_order()
....
return request.render("website_sale.cart", values)
Class variables are created like so:
class Ale():
content = "Lager" # this is shared between all instances -> "static"
Instance variables are created like so:
class Ale():
def __init__(self, ale_type):
self.content = ale_type # this is different for each instance unless you
# create multiple instances with the same ale_type
# but they are still "independent" of each other
Function scope variables are creates like so:
class Ale():
# ....
def doSomething(self):
lenContent = len(self.content) # function scope
print( self.content, lenContent )
def doElse(self):
print(lenContent) # NameError - does not exist in scope
See Resolution of names and Short description of the scoping rules?

why inheritance doesn't work well for this

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.

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

How to convert (inherit) parent to child class?

I would like to know how to convert parent object that was return by some function to child class.
class A(object):
def __init__():
pass
class B(A):
def functionIneed():
pass
i = module.getObject() # i will get object that is class A
j = B(i) # this will return exception
j.functionIneed()
I cannot change class A. If I could I would implement functionIneed to class A, but it is impossible because of structure of code.
Python does not support "casting". You will need to write B.__init__() so that it can take an A and initialize itself appropriately.
I have a strong suspicion, nay, conviction, that there is something horribly wrong with your program design that it requires you to do this. In Python, unlike Java, very few problems require classes to solve. If there's a function you need, simply define it:
def function_i_need(a):
"""parameter a: an instance of A"""
pass # do something with 'a'
However, if I cannot dissuade you from making your function a method of the class, you can change an instance's class by setting its __class__ attribute:
>>> class A(object):
... def __init__(self):
... pass
...
>>> class B(A):
... def functionIneed(self):
... print 'functionIneed'
...
>>> a = A()
>>> a.functionIneed()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'functionIneed'
>>> a.__class__ = B
>>> a.functionIneed()
functionIneed
This will work as long as B has no __init__ method, since, obviously, that __init__ will never be called.
You said you want to implement something like this:
class B(A):
def functionIneed():
pass
But really what you would be making is something more like this (unless you had intended on making a class or static method in the first place):
class B(A):
def functionIneed(self):
pass
Then you can call B.functionIneed(instance_of_A). (This is one of the advantages of having to pass self explicitly to methods.)
You did not correctly define your classes.
Should be like this:
class A(object):
def __init__(self):
pass
class B(A):
def __init__(self):
super(B,self).__init__()
def functionIneed(self):
pass
Then you can
j=B()
j.fuctionIneed()
as expected
You forgot to refer to the ins
Just thinking outside the box:
Instead of a new class with the function you want, how about just adding the function to the class or instance you already have?
There is a good description of this in
Adding a Method to an Existing Object Instance
How about:
i = module.getObject() # i will get object that is class A
try:
i.functionIneed()
except AttributeError:
# handle case when u have a bad object
Read up on duck typing.

Categories