How can I access a classmethod from inside a class in Python - python

I would like to create a class in Python that manages above all static members. These members should be initiliazed during definition of the class already. Due to the fact that there will be the requirement to reinitialize the static members later on I would put this code into a classmethod.
My question: How can I call this classmethod from inside the class?
class Test():
# static member
x = None
# HERE I WOULD LOVE TO CALL SOMEHOW static_init!
# initialize static member in classmethod, so that it can be
#reinitialized later on again
#classmethod
def static_init(cls):
cls.x = 10
Any help is appreciated!
Thanks in advance,
Volker

At the time that x=10 is executed in your example, not only does the class not exist, but the classmethod doesn't exist either.
Execution in Python goes top to bottom. If x=10 is above the classmethod, there is no way you can access the classmethod at that point, because it hasn't been defined yet.
Even if you could run the classmethod, it wouldn't matter, because the class doesn't exist yet, so the classmethod couldn't refer to it. The class is not created until after the entire class block runs, so while you're inside the class block, there's no class.
If you want to factor out some class initialization so you can re-run it later in the way you describe, use a class decorator. The class decorator runs after the class is created, so it can call the classmethod just fine.
>>> def deco(cls):
... cls.initStuff()
... return cls
>>> #deco
... class Foo(object):
... x = 10
...
... #classmethod
... def initStuff(cls):
... cls.x = 88
>>> Foo.x
88
>>> Foo.x = 10
>>> Foo.x
10
>>> Foo.initStuff() # reinitialize
>>> Foo.x
88

You call a class method by appending the class name likewise:
class.method
In your code something like this should suffice:
Test.static_init()
You could also do this:
static_init(Test)
To call it inside your class, have your code do this:
Test.static_init()
My working code:
class Test(object):
#classmethod
def static_method(cls):
print("Hello")
def another_method(self):
Test.static_method()
and Test().another_method() returns Hello

You can't call a classmethod in the class definition because the class hasn't been fully defined yet, so there's nothing to pass the method as its first cls argument...a classic chicken-and-egg problem. However you can work around this limitation by overloading the __new__() method in a metaclass, and calling the classmethod from there after the class has been created as illustrated below:
class Test(object):
# nested metaclass definition
class __metaclass__(type):
def __new__(mcl, classname, bases, classdict):
cls = type.__new__(mcl, classname, bases, classdict) # creates class
cls.static_init() # call the classmethod
return cls
x = None
#classmethod
def static_init(cls): # called by metaclass when class is defined
print("Hello")
cls.x = 10
print Test.x
Output:
Hello
10

After re-reading your question carefully this time I can think of two solutions. The first one is to apply the Borg design pattern. The second one is to discard the class method and use a module level function instead. This appears to solve your problem:
def _test_static_init(value):
return value, value * 2
class Test:
x, y = _test_static_init(20)
if __name__ == "__main__":
print Test.x, Test.y
Old, incorrect answer:
Here's an example, I hope it helps:
class Test:
x = None
#classmethod
def set_x_class(cls, value):
Test.x = value
def set_x_self(self):
self.__class__.set_x_class(10)
if __name__ == "__main__":
obj = Test()
print Test.x
obj.set_x_self()
print Test.x
obj.__class__.set_x_class(15)
print Test.x
Anyway, NlightNFotis's answer is a better one: use the class name when accessing the class methods. It makes your code less obscure.

This seems like a reasonable solution:
from __future__ import annotations
from typing import ClassVar, Dict
import abc
import string
class Cipher(abc.ABC):
#abc.abstractmethod
def encrypt(self, plaintext: str) -> str:
pass
#abc.abstractmethod
def decrypt(self, ciphertext: str) -> str:
pass
class RotateCipher(Cipher, abc.ABC):
#staticmethod
def rotate(n: int) -> str:
return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]
class VigenereCipher(RotateCipher):
_TABLE: ClassVar[Dict[str, str]] = dict({(chr(i + ord("A")), RotateCipher.rotate(i)) for i in range(26)})
def encrypt(self, plaintext: str) -> str:
pass
def decrypt(self, plaintext: str) -> str:
pass
vc = VigenereCipher()
The method is now a static method of the cipher, nothing outside the classes is referenced. You could opt to name RotateCipher _RotateCipher instead, if you don't want people using it by itself.
Note: I removed the Final, as I ran this on 3.7, but after reading the documentation on Final, I don't think it would affect the solution? Also added an import for string which the question was missing. And finally added an implementation for the abstract methods, alternatively, could have let VigenereCipher inherit from abc.ABC as well.

