Creating properties dynamically that point to an attribute's properties [duplicate] - python

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
I want to make properties from an attribute of my class accessible directly through the instance of the class (without inheriting from it). So basically if I have:
class A:
#property
def foo(self):
print("foo")
#property
def bar(self):
print("bar")
class B:
def __init__(self):
self._a = A()
Instead of doing b._a.bar I want to be able to do b.bar. Based on this answer here, I tried the following in class B:
class B:
def __init__(self):
self._a = A()
attrs = [attr for attr in dir(self._a)
if not callable(self._a.__getattribute__(attr))
and not attr.startswith("__")]
for attr in attrs:
setattr(self.__class__, attr,
property(lambda s: s._a.__getattribute__(attr)))
But when instantiating and testing it out, I get one of those weird python moments:
>>> b = B()
foo
bar
>>> b.foo
bar
>>> b.bar
bar
Why are both 'foo' and 'bar' printed out when creating the instance ?
How does the 'foo' property point to the same getter as 'bar' ?

bar and foo are printed when you create the instance because doing _a.__getattribute__("foo") and _a.foo will both call the property object to get a value.
Both of the attributes you set up in B use lambdas to get the correct property from A. This is a common mistake when calling lambdas. Because the attr value is inherited from the outside scope, it isn't frozen when the lambda is evaluated. Instead, it is simply the same attr reference as the enclosing scope's attr, and changes accordingly. So all of your lambdas will have the same attr value.
You can define a B.__getattr__ method instead. This method is called when ordinary attribute lookup fails.
class B:
def __init__(self):
self._a = A()
def __getattr__(self, name):
return getattr(self._a, name)
b = B()
b.bar # bar
b.foo # foo

Related

Python: looking for a short-hand way to setup setters/getters for lots of variables

I have one class (Bar) embedded inside another class (Foo).
class Foo():
class Bar():
def __init__(self):
self.a = 1
self.b = 2
...
self.z = 26
def __init__(self):
self.bar = Bar()
To access the attributes of class Bar, the user would need to the following:
>>> f = Foo()
>>> f.bar.a
1
How can I setup a short dot notation so that users can use BOTH:
>>> f.bar.a
1
and
>>> f.a
1
In my example, I'm trying to demonstrate that Bar class has a lot of variables. So I don't want to write a getter/setter for each one manually. So I was thinking to use the property() in a for loop like this:
def __init__(self):
self.bar = Bar()
# Allow shorter dot notation
for parm in self.bar.__dict__:
setattr(self, i, getattr(bar, i))
self.i = property(...)
But I'm unsure how to use property in this context without manually writing several setter functions.
Any suggestions on how to allow access to both shorter and longer notations?
That's what the __getattr__hook is ideally suited for:
class Foo:
# ...
def __getattr__(self, name):
return getattr(self.bar, name)
__getattr__ is only called for attributes that are missing; so only attributes that are not already present on instances of Foo() are passed to Foo().__getattr__(). The getattr() function then lets you use the same attribute name on self.bar; if the attribute doesn't exist there either, an AttributeError is thrown, as would be expected.

classinstance.__dict__ returns empty dictionary [duplicate]

This question already has answers here:
What is the difference between class and instance attributes?
(5 answers)
Closed 6 years ago.
When I define a class with variables already assign, instantiate it and use __dict__ to get variables as a dictionary, I get an empty list.
In [5]:
class A(object):
a = 1
b = 2
text = "hello world"
def __init__(self):
pass
def test(self):
pass
x = A()
x.__dict__
Out[5]:
{}
But when I declare variables in __init__ and use __dict__ it returns variables which were assigned after instantiation of class.
In [9]:
class A(object):
a = 1
def __init__(self):
pass
def test(self):
self.b = 2
self.text = "hello world"
x = A()
x.test()
x.__dict__
Out[9]:
{'b': 2, 'text': 'hello world'}
Why is that __dict__ returning only variables declared after instantiation of class
Edit Answer:
When an instance is created like x = A()
x.__dict__ stores all the instance attributes.
A.__dict__ stores the class attributes
Pls try A.__dict__ to get all class attributes,
x = A()
x.__dict__
here you are calling __dict__ method on A's instance. So the variables associated with that instance should be displayed...
self.b, self.text are instance variables which are specific to particular instance only..

callable object as method of a class - Can I get `self` to be the class that owns the method?

In python, a class instance can be used almost like a function, if it has a __call__ method. I want to have a class B that has a method A, where A is the instance of a class with a __call__ method. For comparison, I also define two other methods foo and bar in the "traditional" way (i.e. using def). Here is the code:
class A(object):
def __call__(*args):
print args
def foo(*args):
print args
class B(object):
A = A()
foo = foo
def bar(*args):
print args
When I call any of the methods of B, they are passed a class instance as implicit first argument (which is conventionally called self).
Yet, I was surprised to find that b.A() gets passed an A instance, where I would have expected a B instance.
In [13]: b = B()
In [14]: b.A()
(<__main__.A object at 0xb6251e0c>,)
In [15]: b.foo()
(<__main__.B object at 0xb6251c0c>,)
In [16]: b.bar()
(<__main__.B object at 0xb6251c0c>,)
Is there a way (maybe a functools trick or similar) to bind A() in such a way that b.A() is passed a reference to the b object?
Please note that the example presented above is simplified for the purpose of illustrating my question. I'm not asking for advice on my actual implementation use case, which is different.
Edit: I get the same output, if I define my class B like this:
class B(object):
def __init__(self):
self.A = A()
foo = foo
def bar(*args):
print args
The problem with your code is:
class B(object):
A = A()
class B has a member named A that is an instance of A. When you do B.A(), it calls the method __call__ of that A instance (that is confusingly named A); and since it is an A all the time, and A's method, of course the actual object in args is an A.
What you're after is a descriptor; that is, A should have the magic method __get__; :
class A(object):
def __get__(self, cls, instance):
print(cls, instance)
return self
class B(object):
a = A()
b = B()
c = b.a
Now when b.a is executed, __get__ method gets B and b as the cls and instance arguments, and whatever it returns is the value from the attribute lookup (the value that is stored in c) - it could return another instance, or even a function, or throw an AttributeError - up to you. To have another function that knows the B and b; you can do:
class A(object):
def __get__(self, cls, instance):
if instance is not None:
def wrapper():
print("I was called with", cls, "and", instance)
return wrapper
return self
class B(object):
a = A()
B.a()
The code outputs:
I was called with <__main__.B object at 0x7f5d52a7b8> and <class '__main__.B'>
Task accomplished.

