How can I get only class variables? - python

I have this class definition:
class cols:
name = 'name'
size = 'size'
date = 'date'
#classmethod
def foo(cls):
print "This is a class method"
With __dict__ I get all class attributes (members and variables). Also there are the "Internal attributes" too (like __main__). How can I get only the class variables without instantiation?

I wouldn't know a straightforward way, especially since from the interpreter's POV, there is not that much of a difference between a method of a class and any other variable (methods have descriptors, but that's it...).
So when you only want non-callable class members, you have to fiddle around a little:
>>> class cols:
... name = "name"
... #classmethod
... def foo(cls): pass
>>> import inspect
>>> def get_vars(cls):
... return [name for name, obj in cls.__dict__.iteritems()
if not name.startswith("__") and not inspect.isroutine(obj)]
>>> get_vars(cols)
['name']

import inspect
inspect.getmembers(cols)
There are a lot if things you can do with the inspect module: http://lfw.org/python/inspect.html

Related

Static class property pointing to special instance of the same class in Python

Coming from cpp/c#, how does one refer to the same class in the class body in Python:
class Foo(object):
ANSWER = Foo(42)
FAIL = Foo(-1)
def __init__(self, value):
self._v = value
When I try to use this code, I get "name 'Foo' is not defined" exception in a line trying to instantiate the ANSWER instance.
The name Foo is not set until the full class body has been executed. The only way you can do what you want is to add attributes to the class after the class statement has completed:
class Foo(object):
def __init__(self, value):
self._v = value
Foo.ANSWER = Foo(42)
Foo.FAIL = Foo(-1)
It sounds like you are re-inventing Python's enum module; it lets you define a class with constants that are really instances of that class:
from enum import Enum
class Foo(Enum):
ANSWER = 42
FAIL = -1
After that class statement has run, Foo.ANSWER is an instance of Foo with a .value attribute set to 42.

How to add or change a Class (not an instance)?

I would like to set an attribute to an class object directly, without creating an instance, e.g. having an alternative name that can be accessed like the __ name __ attribute:
class Foo:
pass
> Foo.__name__
Foo
But this doesn't work:
some_file.py:
class Foo:
alternativ_name = __name__ + "_ending"
print(Foo.alternativ_name)
This prints:
__main___ending
If I try it in the interactive Console, it returns something else again:
>>> class Foo:
... alt_name = __name__ + "_ending"
...
>>> Foo.alt_name
'builtins_ending'
What I would like to achive is:
class Foo:
alt_name = __name__ + "_ending"
Foo.alt_name
should return:
'Foo_ending'
How do I do this?
The variables __name__ and Foo.__name__ actually point to two different things. Using __name__ within the Foo class still uses the global variable, and not Foo.__name__.
Within the class, it is not possible to explicitly reference the same class:
class Foo:
alt_name = Foo.__name__ + "_ending"
# raises NameError: name 'Foo' is not defined
If you want the property on objects, you can do it during runtime, e.g. in the __init__. If you really want the property on the class itself, you can do that using metaclasses:
class Foo:
class __metaclass__(type):
#property
def alt_name(cls):
return cls.__name__ + "_ending"
Foo.__name__ has not yet been created at the point you are trying to access it. Therefore, when you access __name__ it gets the module's __name__. There are several ways you can solve this. One is by using a metaclass, but this is pretty overkill for just adding an attribute to a class. The second is to use a decorator on the class, and the third is to make alt_name a non-data descriptor or maybe a property.
Using a decorator:
def add_alt_name(template):
def decorator(klass):
klass.alt_name = template.format(klass.__name__)
return klass
return decorator
#add_alt_name(template="{}_ending")
class Foo:
pass
print(Foo.alt_name)
Using a non-data descriptor:
class AlternativeName:
def __init__(self, template, name="alt_name"):
self.template = template
self.name = "_" + name
def __get__(self, instance, klass):
try:
return getattr(klass, self.name)
except AttributeError:
pass
alt_name = self.template.format(klass.__name__)
setattr(klass, self.name, alt_name)
return alt_name
class Foo:
alt_name = AlternativeName(template="{}_ending")
print(Foo.alt_name)
Much simpler just to use a decorator.

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 !!!

Python Method overriding, does signature matter?

Lets say I have
class Super():
def method1():
pass
class Sub(Super):
def method1(param1, param2, param3):
stuff
Is this correct? Will calls to method1 always go to the sub class? My plan is to have 2 sub classes each override method1 with different params
In Python, methods are just key-value pairs in the dictionary attached to the class. When you are deriving a class from a base class, you are essentially saying that method name will be looked into first derived class dictionary and then in the base class dictionary. In order to "override" a method, you simply re-declare the method in the derived class.
So, what if you change the signature of the overridden method in the derived class? Everything works correctly if the call is on the derived instance but if you make the call on the base instance, you will get an error because the base class uses a different signature for that same method name.
There are however frequent scenarios where you want derived class method have additional parameters and you want method call work without error on base as well. This is called "Liskov substitution principle" (or LSP) which guarantees that if person switches from base to derived instance or vice versa, they don't have to revamp their code. To do this in Python, you need to design your base class with the following technique:
class Base:
# simply allow additional args in base class
def hello(self, name, *args, **kwargs):
print("Hello", name)
class Derived(Base):
# derived class also has unused optional args so people can
# derive new class from this class as well while maintaining LSP
def hello(self, name, age=None, *args, **kwargs):
super(Derived, self).hello(name, age, *args, **kwargs)
print('Your age is ', age)
b = Base()
d = Derived()
b.hello('Alice') # works on base, without additional params
b.hello('Bob', age=24) # works on base, with additional params
d.hello('Rick') # works on derived, without additional params
d.hello('John', age=30) # works on derived, with additional params
Above will print:
Hello Alice
Hello Bob
Hello Rick
Your age is None
Hello John
Your age is 30
.
Play with this code
Python will allow this, but if method1() is intended to be executed from external code then you may want to reconsider this, as it violates LSP and so won't always work properly.
You could do something like this if it's ok to use default arguments:
>>> class Super():
... def method1(self):
... print("Super")
...
>>> class Sub(Super):
... def method1(self, param1="X"):
... super(Sub, self).method1()
... print("Sub" + param1)
...
>>> sup = Super()
>>> sub = Sub()
>>> sup.method1()
Super
>>> sub.method1()
Super
SubX
In python, all class methods are "virtual" (in terms of C++). So, in the case of your code, if you'd like to call method1() in super class, it has to be:
class Super():
def method1(self):
pass
class Sub(Super):
def method1(self, param1, param2, param3):
super(Sub, self).method1() # a proxy object, see http://docs.python.org/library/functions.html#super
pass
And the method signature does matter. You can't call a method like this:
sub = Sub()
sub.method1()
It will work:
>>> class Foo(object):
... def Bar(self):
... print 'Foo'
... def Baz(self):
... self.Bar()
...
>>> class Foo2(Foo):
... def Bar(self):
... print 'Foo2'
...
>>> foo = Foo()
>>> foo.Baz()
Foo
>>>
>>> foo2 = Foo2()
>>> foo2.Baz()
Foo2
However, this isn't generally recommended. Take a look at S.Lott's answer: Methods with the same name and different arguments are a code smell.

Reverse mapping class attributes to classes in Python

I have some code in Python where I'll have a bunch of classes, each of which will have an attribute _internal_attribute. I would like to be able to generate a mapping of those attributes to the original class. Essentially I would like to be able to do this:
class A(object):
_internal_attribute = 'A attribute'
class B(object):
_internal_attribute = 'B attribute'
a_instance = magic_reverse_mapping['A attribute']()
b_instance = magic_reverse_mapping['B attribute']()
What I'm missing here is how to generate magic_reverse_mapping dict. I have a gut feeling that having a metaclass generate A and B is the correct way to go about this; does that seem right?
You can use a meta class to automatically register your classes in magic_reverse_mapping:
magic_reverse_mapping = {}
class MagicRegister(type):
def __new__(meta, name, bases, dict):
cls = type.__new__(meta, name, bases, dict)
magic_reverse_mapping[dict['_internal_attribute']] = cls
return cls
class A(object):
__metaclass__ = MagicRegister
_internal_attribute = 'A attribute'
afoo = magic_reverse_mapping['A attribute']()
Alternatively you can use a decorator on your classes to register them. I think this is more readable and easier to understand:
magic_reverse_mapping = {}
def magic_register(cls):
magic_reverse_mapping[cls._internal_attribute] = cls
return cls
#magic_register
class A(object):
_internal_attribute = 'A attribute'
afoo = magic_reverse_mapping['A attribute']()
Or you could even do it by hand. It's not that much more work without using any magic:
reverse_mapping = {}
class A(object):
_internal_attribute = 'A attribute'
reverse_mapping[A._internal_attribute] = A
Looking at the different variants I think the decorator version would be the most pleasant to use.
You need some data structure to store the list of applicable classes in the first place, but you don't have to generate it in the first place. You can read classes from globals instead. This naturally assumes that your classes extend object, as they do in your first post.
def magic_reverse_mapping(attribute_name, attribute_value):
classobjects = [val for val in globals().values() if isinstance(val, object)]
attrobjects = [cls for cls in classobjects if hasattr(cls, attribute_name)]
resultobjects = [cls for cls in attrobjects if object.__getattribute__(cls, attribute_name) == attribute_value]
return resultobjects
magic_reverse_mapping('_internal_attribute', 'A attribute')
#output: [<class '__main__.A'>]
Note that this returns a list of classes with that attribute value, because there may be more than one. If you wanted to instantiate the first one:
magic_reverse_mapping('_internal_attribute', 'A attribute')[0]()
#output: <__main__.A object at 0xb7ce486c>
Unlike in sth's answer, you don't have to add a decorator to your classes (neat solution, though). However, there's no way to exclude any classes that are in the global namespace.

Categories

Resources