If your classmethod is not used very often do a lazy evaluation
class A() {
# this does not work: x=A.initMe()
#classmethod
def initMe(cls) {
if not hasattr(cls,"x"):
# your code her
cls.x=# your result
pass
#classmethod
def f1(cls) {
# needs initMe
cls.initMe()
# more code using cls.x
}
}

Related

python getter and setter in dict style of static class [duplicate]

I have a class like:
class MyClass:
Foo = 1
Bar = 2
Whenever MyClass.Foo or MyClass.Bar is invoked, I need a custom method to be invoked before the value is returned. Is it possible in Python? I know it is possible if I create an instance of the class and I can define my own __getattr__ method. But my scnenario involves using this class as such without creating any instance of it.
Also I need a custom __str__ method to be invoked when str(MyClass.Foo) is invoked. Does Python provide such an option?
__getattr__() and __str__() for an object are found on its class, so if you want to customize those things for a class, you need the class-of-a-class. A metaclass.
class FooType(type):
def _foo_func(cls):
return 'foo!'
def _bar_func(cls):
return 'bar!'
def __getattr__(cls, key):
if key == 'Foo':
return cls._foo_func()
elif key == 'Bar':
return cls._bar_func()
raise AttributeError(key)
def __str__(cls):
return 'custom str for %s' % (cls.__name__,)
class MyClass(metaclass=FooType):
pass
# # in python 2:
# class MyClass:
# __metaclass__ = FooType
print(MyClass.Foo)
print(MyClass.Bar)
print(str(MyClass))
printing:
foo!
bar!
custom str for MyClass
And no, an object can't intercept a request for a stringifying one of its attributes. The object returned for the attribute must define its own __str__() behavior.
Updated 2023-02-20 for Python 3.x default implementation (python 2 as a comment).
(I know this is an old question, but since all the other answers use a metaclass...)
You can use the following simple classproperty descriptor:
class classproperty(object):
""" #classmethod+#property """
def __init__(self, f):
self.f = classmethod(f)
def __get__(self, *a):
return self.f.__get__(*a)()
Use it like:
class MyClass(object):
#classproperty
def Foo(cls):
do_something()
return 1
#classproperty
def Bar(cls):
do_something_else()
return 2
For the first, you'll need to create a metaclass, and define __getattr__() on that.
class MyMetaclass(type):
def __getattr__(self, name):
return '%s result' % name
class MyClass(object):
__metaclass__ = MyMetaclass
print MyClass.Foo
For the second, no. Calling str(MyClass.Foo) invokes MyClass.Foo.__str__(), so you'll need to return an appropriate type for MyClass.Foo.
Surprised no one pointed this one out:
class FooType(type):
#property
def Foo(cls):
return "foo!"
#property
def Bar(cls):
return "bar!"
class MyClass(metaclass=FooType):
pass
Works:
>>> MyClass.Foo
'foo!'
>>> MyClass.Bar
'bar!'
(for Python 2.x, change definition of MyClass to:
class MyClass(object):
__metaclass__ = FooType
)
What the other answers say about str holds true for this solution: It must be implemented on the type actually returned.
Depending on the case I use this pattern
class _TheRealClass:
def __getattr__(self, attr):
pass
LooksLikeAClass = _TheRealClass()
Then you import and use it.
from foo import LooksLikeAClass
LooksLikeAClass.some_attribute
This avoid use of metaclass, and handle some use cases.

How to initialize a class member using a classmethod

I have a class, which holds some member x (say, some data that is needed by all instances, but independent of them):
class Foo(object):
x = 23
# some more code goes here
Now, the procedure of determining x became more complex plus I wanted to be able to "refresh" x at certain times, so I decided to write an extra function for it
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
# some more code goes here
However, this class definition lacks an initialization call of generate_x.
What I tried so far:
This does not work:
class Foo(object):
# generate_x() # NameError: name 'generate_x' is not defined
# Foo.generate_x() # NameError: name 'Foo' is not defined
#classmethod
def generate_x(cls):
cls.x = 23
This works but less clear, because code is used outside the class definition
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
# ...
Foo.generate_x()
Are there better alternatives to this? Is using #classmethod the best approach here? What I'm searching is a class-equivalent of __init__.
Considering code clarity, is there a better way than the latter to instantiate Foo.x automatically using a function?
One way to achieve this is by using a decorator:
def with_x(cls):
cls.generate_x()
return cls
#with_x
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
(That said, I personally would just call Foo.generate_x explicitly after the class declaration, and avoid all the magic altogether.)
Use a descriptor.
class Complicated:
def __init__(self, location, get_value):
self.location =location
self.get_value = staticmethod(get_value)
def __get__(self, obj, owner):
try:
a = getattr(owner, self.location)
except AttributeError:
a = self.get_value()
setattr(owner, self.location, a)
return a
class My class:
x = Complicated ('_x', get_x)

Naming conventions for class method vs instance method

I have two methods, one for the individual Instance, and one for every Instance in that class:
class MasterMatches(models.Model):
#classmethod
def update_url_if_any_matches_has_one(cls):
# apply to all instances, call instance method.
def update_url_if_any_matches_has_one(self):
# do something
Should I name these the same? Or, what is a good naming convention here?
The question of using the same names can be clarified by understanding how decorators work.
#dec
def foo(x):
print(x)
translates to
def foo(x):
print(x)
foo = dec(foo)
In your example the decorator syntax can be expanded to
class MasterMatches(models.Model):
def update_url_if_any_matches_has_one(cls):
# apply to all instances, call instance method.
update_url_if_any_matches_has_one = classmethod(update_url_if_any_matches_has_one)
def update_url_if_any_matches_has_one(self):
# do something
The former implementation of update_url_if_any_matches_has_one will be overwritten by the latter.
Usually use self declaration style. #classmethod use only if method not works with class instance fields.
Function decorated as #classmethod takes the first argument is the class type, while normal method takes instance of object.
class A:
#classmethod
def a(cls):
print(cls)
def b(self):
print(self)
a = A()
a.a()
a.b()
# Output:
# <class '__main__.A'>
# <__main__.A object at 0x03FC5DF0>
It can be useful if you have a static class fields. The to access therm you don't need explicitly specify the class name. But you don't get access to instance fields. Example:
class A:
field = 1
#classmethod
def a(cls):
print(cls.field)
def b(self):
self.field = 2
print(self.field, A.field)
a = A()
a.a()
a.b()
# Outputs:
# 1
# 2 1

Get name of current class?

How do I get the name of the class I am currently in?
Example:
def get_input(class_name):
[do things]
return class_name_result
class foo():
input = get_input([class name goes here])
Due to the nature of the program I am interfacing with (vistrails), I cannot use __init__() to initialize input.
obj.__class__.__name__ will get you any objects name, so you can do this:
class Clazz():
def getName(self):
return self.__class__.__name__
Usage:
>>> c = Clazz()
>>> c.getName()
'Clazz'
Within the body of a class, the class name isn't defined yet, so it is not available. Can you not simply type the name of the class? Maybe you need to say more about the problem so we can find a solution for you.
I would create a metaclass to do this work for you. It's invoked at class creation time (conceptually at the very end of the class: block), and can manipulate the class being created. I haven't tested this:
class InputAssigningMetaclass(type):
def __new__(cls, name, bases, attrs):
cls.input = get_input(name)
return super(MyType, cls).__new__(cls, name, bases, newattrs)
class MyBaseFoo(object):
__metaclass__ = InputAssigningMetaclass
class foo(MyBaseFoo):
# etc, no need to create 'input'
class foo2(MyBaseFoo):
# etc, no need to create 'input'
PEP 3155 introduced __qualname__, which was implemented in Python 3.3.
For top-level functions and classes, the __qualname__ attribute is equal to the __name__ attribute. For nested classes, methods, and nested functions, the __qualname__ attribute contains a dotted path leading to the object from the module top-level.
It is accessible from within the very definition of a class or a function, so for instance:
class Foo:
print(__qualname__)
will effectively print Foo.
You'll get the fully qualified name (excluding the module's name), so you might want to split it on the . character.
However, there is no way to get an actual handle on the class being defined.
>>> class Foo:
... print('Foo' in globals())
...
False
You can access it by the class' private attributes:
cls_name = self.__class__.__name__
EDIT:
As said by Ned Batchelder, this wouldn't work in the class body, but it would in a method.
EDIT: Yes, you can; but you have to cheat: The currently running class name is present on the call stack, and the traceback module allows you to access the stack.
>>> import traceback
>>> def get_input(class_name):
... return class_name.encode('rot13')
...
>>> class foo(object):
... _name = traceback.extract_stack()[-1][2]
... input = get_input(_name)
...
>>>
>>> foo.input
'sbb'
However, I wouldn't do this; My original answer is still my own preference as a solution. Original answer:
probably the very simplest solution is to use a decorator, which is similar to Ned's answer involving metaclasses, but less powerful (decorators are capable of black magic, but metaclasses are capable of ancient, occult black magic)
>>> def get_input(class_name):
... return class_name.encode('rot13')
...
>>> def inputize(cls):
... cls.input = get_input(cls.__name__)
... return cls
...
>>> #inputize
... class foo(object):
... pass
...
>>> foo.input
'sbb'
>>>
#Yuval Adam answer using #property
class Foo():
#property
def name(self):
return self.__class__.__name__
f = Foo()
f.name # will give 'Foo'
I think, it should be like this:
class foo():
input = get_input(__qualname__)
import sys
def class_meta(frame):
class_context = '__module__' in frame.f_locals
assert class_context, 'Frame is not a class context'
module_name = frame.f_locals['__module__']
class_name = frame.f_code.co_name
return module_name, class_name
def print_class_path():
print('%s.%s' % class_meta(sys._getframe(1)))
class MyClass(object):
print_class_path()
I'm using python3.8 and below is example to get your current class name.
class MyObject():
#classmethod
def print_class_name(self):
print(self.__name__)
MyObject.print_class_name()
Or without #classmethod you can use
class ClassA():
def sayhello(self):
print(self.getName())
def getName(self):
return self.__class__.__name__
ClassA().sayhello()
Hope that helps others !!!

