Example:
class Bird:
def __init__(self):
self.sound = "chirp!"
def reproduce_sound(self):
if self:
print(self.sound)
bird = Bird()
bird.reproduce_sound()
What does if self: mean? What is the case where the reproduce_sound function call prints nothing?
It checks the truth value of the instance and only prints if it is True. In your example the check doesn't do anything useful and will always print something. You can override the __bool__ method to change its default behaviour.
For example:
class Bird:
...
def __bool__(self):
return bool(self.sound)
Then:
b = Bird()
b.reproduce_sound() # Prints "chirp!"
b.sound = 0 # or any falsy value, such as None or ""
b.reproduce_sound() # Won't print anything because b == False
Related
I am using Python 3.8.6 and this works fine
class A:
#property
def _a(self):
return getattr(self, '_a_', 0)
#_a.setter
def _a(self, value):
self._a_ = value
a = A()
print(a._a) # prints 0
a._a = 10
print(a._a) # prints 10 as expected
This doesn't work
class A:
#property
def _a(self):
return getattr(self, '__a', 0)
#_a.setter
def _a(self, value):
self.__a = value
a = A()
print(a._a) # prints 0
a._a = 10
print(a._a) # prints 0 again
That's mind blowing! the only difference between the first and second example is that the private attribute is __a instead of _a_
Any idea why? I wasn't able to figure it out
It's due to private name mangling, but it doesn't apply to the contents of string literals like the one you're passing to getattr().
Fortunately the fix is simple:
class A:
#property
def _a(self):
return getattr(self, '_A__a', 0)
#_a.setter
def _a(self, value):
self.__a = value
a = A()
print(a._a) # prints 0
a._a = 10
print(a._a) # prints 10 now
I want to print name as tanya but since self.name = None has been assigned in constructor it is printing None. So how to get tanya printed when the check function gets called:
class A:
def __init__(self):
self.name = None
def price(self):
self.name = "tanya"
def check(self):
print(self.price())
a=A()
a.check()
The constructor isn't the problem
print(self.price()) is going to print None because you are printing the result of the function.
It then sets self.name="tanya" after printing, but you are ignoring it
Instead, I think you want
a=A()
a.price()
print(a.name)
and forget the check function
class A:
def __init__(self):
self.name=None
def price(self):
self.name="tanya"
return self.name
def check(self):
print(self.price())
a=A()
a.check()
You just have to add the return statement in the price function, and you're done!
I've a decorator which takes parameters.
def decorator(abc):
def inner(func):
def wrapper(*args, **kwargs):
print(abc) # prints base class variable
# do something
return True
return wrapper
return inner
I've Child-Parent Classes as follow:-
class ABC():
abc = 1
#decorator(abc)
def func(self):
return True
class DEF(ABC):
abc = 2
obj = DEF()
print(obj.func())
The problem that I'm facing is while passing child class variable to the decorator, it still takes the base class variable.
How do I pass the child class variable to the decorator?
Your decorator is being passed a concrete value at definition time of the base class and its function. There is no attribute access whatsoever and the function does not get magically redefined and redecorated with a new value in the derived class.
It also makes little sense to pass a class attribute to a method decorator in the first place as the method has dynamic access to it via the passed instance anyway. You can do the much simpler:
def decorator(func):
def inner(self, *args, **kwargs):
print(self.__class__.abc) # actually prints the class attribute
# do something
return True
return inner
class ABC(object):
abc = 1
#decorator
def func(self):
return True
>>> a = ABC()
>>> a.func()
1
True
>>> b = DEF()
>>> b.func()
2
True
A simple way would be to considere that what you want to process in the decorator is the run time value of an attribute. Then you just pass the attribute name and use it at run time. That is enough, because a method gets its object as its first parameter:
def decorator(attr):
def inner(func):
def wrapper(*args, **kwargs):
print(getattr(args[0], attr)) # prints current attribute
# do something
return True
return wrapper
return inner
class ABC():
abc = 1
#decorator('abc')
def func(self):
return True
class DEF(ABC):
abc = 2
obj = DEF()
obj.func()
gives as expected:
2
True
One other solution could be to override the method in DEF, since according to DEF.__mro__, since python cannot find the method declared in DEF, it will go to parent class and find it there, passing in ABC's class attribute.
Output of DEF.__mro__:
(__main__.DEF, __main__.ABC, object)
A proposed solution:
class ABC(object):
abc = 1
#decorator(abc)
def func(self):
return True
class DEF(ABC):
abc = 2
#decorator(abc)
def func(self):
return True
I have the following callable:
class SomeClass(object):
def __init__(self, expr, return_status):
self._expr = expr
self._status = return_status
def __call__(self):
if self._expr == self._status:
return True
def __str__(self):
return ("Function: %s\n Return Status: %s\n" %
(self.__class__.__name__, self._status))
The problem I am facing is this that whenever I try to pass an expression like:
some_variable = SomeFunction(SomeClass.some_method,return_status=True)
SomeClass.some_method gets evaluated and gets stored in self._expr as a boolean value.
What I actually want is this expression (SomeClass.some_method) be stored in self._expr and get evaluated each time the __call__(self) method is called.
Am I making sense?
Let's say I am taking the following example:
def addition(c,b):
print "'addition' function called!\n"
sum = c+b
if sum>5:
return True
else:
return False
script_timeout = 3
some_variable = SomeFunction(addition(1,2),return_status=True)
print "some_variable: \n%s" %some_variable
some_class.some_method(some_variable, script_timeout, 1)
This gives me the following output:
'addition' function called!
SomeFunction (_init_) function called!
expr: False
self._expr = False and self._status = True
SomeFunction (_str_) function called!
self.__class__.__name__ = SomeFunction and self._expr = False
monitor:
Function: SomeFunction
Return Status of the Expression: True
SomeFunction (_call_) function called!
self._expr = False and self._status = True
SomeFunction (_call_) function called!
self._expr = False and self._status = True
SomeFunction (_call_) function called!
self._expr = False and self._status = True
So, the concern is the addition function is not getting called with each iteration calling of SomeFunction (by the some_method method.)
The required functionality is this that SomeFunction (when called by some_method) should call the function addition.
Assuming expr will be a method/function and assuming you know what method/function returns, you have 3 options. Follow just one of these 3 options and you'll achieve what you want.
1) You can call expr in the assignement to self.expr:
....
class CheckStatus:
def __init__(self, expr, ...)
self.expr = expr() # expr() being called here, store whatever the result is to self.expr
def __call__(self):
# self.expr already holds a boolean value, or anything your expr returns
if self.expr == self.status:
# self.expr match ...
# do what else you have to do
obj = CheckStatus(SomeClass().method, ...) # pay attention how we pass the method here
2) If self.expr is a reference to that expr, then:
class CheckStatus:
def __init__(self, expr, ...):
self.expr = expr
def __call__(self):
# in this example, self.expr now it's a reference to some method
# thus you need to call self.expr here
if self.expr() == self.status:
....
obj = CheckStatus(SomeClass().method, ...) # pay attention how we pass method for this example
3) call the SomeClass().method() at instantiation of CheckStatus():
class CheckStatus:
def __init__(self, expr, ...):
self.expr = expr # for this example, expr already is a boolean or anything else some method/function returned
def __call__(self):
# don't need to call anything here
if self.expr == self.status:
....
obj = CheckStatus(SomeClass().method(), ...) # because here we called SomeClass().method()
You have to call the method/function your passing in to your CheckStatus class somewhere, otherwise you'll never have that method/function result to check.
Hope it was clear.
class S(object):
def __init__(self, expr, return_status):
self._expr = expr
self._status = return_status
def __call__(self):
if self._expr() == self._status:
raise Exception
self._expr()
def __str__(self):
return ("Function: %s\n Return Status of the Expression: %s\n" %
(self.__class__.__name__, self._status))
def some_method():return True
try:
S(some_method,return_status=True)()
except Exception as e:
print('Got Exception')
Is it possible to make a property assert when it is changed (for the purpose of debugging)?
class MyClass(object):
def set_my_property(self, value):
self.my_property = value
# TODO: mark my_property so that if it gets set again, an assert
# is triggered
c = MyClass()
c.set_my_property(4)
# any of these lines would cause an assertion
c.set_my_property(8)
c.my_property = 123
EDIT:
Is this what you're looking for?
class MyClass(object):
def __init__(self):
self.trigger = False
self._my_property = 0
def set_my_property(self, value):
if self.trigger:
raise Exception("WHOOPS!")
self._my_property = value
# TODO: mark my_property so that if it gets set again, an assert
# is triggered
self.trigger = True
def get_my_property(self):
return self._my_property
my_property = property(get_my_property, set_my_property, None)
c = MyClass()
c.set_my_property(4)
# any of these lines would cause an assertion
c.set_my_property(8)
c.my_property = 123
Add a boolean to check if the value has been set before:
EDIT: But you want a property, so you'll need to create one:
class MyClass(object):
def __init__(self):
self.my_property_set = False
self._my_property = None
def set_my_property(self, value):
self._my_property = value
assert not self.my_property_set,"my_property already set"
self.my_property_set = True
def get_my_property(self):
return self._my_property
my_property = property(get_my_property, set_my_property, None)
c = MyClass()
c.set_my_property(4)
# any of these lines would cause an assertion
c.set_my_property(8)
c.my_property = 123
class Foo:
def __init__(self):
self._bar = None
#property
def bar(self): return self._bar
#bar.setter:
def bar(self, value):
assert value != some_constant # your assert condition
self._bar = value
#bar.deleter:
def bar(self, value):
assert value != some_constant # your assert condition
self._bar = None