I have a python class that has certain values. This class is just a wrapper class that is used as a datacontainer inside another class object.
When I have any variable in python, I can check if it is empty (or for that matter equal to False) by simply doing
my_variable = "something"
if my_variable
>>> True
my_variable = None # or False, or 0 or whatever equals False
if my_variable
>>> False
So far this is all as usual. But I'd like to behave my class exactly the same but only if a certain attribute has a certain value, otherwise it should return True. Is this possible or does python only check if my_variable is bound to something or not?
class Test(object):
def __init__(self, isTrue):
self.isTrue = isTrue
A = Test(True)
B = Test(False)
if A
>>> True
if B
>>> False
Sounds like you are looking for __bool__ (or __nonzero__ for Python 2).
class Test(object):
def __init__(self, isTrue):
self.isTrue = isTrue
def __bool__(self):
return self.isTrue
Related
I often times find myself initializing an attribute in a class to False, But what I really want is for this to represent True or False ONLY after it is actually assigned to reduce bugs in the future. For instance, the attribute isDog I want to assign later in the methods to either True or False, but I hate having to assign the default to "False" since it leaves room for bugs in the future and seems to assume a priori it's not a dog. Is there a best practice or standard for what I could assign this to that won't render in boolean logic (instead, printing an error if used in Boolean logic) so that I don't need to preassign as False?
A good option is to define your variable as None and check if it is defined before using it.
Here an example:
class Animal:
def __init__(self):
self.is_dog: Optional[bool] = None
...
def become_a_dog(self) -> None:
self.is_dog = True
def become_a_cat(self) -> None:
self.is_dog = False
def can_bark(self) -> bool:
if self.is_dog is None:
raise Exception("Animal instance is not yet specified as dog or cat.")
return self.is_dog
I won't say that this is best practice or standard, however you could use the None keyword to achieve this functionality.
Take a look at the code example below
class Pet:
def __init__(self):
self.isDog = None
self.isCat = None
myCat = Pet()
myCat.isCat = True
if myCat.isDog:
print('I have a dog!')
if myCat.isCat:
print('I have a cat!')
if myCat.isDog == None:
print("I haven't decided whether it's a dog yet")
This code will output "I have a cat!", and "I haven't decided whether it's a dog yet"
Here's a workaround using #property
class Foo:
def __init__(self):
self._is_foo = None
#property
def is_foo(self):
assert isinstance(self._is_foo, bool), "ERROR!!!"
return self._is_foo
def set_foo(self, val):
self._is_foo = val
x = Foo()
x.is_foo
# AssertionError: ERROR!!!
x.set_foo(True)
x.is_foo
# True
How to determine if an object is a class method? Isn't it best practice to use isinstance(), and how does one make that work?
class Foo:
class_var = 0
#classmethod
def bar(cls):
cls.class_var += 1
print("class variable value:", cls.class_var)
def wrapper(wrapped: classmethod):
"""
Call the wrapped method.
:param wrapped (classmethod, required)
"""
wrapped()
Foo.bar()
wrapper(Foo.bar)
print("the type is:", type(Foo.bar))
print("instance check success:", isinstance(Foo.bar, classmethod))
Output:
class variable value: 1
class variable value: 2
the type is: <class 'method'>
instance check success: False
Process finished with exit code 0
If you just want to tell class methods apart from regular methods and static methods, then you can check this with inspect.ismethod(f).
class A:
def method(self): pass
#classmethod
def class_method(cls): pass
#staticmethod
def static_method(): pass
In the REPL:
>>> from inspect import ismethod
>>> ismethod(A.method)
False
>>> ismethod(A.class_method)
True
>>> ismethod(A.static_method)
False
If you prefer to do this with isinstance, then that's possible using typing.types.MethodType:
>>> from typing import types
>>> isinstance(A.method, types.MethodType)
False
>>> isinstance(A.class_method, types.MethodType)
True
>>> isinstance(A.static_method, types.MethodType)
False
Note that these tests will incorrectly identify e.g. A().method because really we're just testing for a bound method as opposed to an unbound function. So the above solutions only work assuming that you are checking A.something where A is a class and something is either a regular method, a class method or a static method.
As you know Python fills the first parameter of the classmethods with a reference to the class itself and it doesn't matter if you call that method from the class or the instance of the class. A method object is a function which has an object bound to it.
That object can be retrieved by .__self__ attribute. So you can simply check that if the .__self__ attribute is a class or not. If it is a class , it's class is type.
One way of doing it:
class Foo:
#classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(m):
first_parameter = getattr(m, '__self__', None)
if not first_parameter:
return False
type_ = type(first_parameter)
return type_ is type
print(is_classmethod(Foo.fn1))
print(is_classmethod(Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo.fn2))
print(is_classmethod(Foo().fn2))
output:
True
True
-----------------------------------
False
False
There is a ismethod function in inspect module that specifically checks that if the object is a bound method. You can use this as well before checking for the type of the first parameter.
NOTE: There is a caveat with the above solution, I'll mention it at the end.
Solution number 2:
Your isinstance solution didn't work because classmethod is a descriptor. If you want to get the actual classmethod instance, you should check the Foo's namespace and get the methods from there.
class Foo:
#classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(cls, m):
return isinstance(cls.__dict__[m.__name__], classmethod)
print(is_classmethod(Foo, Foo.fn1))
print(is_classmethod(Foo, Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo, Foo.fn2))
print(is_classmethod(Foo, Foo().fn2))
Solution number 1 caveat: For example if you have a simple MethodType object whose bound object is a different class like int here, this solution isn't going to work. Because remember we just checked that if the first parameter is of type type:
from types import MethodType
class Foo:
def fn2(self):
pass
fn2 = MethodType(fn2, int)
#classmethod
def fn1(cls):
pass
Now only solution number 2 works.
I'm creating a Verdict class which will evaluate to true until it is set false after which it always evaluates false even if you set it to true. The only way I could think of to do that would be to have a property and a setter.
It works, but for simplicity rather than having:
v = Verdict()
v.verdict = ...
v.verdict = ...
v.verdict = ...
I thought I could do:
v = Verdict().verdict
v = ...
v = ...
v = ...
But it seems that v in the second case is the attribute directly, and is ignoring the setter.
class Verdict():
def __init__(self):
self.__verdict = True
#property
def verdict(self):
return self.__verdict
#verdict.setter
def verdict(self, value):
if self.__verdict is True:
self.__verdict = value
def __bool__(self):
return self.__verdict
class A():
v = Verdict().verdict
y = Verdict()
def foo(cls):
cls.y = False
cls.y = True # Uses setter and stays false
cls.v = False
cls.v = True # should use setter and stay false but doesn't
Is there a way to fix this, or a better method to achieve the Verdict?
You can't avoid using the v.verdict = ... syntax.
This is because properties require attribute access in order to work. Properties are descriptors, and the descriptor protocol only takes effect on attribute access.
If you store a property (or, more generally, a descriptor) in a variable, you've effectively robbed it of its functionality. Accessing a variable is just a name lookup, and assigning to a variable is just binding a value to a name. It's not possible to make an assignment like v = ... trigger your setter.
Here is my code:
class a(object):
d='ddd'
def __contains__(self):
if self.d:return True
b=a()
print b.contains('d') # error
print contains(b,'d') # error
Like all special methods (with "magic names" that begin and end in __), __contains__ is not meant to be called directly (except in very specific cases, such as up=calls to the superclass): rather, such methods are called as part of the operation of built-ins and operators. In the case of __contains__, the operator in question is in -- the "containment check" operator.
With your class a as you present it (except for fixing your typo, and using True instead of true!-), and b as its instance, print 'x' in b will print True -- and so will any other containment check on b, since b always returns True (because self.d, a non-empty string, is true).
to get your code to do something (although nothing useful):
class a(object):
d = 'ddd'
def __contains__(self, m):
if self.d:
return True
b = a()
>>> 'd' in b
True
The docs.
__contains__ method defines how instances of class behave when they appear at right side of in and not in operator.
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __contains__(self,param1):
return True if param1 in self.__dict__.keys() else False
>>> p = Person('Robby Krieger',23)
>>> 'name' in p
True
Lets see a very simple example of magic method __contains__ :
Suppose I have class Player and my __init__ method takes one string argument name. In main I have created an object (obj1) of class Player.
Now if I want to know if my obj1 (in this case attribute name of obj1) contains a particular string, substring or an alphabet, I have to implement __contains__ method as shown in the example.
If my class has __contains__ method I can call built-in operator in on my custom objects as shown in the example.
class Player():
def __init__(self, name):
self.name=name
def __contains__(self, substring):
if substring in self.name:
return True
else:
return False
obj1=Player("Sam")
print ('am' in obj1) ----> True
print ('ami' in obj1) ----> False
if self.d:return true
self.d is the string 'ddd'. Non-empty strings are always truthy: when you use if on 'ddd' it will always act as if you'd said if True:.
I think what you probably meant is:
def __contains__(self, item):
return item in self.d
in is the operator that calls the __contains__ method behind the scenes.
How can one check if a variable is an instance method or not? I'm using python 2.5.
Something like this:
class Test:
def method(self):
pass
assert is_instance_method(Test().method)
inspect.ismethod is what you want to find out if you definitely have a method, rather than just something you can call.
import inspect
def foo(): pass
class Test(object):
def method(self): pass
print inspect.ismethod(foo) # False
print inspect.ismethod(Test) # False
print inspect.ismethod(Test.method) # True
print inspect.ismethod(Test().method) # True
print callable(foo) # True
print callable(Test) # True
print callable(Test.method) # True
print callable(Test().method) # True
callable is true if the argument if the argument is a method, a function (including lambdas), an instance with __call__ or a class.
Methods have different properties than functions (like im_class and im_self). So you want
assert inspect.ismethod(Test().method)
If you want to know if it is precisely an instance method use the following function. (It considers methods that are defined on a metaclass and accessed on a class class methods, although they could also be considered instance methods)
import types
def is_instance_method(obj):
"""Checks if an object is a bound method on an instance."""
if not isinstance(obj, types.MethodType):
return False # Not a method
if obj.im_self is None:
return False # Method is not bound
if issubclass(obj.im_class, type) or obj.im_class is types.ClassType:
return False # Method is a classmethod
return True
Usually checking for that is a bad idea. It is more flexible to be able to use any callable() interchangeably with methods.