_Getattr_ for Static/Class Variables

__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



Leave a reply



Submit