__getattr__ for static/class variables
__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
# # in python 3:
# class MyClass(metaclass=FooType):
# pass
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. __getattr__ and __getattribute__ for class/static atributes of dynamically generated classes
Just make your metaclass inherit from SomeFancyMetaclass, implement the __getattr__
(and __getattribute__
) there properly, and use this metaclass, rather than a call to type
to generate your inheited, dynamic class.
Although you are using a lot of seldon used stuff, there are no special mechanisms in the way - it should be plain Python -
Of course, you did not tell what you want to do in the metaclass special methods - there might be some black magic to be performed there - and if you are doing __getattribute__
, you always have to be extra careful, and redirect all attrbiutes that you don't care about to the super-call, otherwise, nothing works.
Also, keep in mind that the attribute-access ustomization possible with both methods won't work to "create magic dunder methods" - that is: your class won't magically have an __add__
or __dir__
method because your metaclass __getattribute__
generates one - rather, these are fixed in spcial slots by the Python runtime, and their checking and calling bypasses normal attribute lookup in Python.
Otherwise:
class Inherited(metaclass=SomeFancyMetaclass):
...
class MagicAttrsMeta(Inherited.__class__):
def __getattr__(self, attr):
if attr in ("flying", "circus", "brian", "king_arthur"):
return "coconut"
raise AttributeError()
generated_class = MagicAttrsMeta("GeneratedClass", (Inherited,), {})
Class (static) variables and methods
Variables declared inside the class definition, but not inside a method are class or static variables:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
As @millerdev points out, this creates a class-level i
variable, but this is distinct from any instance-level i
variable, so you could have>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
This is different from C++ and Java, but not so different from C#, where a static member can't be accessed using a reference to an instance.See what the Python tutorial has to say on the subject of classes and class objects.
@Steve Johnson has already answered regarding static methods, also documented under "Built-in Functions" in the Python Library Reference.
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy recommends classmethods over staticmethod, as the method then receives the class type as the first argument. getattr on class objects
Is this good enough?
import types
class Test(object):
@staticmethod
def foo():
print 'foo'
def bar(self):
print 'bar'
In combination with:>>>(isinstance(getattr(Test, 'foo'), types.FunctionType),
isinstance(getattr(Test, 'bar'), types.FunctionType))
True, False
You can also use the inspect
module:>>> inspect.isfunction(Test.foo)
True
>>> inspect.isfunction(Test.bar)
False
With a little additional work you can even distinguish class methods from instance methods and static methods:import inspect
def get_type(cls, attr):
try:
return [a.kind for a in inspect.classify_class_attrs(cls) if a.name == attr][0]
except IndexError:
return None
class Test(object):
@classmethod
def foo(cls):
print 'foo'
def bar(self):
print 'bar'
@staticmethod
def baz():
print 'baz'
You can use it as:>>> get_type(Test, 'foo')
'class method'
>>> get_type(Test, 'bar')
'method'
>>> get_type(Test, 'baz')
'static method'
>>> get_type(Test, 'nonexistant')
None
Python: Accessing static class variables from inside the class
Since none of the methods are called until after Sequence
is fully defined, you can refer to Sequence.__map__
without any trouble. For example:
def __setattr(self, name, value):
print('Setting atr', name, 'with val', value)
try:
self[Sequence.__map__[name]] = value
except KeyError:
object.__setattr__(self, name, value)
As an aside, here's a demonstration that class attributes may be accessed via objects as long as an instance attribute with the same name does not also exist:
class Foo:
i = 3
def __init__(self, overwrite):
if overwrite:
self.i = 4
f = Foo(False)
id(f.i) == id(Foo.i) # Should be True
f = Foo(True)
id(f.i) == id(Foo.i) # Should be False
Is there a method like '__getattribute__' for class (not instance) variables?
While the other two answers have a valid method. I like to take the route of 'least-magic'.
You can do something similar to the metaclass approach without actually using them. Simply by using a decorator.
def instancer(cls):
return cls()
@instancer
class SysProps(object):
def __getattribute__(self, key):
return key # dummy
This will create an instance of SysProps
and then assign it back to the SysProps
name. Effectively shadowing the actual class definition and allowing a constant instance.Since decorators are more common in Python I find this way easier to grasp for other people that have to read your code.
Python: How to fix, if a static class variable gets a different function reference pointer?
I thought already that my object is calling the referenced function with itself as argument. After a bit of research I finally found a solution. When I use a class variable to point to a function it will not referencing a direct pointer. It references the function as a bounced method of it's class. To get rid of the default call of calling a method with getattr
, the call function of getattr
for the class itself has to be overwritten (in this case the class bar
, because foo
(the wrapper classes) inherits the functionalities of bar
:
import inspect
class bar(object):
GET_STUFF = None
def __getattribute__(self, name):
attr = object.__getattribute__(self,name)
if name == "GET_STUFF":
# Check: is method and is bounced?
if inspect.ismethod(attr) and attr.im_self is not None:
return attr.__func__
return attr
getattr
of bar
is now pointing to the original function reference, but only for the class variable GET_STUFF
, because I want to leave the default functionality for the rest of my variables.So, when I now execute the following:
class foo(bar):
GET_STUFF = getStuff
def __init__(self):
print "inner func: ",self.GET_STUFF
self.GET_STUFF()
foo()
I get the expected result and can write my wrappers without producing additional code for each module with those wrapper classes:outer func: <function getStuff at 0x00000000034259E8>
inner func: <function getStuff at 0x00000000034259E8>
I do my stuff!!!
Related Topics
Import Text to Pandas with Multiple Delimiters
Scale Matplotlib.Pyplot.Axes.Scatter Markersize by X-Scale
How to Define a Class Constant Inside an Enum
Python - Email Header Decoding Utf-8
How to Solve Equations in Python
Filling a Queue and Managing Multiprocessing in Python
Is 'Import Module' Better Coding Style Than 'From Module Import Function'
Selecting Across Multiple Columns with Python Pandas
Is There an Platform Independent Equivalent of Os.Startfile()
How to Make a Local Variable (Inside a Function) Global
Detect 64Bit Os (Windows) in Python
Errors While Building/Installing C Module for Python 2.7
Reading Binary Data from Stdin
Matplotlib Custom Marker/Symbol