How to check if a function exist (but not inherited) in python?

Kind of related to this question:
https://stackoverflow.com/questions/8708525/how-to-check-if-mako-function-exist
I want to check if a function exists for a given class, but not inherited, so that the parent can called the child's function, since otherwise it would result in an infinite recursion..
edit:
it actually gives a maximum stack level error, which is the same.
the equivalent code would be:
class A(object):
def f(x):
b = B()
b.f()
class B(A):
pass
a = A()
a.f()
i understand this is not clean or preferred, but it is what the template translates to, and I dunno how to check for it otherwise.
I want to check if a function exists for a given class, but not inherited
Yes, you can check the class dictionary directly. Either use the __dict__ attribute or the built-in vars() function::
>>> class A(object):
def f(x):
pass
>>> class B(A):
def g(x):
pass
>>> 'f' in vars(B)
False
>>> 'g' in vars(B)
True
If what you need is to check whether the method is defined directly in instance's class and not in one of its ancestors then you can try this:
import inspect
def has_method(obj, name):
v = vars(obj.__class__)
# check if name is defined in obj's class and that name is a method
return name in v and inspect.isroutine(v[name])
class A:
def foo(self):
print 'foo'
class B(A):
pass
b = B()
a = A()
print has_method(a, 'foo') # => True
print has_method(b, 'foo') # => False

foo and _foo - about variables inside a class

class ClassName(object):
"""
"""
def __init__(self, foo, bar):
"""
"""
self.foo = foo # read-write property
self.bar = bar # simple attribute
def _set_foo(self, value):
self._foo = value
def _get_foo(self):
return self._foo
foo = property(_get_foo, _set_foo)
a = ClassName(1,2)
#a._set_foo(3)
print a._get_foo()
When I print a._get_foo() the function _get_foo prints the variable self._foo .
But where does it come from?
self._foo and self.foo are different, aren't they?
EDIT: The problem is that I still not understand what property does. Give me some time.
Docs for property explain how it's supposed to be used. There is no difference between these lines:
self.foo = foo # read-write property
and
a.foo = 3
You're also not supposed to call setters and getters manually.
eta: if you don't understand what property does after looking at the examples provided in the docs and reading our answers, you perhaps should just abstain from using it. It really is not the most essential of Python's features. You might want to start with a simpler example, which is easy to understand:
>>> class ClassName(object):
def __init__(self, foo):
self.foo = foo
>>> a = ClassName(1, 2)
>>> a.foo
1
>>> a.foo = 42
>>> a.foo
42
I really recommend this site:
http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
A good explanation of the property-function.
You define foo to be a property with getters and setters.
Those getters and setters use the variable self._foo, since you coded it that way:
def _set_foo(self, value):
self._foo = value
In your case you would get a problem if you had a slightly different implementation:
class ClassName(object):
"""
"""
def __init__(self,):
"""
"""
pass
def _set_foo(self, value):
self._foo = value
def _get_foo(self):
return self._foo
foo = property(_get_foo, _set_foo)
a = ClassName()
print a.foo
-> AttributeError
b = ClassName()
b.foo = 1 # implicitely sets self._foo !
print b.foo
>> OK, this is 1
As it happens you indeed should set self.foo in the __init__ since the setter creates self._foo. (Or initialize self._foo in the __init__ directly of course).
So, where do self.foo and self._foo come from? It's explicit in the code. self.foo is a property, and self._foo is the variable in which you decided to keep the value of that property.
self._foo and self.foo would be different except that you have assigned the property you created to the name foo: foo = property(_get_foo, _set_foo).
So now you have two names defined foo which is property that is defined in terms of the methods _set_foo and _get_foo. You also have a name _foo defined but this is the same attribute used in _set_foo and _get_foo and therefore in property foo.
So you two names but only one object.
foo
/\
/ \
_set_foo _get_foo
\ /
\ /
_foo --> object
Note: For the example you have Python this is overkill, there is no need to use getter and setter methods unless they are going to have business logic in them. Just use an attribute named foo, you can always wrap that in a property in future without affecting client code if it turns out that you need some smarts around the access of the attribute.
Change your code to:
class ClassName(object):
def __init__(self, foo, bar):
self.foo = foo # read-write property
self.bar = bar # simple attribute
Both foo and bar are read write, if you need finer control you can then consider using a property.
According to your code, it "comes from" _set_foo. In your init, when you do self.foo = foo, that calls _set_foo(1), which performs self._foo = 1.
You can see this more clearly if you add a print statement inside _set_foo().

Categories