Is it safe to replace a self object by another object of the same type in a method?

I would like to replace an object instance by another instance inside a method like this:
class A:
def method1(self):
self = func(self)
The object is retrieved from a database.
It is unlikely that replacing the 'self' variable will accomplish whatever you're trying to do, that couldn't just be accomplished by storing the result of func(self) in a different variable. 'self' is effectively a local variable only defined for the duration of the method call, used to pass in the instance of the class which is being operated upon. Replacing self will not actually replace references to the original instance of the class held by other objects, nor will it create a lasting reference to the new instance which was assigned to it.
As far as I understand, If you are trying to replace the current object with another object of same type (assuming func won't change the object type) from an member function. I think this will achieve that:
class A:
def method1(self):
newObj = func(self)
self.__dict__.update(newObj.__dict__)
It is not a direct answer to the question, but in the posts below there's a solution for what amirouche tried to do:
Python object conversion
Can I dynamically convert an instance of one class to another?
And here's working code sample (Python 3.2.5).
class Men:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a men! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_men(self):
print('I made The Matrix')
class Women:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a women! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_women(self):
print('I made Cloud Atlas')
men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix
men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas
Note the self.__class__ and not self.__class__.__name__. I.e. this technique not only replaces class name, but actually converts an instance of a class (at least both of them have same id()). Also, 1) I don't know whether it is "safe to replace a self object by another object of the same type in [an object own] method"; 2) it works with different types of objects, not only with ones that are of the same type; 3) it works not exactly like amirouche wanted: you can't init class like Class(args), only Class() (I'm not a pro and can't answer why it's like this).
Yes, all that will happen is that you won't be able to reference the current instance of your class A (unless you set another variable to self before you change it.) I wouldn't recommend it though, it makes for less readable code.
Note that you're only changing a variable, just like any other. Doing self = 123 is the same as doing abc = 123. self is only a reference to the current instance within the method. You can't change your instance by setting self.
What func(self) should do is to change the variables of your instance:
def func(obj):
obj.var_a = 123
obj.var_b = 'abc'
Then do this:
class A:
def method1(self):
func(self) # No need to assign self here
In many cases, a good way to achieve what you want is to call __init__ again. For example:
class MyList(list):
def trim(self,n):
self.__init__(self[:-n])
x = MyList([1,2,3,4])
x.trim(2)
assert type(x) == MyList
assert x == [1,2]
Note that this comes with a few assumptions such as the all that you want to change about the object being set in __init__. Also beware that this could cause problems with inheriting classes that redefine __init__ in an incompatible manner.
Yes, there is nothing wrong with this. Haters gonna hate. (Looking at you Pycharm with your in most cases imaginable, there's no point in such reassignment and it indicates an error).
A situation where you could do this is:
some_method(self, ...):
...
if(some_condition):
self = self.some_other_method()
...
return ...
Sure, you could start the method body by reassigning self to some other variable, but if you wouldn't normally do that with other parametres, why do it with self?
One can use the self assignment in a method, to change the class of instance to a derived class.
Of course one could assign it to a new object, but then the use of the new object ripples through the rest of code in the method. Reassiging it to self, leaves the rest of the method untouched.
class aclass:
def methodA(self):
...
if condition:
self = replace_by_derived(self)
# self is now referencing to an instance of a derived class
# with probably the same values for its data attributes
# all code here remains untouched
...
self.methodB() # calls the methodB of derivedclass is condition is True
...
def methodB(self):
# methodB of class aclass
...
class derivedclass(aclass):
def methodB(self):
#methodB of class derivedclass
...
But apart from such a special use case, I don't see any advantages to replace self.
You can make the instance a singleton element of the class
and mark the methods with #classmethod.
from enum import IntEnum
from collections import namedtuple
class kind(IntEnum):
circle = 1
square = 2
def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
class Shape(namedtuple('Shape', 'k,l,b,u,r')):
self = None
#classmethod
def __repr__(cls):
return "<Shape({},{},{},{},{}) object at {}>".format(
*(attr(cls.self)+[id(cls.self)]))
#classmethod
def transform(cls, func):
cls.self = cls.self._replace(**func(cls.self))
Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
s = Shape.self
def nextkind(self):
return {'k': self.k+1}
print(repr(s)) # <Shape(1,2,3,4,5) object at 139766656561792>
s.transform(nextkind)
print(repr(s)) # <Shape(2,2,3,4,5) object at 139766656561888>

Categories

Resources