Consider this class:
class Foo(object):
def bar(self, name):
return 'bar: ' + name
def baz(self, name):
return 'baz: ' + name
I need to tell code to run the baz method:
def run_a_method(method, name):
f = Foo()
f.method(name)
run_a_method('baz', 'Jeff Atwood')
This fails with the following error:
AttributeError: 'Foo' object has no attribute 'method'
What is the proper way to call the function on whatever class f is defined?
First, you need to define your class correctly - don't forget the self parameter:
class Foo(object):
def bar(self, name):
return 'bar: ' + name
def baz(self, name):
return 'baz: ' + name
Then, use getattr() to access an attribute by name:
>>> a = Foo()
>>> getattr(a, "baz")("Jeff Atwood")
'baz: Jeff Atwood'
Related
Is there a way to get a list or return all the instances of a class within a class in python? I've already done some research into it and all the answers that I've seen assume the instances are global variables, not part of an existing class.
For example, can I find all instances of Bar that are instantiated within the class Foo below?
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe')
self.mymsg2 = Bar('Jane Doe')
self.somenumber = 42
self.somewords = 'hello world'
class Bar:
def __init__(self, name):
self.hellomsg = 'hello ' + name
I want to be able to get mymsg1 and mymsg2 because they are Bar objects, but I don't want any of the other attributes or methods.
You can use class variable very easily:
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe')
self.mymsg2 = Bar('Jane Doe')
self.somenumber = 42
self.somewords = 'hello world'
class Bar:
_instances = []
def __init__(self, name):
Bar._instances.append(self)
self.hellomsg = 'hello ' + name
>>> f = Foo()
>>> print('first:', Bar._instances[0].hellomsg,
... ', second:' ,Bar._instances[1].hellomsg)
first: hello John Doe , second: hello Jane Doe
For partitioning the Bar instances by instantiator, one can do this:
from collections import defaultdict
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe', self)
self.mymsg2 = Bar('Jane Doe', self)
self.somenumber = 42
self.somewords = 'hello world'
class Bar:
_instances = defaultdict(list)
def __init__(self, name, instantiator):
Bar._instances[instantiator].append(self)
self.hellomsg = 'hello ' + name
>>> f, ff = Foo(), Foo()
>>> print('first:', Bar._instances[f][0].hellomsg,
... ', second:' ,Bar._instances[ff][1].hellomsg)
first: hello John Doe , second: hello Jane Doe
The simplest and most effective method is to create an appropriate data structure and avoid doing Python magic. However, if you have a degree in serpentine magic, I have listed various methods of advanced wizardry below.
Search __dict__
class Foo:
def __init__(self):
self.bar1 = Bar()
self.bar2 = Bar()
def bars(self):
return [v for v in self.__dict__.values() if isinstance(v, Bar)]
Manually register each name
class Foo:
def __init__(self):
self._bar_names = {"bar1", "bar2"}
self.bar1 = Bar()
self.bar2 = Bar()
def bars(self):
return [self.__dict__[x] for x in self._bar_names]
Automatically register names by overriding __setattr__
class Foo:
def __init__(self):
self._bar_names = set()
self.bar1 = Bar()
self.bar2 = Bar()
def __setattr__(self, name, value):
if name == "_bar_names":
self.__dict__[name] = value
return
if isinstance(value, Bar):
self._bar_names.add(name)
else:
self._bar_names.discard(name)
self.__dict__[name] = value
def bars(self):
return [self.__dict__[x] for x in self._bar_names]
This way you could filter whatever the class you pass by argument, and the function returns an array of that class objects.
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe')
self.mymsg2 = Bar('Jane Doe')
self.somenumber = 42
self.somewords = 'hello world'
def filter_class(self, _class):
return [i[1] for i in (self.__dict__).items() if isinstance(i[1],_class)]
class Bar:
def __init__(self, name):
self.hellomsg = 'hello ' + name
I'm looking to do something like this:
class MyClass(Object):
def ****(self):
print self.__name __
MyClass.test()
->test
MyClass.whatever()
->whatever
So you can call any method and it prints the name.
Implement a __getattr__() method on your class to intercept access attempts on unknown attributes, and return a function (which you could bind to the class):
class MyClass(object):
def __getattr__(self, name):
def echo():
return name
return echo
This returns unbound functions, with no reference to the instance.
You do need to create an instance first for this to work:
>>> class MyClass(object):
... def __getattr__(self, name):
... def echo():
... return name
... return echo
...
>>> instance = MyClass()
>>> instance.test()
'test'
>>> instance.whatever()
'whatever'
You can bind the function to the instance (so it gets self passed in) by manually invoking the descriptor protocol, calling __get__ on the function before returning:
class MyClass(object):
def __getattr__(self, name):
def echo(self):
return '{}.{}'.format(type(self).__name__, name)
return echo.__get__(self, type(self))
With access to self we can print a little more information:
>>> class MyClass(object):
... def __getattr__(self, name):
... def echo(self):
... return '{}.{}'.format(type(self).__name__, name)
... return echo.__get__(self, type(self))
...
>>> instance = MyClass()
>>> instance.test()
'MyClass.test'
>>> instance.whatever()
'MyClass.whatever'
Python has a magic __getattr__ method that allows custom values to be returned:
class A(object):
def __getattr__(self, name):
return name
B = A()
print B.foo # 'foo'
However, calling A.foo has no similar effect, because A is not an instance.
Using metaclasses, Google App Engine raises this error on instantiation:
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 913, in __init__
key_name.__class__.__name__)
BadKeyError: Name must be string type, not tuple
Assuming the referenced question is correctly implemented, what other ways can a magic class __getattr__ be implemented?
The metaclass solution should work, here is an example:
class GetAttrMeta(type):
def __getattr__(self, name):
return name
class A(object):
__metaclass__ = GetAttrMeta
print A.foo # 'foo'
Or with Python 3.x:
class GetAttrMeta(type):
def __getattr__(self, name):
return name
class A(object, metaclass=GetAttrMeta):
pass
print(A.foo) # 'foo'
Not sure if this answers your question, but maybe checkout property descriptors ..
class RevealAccess(object):
"""A data descriptor that sets and returns values
normally and prints a message logging their access.
"""
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val
def __set__(self, obj, val):
print 'Updating' , self.name
self.val = val
>>> class MyClass(object):
x = RevealAccess(10, 'var "x"')
y = 5
>>> MyClass.x
Retrieving var "x"
10
>>> MyClass().x
Retrieving var "x"
10
>>>
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20
>>> m.y
5
TL;DR: Having to define a unique set of getters and setters for each property()'d variable sucks. Can I define generic getters and setters and use them with whatever variable I want?
Let's say I make a class with some nice getters and setters:
class Foo
def getter(self):
return _bar+' sasquatch'
def setter(self, value):
_bar = value+' unicorns'
bar = property(getter, setter)
Pretty great, right?
Now let's say I put in another variable called "baz" and I don't want it to be left out from this sasquatch/unicorn fun. Well, I guess I could make another set of getters and setters:
class Foo
def bar_getter(self):
return _bar+' sasquatch'
def bar_setter(self, value):
_bar = value+' unicorns'
bar = property(bar_getter, bar_setter)
def baz_getter(self):
return _baz+' sasquatch'
def baz_setter(self, value):
_baz = value+' unicorns'
baz = property(baz_getter, baz_setter)
But that's not very DRY and needlessly clutters my code. I guess I could make it a bit DRYer:
class Foo
def unicornify(self, value):
return value+' unicorns'
def sasquatchify(self, value):
return value+' sasquatch'
def bar_getter(self):
return self.sasquatchify(_bar)
def bar_setter(self, value):
_bar = self.unicornify(_bar)
bar = property(bar_getter, bar_setter)
def baz_getter(self):
return self.sasquatchify(_baz)
def baz_setter(self, value):
_baz = self.unicornify(_baz)
baz = property(baz_getter, baz_setter)
Although that might make my code DRYer, it's not ideal. If I wanted to unicornify and sasquatchify two more variables, I would have to add four more functions!
There must be a better way to do this. Can I use a single generic getter and/or setter across multiple variables?
Unicorn-less and sasquatch-less real-world implementation: I'm using SQLAlchemy ORM, and want to transform some of the data when storing and retrieving it from the database. Some of the transformations are applicable to more than one variable, and I don't want to clutter my classes with getters and setters.
How about just:
def sasquatchicorn(name):
return property(lambda self: getattr(self, name) + ' sasquatch',
lambda self, val: setattr(self, name, val + ' unicorns'))
class Foo(object):
bar = sasquatchicorn('_bar')
baz = sasquatchicorn('_baz')
Somewhat more generically:
def sasquatchify(val):
return val + ' sasquatch'
def unicornify(val):
return val + ' unicorns'
def getset(name, getting, setting):
return property(lambda self: getting(getattr(self, name)),
lambda self, val: setattr(self, name, setting(val)))
class Foo(object):
bar = getset('_bar', sasquatchify, unicornify)
baz = getset('_baz', sasquatchify, unicornify)
Or, with barely more work, you can use the full descriptor protocol, as described in agf's answer.
This is what the descriptor protocol property is based on is for:
class Sasicorn(object):
def __init__(self, attr):
self.attr = "_" + attr
def __get__(self, obj, objtype):
return getattr(obj, self.attr) + ' sasquatch'
def __set__(self, obj, value):
setattr(obj, self.attr, value + ' unicorns')
class Foo(object):
def __init__(self, value = "bar"):
self.bar = value
self.baz = "baz"
bar = Sasicorn('bar')
baz = Sasicorn('baz')
foo = Foo()
foo2 = Foo('other')
print foo.bar
# prints bar unicorns sasquatch
print foo.baz
# prints baz unicorns sasquatch
print foo2.bar
# prints other unicorns sasquatch
While property in a factory function may be fine for your toy example, it sounds like maybe you need more control for your real use case.
Using getattribute and setattr you can define this for all attributes past and future.
class Foo(object):
x = 3
def __getattribute__(self, attr):
return str(object.__getattribute__(self, attr)) + ' sasquatch'
def __setattr__(self, attr, value):
object.__setattr__(self, attr, str(value) + ' unicorn')
print Foo.x
f = Foo()
print f.x
f.y = 4
print f.y
This prints:
3
3 sasquatch
4 unicorn sasquatch
A colleague of mine suggested using closures to return getter and setter functions, which is what I've decided to use.
class Foo(object):
def setter(var):
def set(self, value):
setattr(self, var, value+' unicorn')
return set
def getter(var):
def get(self):
return getattr(self, var)+' sasquatch'
return get
bar = property(getter('_bar'), setter('_bar'))
f = Foo()
f.foo = 'hi'
print f.foo
But thank you all for your answers :)
# coding=utf-8
__author__ = 'Ahmed Şeref GÜNEYSU'
class Student(object):
def __init__(self, **kwargs):
for k, v in kwargs.iteritems():
self.__setattr__(k, v)
if __name__ == '__main__':
o = Student(first_name='Ahmed Şeref', last_name='GÜNEYSU')
print "{0} {1}".format(o.first_name, o.last_name)
print o.email
Gives
Ahmed Şeref GÜNEYSU
File "/Users/ahmed/PycharmProjects/sanbox/abstract_classes/object_initializer/__init__.py", line 13, in <module>
print o.email
AttributeError: 'Student' object has no attribute 'email'
Process finished with exit code 137
I've got a class:
class Foo():
def bar(name):
return something
and i want to have
foo = Foo()
foo.name
returning the same as foo.bar('name'). Is it possible?
This will automatically use bar if the attribute doesn't exist:
class Foo(object):
def bar(self, name):
return name
def bar2(self, attr, value):
print attr, value
def __getattr__(self, attr):
return self.bar(attr)
def __setattr__(self, attr, value):
self.bar2(attr, value)
foo = Foo()
print foo.name
foo.name = 'not name'
As you describe it now, name only exists in the scope of the function bar and thus Foo has no direct access to it unless you store it in its scope. The simplest solution would be to make a member field called name and set its value in bar.
class Foo():
def __init__(self):
self.name = None
def bar(self, name):
self.name = name
return something
Declare your class:
class Foo:
def bar(self, name):
return 'something'
You can assign the method to an attribute.
foo = Foo()
foo.name = foo.bar
If you prefer you can do it in constructor.
Your class should have an attribute to store the name.
Try this out
#!/usr/bin/python
class Foo:
def __init__(self):
self.name = ''
def bar(self, name):
self.name = name
return "name via bar(): %s" % name
f = Foo()
print f.bar("Jackson")
print f.name