How to access member function as member variable in python classes? - python

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

Related

Can create a def in python class which can be called what ever the def name even if the def didn't exist

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'

Specify which method to call

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'

Implementing Class.magic_class_method

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

Python: Generic getters and setters

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

How to dynamically access class properties in Python?

Let's say I create an instance of a class and want to assign some values to its public properties. Usually, this would be done like this:
class MyClass:
def __init__(self):
self.name = None
self.text = None
myclass = MyClass()
myclass.name = 'My name'
But, what if a write a function that takes a class as parameter and I would like to assign some values to the public properties of that class dynamically - that is via variables and loops (without knowing how many there are or what they are called.)
The obvious would be:
myclass = MyClass()
myclass['name'] = "My name"
But that doesn't work.
Any ideas?
setattr(my_class_instance, 'attr_name', attr_value)
After reading rejected Syntax For Dynamic Attribute Access I'm using a mixin class providing dictionary-style access to an object's attributes :
class MyClass:
def __init__(self):
self.name = None
self.text = None
def __getitem__(self, name):
return getattr(self, name)
def __setitem__(self, name, value):
return setattr(self, name, value)
def __delitem__(self, name):
return delattr(self, name)
def __contains__(self, name):
return hasattr(self, name)
While still being able to set attributes directly:
myclass = MyClass()
myclass.name = "foo"
myclass.text = "bar"
it's then possible to set them dynamically :
for attr in ('name', 'text'):
myclass[attr] = confirm(attr, default=myclass[attr])
Using dir with setattr should do the job
class MyClass:
def __init__(self):
self.name = None
self.text = None
myclass = MyClass()
myclass.name = 'My name'
for prop in dir(myclass):
print '%s:%s'%(prop,getattr(myclass,prop))
print
for prop in dir(myclass):
if prop[:2]!='__' and prop[-2:]!='__':
print prop[-2:]
setattr(myclass,prop,"Foo Bar")
for prop in dir(myclass):
print '%s:%s'%(prop,getattr(myclass,prop))
But be careful because this code also sets '__doc__', '__init__', '__module__' properties to "Foo Bar". So you will have to take care of avoiding certain things given to you by dir (especially those which start and end with __ double underscores).
I don't know if this solution is a good or bad idea.
But this works for me.
myclass = MyClass()
myclass.__dict__['name'] = "My name"

Categories

Resources