Calling attributes from classes in Python - python-3.x

I am playing around with classes and I want to do the following:
class Hi (object):
def __init__(self, bloop):
self.bloop = bloop
thing = Hi("bloop")
name = input("Input a thing") # Let`s assume you input thing
print(name.bloop)
What I want it to do is for it to print "bloop" because you entered thing and it gets bloop from thing kinda like thing.bloop.

How about storing thing in a dict:
class Hi:
def __init__(self, bloop):
self.bloop = bloop
things = {'thing': Hi('bloop')}
name = input("Input a thing") # Let`s assume you input 'thing'
try:
print(things[name].bloop)
except KeyError:
print("Sorry, I dont know that thing :(")
There are, of course, other ways to call an attribute of a class. You could implement a __call__() method, which allows you to call the class instance like a function, and in your case return .bloop:
class Hi:
def __init__(self, bloop):
self.bloop = bloop
def __call__(self):
return self.bloop
things = {'thing': Hi('bloop')}
name = input("Input a thing") # Let`s assume you input 'thing'
try:
print(things[name]())
except KeyError:
print("Sorry, I dont know that thing :(")
This way, you can rename your attribute later, or return another attribute (or do something entirely different altogether), without having to replace .bloop in your main python file.
A third way, which directly relates to your question's title calling attributes from[of] classes in Python: you can use the #Property decorator to make your .bloop attribute callable like a function like so:
class Hi:
def __init__(self, bloop):
self.bloop = bloop
#Property
def bloop():
return self.bloop
#bloop.setter
def bloop(self, new_value)
self.bloop = new_value
things = {'thing': Hi('bloop')}
name = input("Input a thing") # Let`s assume you input 'thing'
try:
print(things[name].bloop())
except KeyError:
print("Sorry, I dont know that thing :(")
To fully understand the Property decorator, I recommend this article.
Btw, according to the tags on your question, you're using Python3.x - you don't have to declare that your class inherits from Object in Python3 and later.

Related

AttributeError | How should I call a class method?

My class code in edit (For presentation, not a problem for my question.)
class TxtFile:
"""Responsible for the file.
Creates objects that store the text of a '.txt' file
"""
file_count = 0
#staticmethod
def question():
"""Call question()
"""
print("""If you need:
open '.txt' file for read, use .open_file
write a '.txt' file, use .write_file
append text to '.txt' file, use .append_file""")
#classmethod
def kids(cls):
"""Counts the number of open files.
Variable keeper - file_count
"""
print('I have', cls.file_count, 'file')
def __init__(self):
self.__file_name = None
self.__file_path = None
TxtFile.file_count += 1
#property
def name(self):
if self.__file_name is None:
print('You didn\'t enter a file name.\n')
else:
return self.__file_name
#property
def path(self):
if self.__file_path is None:
print('Path not specified.')
fpath.display_catalog(DATA_PATH)
else:
return self.__file_path
#name.setter
def name(self, name):
if self.__file_name is not None:
print('The file already has the specified name.\n')
else:
if self.__file_path is not None:
fpath.search_file(self.__file_path, name)
else:
print('You did not specify the path to the',
'directory with the file.\n')
#path.setter
def path(self, path):
if self.__file_path is not None:
print('The file already has the specified path.')
else:
self.__file_path = path
def open_file(self, method='read'):
"""Responsible for opening a file.
Takes 3 arguments: read, write, append
Equal: rt, wt, at
"""
if method == 'read':
pass
if method == 'write':
pass
if method == 'append':
pass
The code I want to do:
def display_info(cls):
method_list = [method for method in dir(cls)
if callable(getattr(cls, method))
and method.startswith('__') is False]
for method in method_list:
method_doc = cls.method.__doc__
print(method + ':')
if method_doc is None:
print('This method does not have docstring.')
else:
print('This is the docstring',
method_doc)
display_info(TxtFile)
Error thrown: AttributeError: type object 'TxtFile' has no attribute 'method'
I tried in this way:
method_doc = cls.__dict__[method].__doc__
Output:
This is the docstring classmethod(function) -> method
Convert a function to be a class method.
A class method receives the class as implicit first argument,
just like an instance method receives the instance.
To declare a class method, use this idiom:
class C:
#classmethod
def f(cls, arg1, arg2, ...):
...
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()). The instance is ignored except for its class.
If a class method is called for a derived class, the derived class
object is passed as the implied first argument.
Class methods are different than C++ or Java static methods.
If you want those, see the staticmethod builtin.
open_file:
This is the docstring Responsible for opening a file.
Takes 3 arguments: read, write, append
Equal: rt, wt, at
question:
This is the docstring staticmethod(function) -> method
Convert a function to be a static method.
A static method does not receive an implicit first argument.
To declare a static method, use this idiom:
class C:
#staticmethod
def f(arg1, arg2, ...):
...
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()). Both the class and the instance are ignored, and
neither is passed implicitly as the first argument to the method.
Static methods in Python are similar to those found in Java or C++.
For a more advanced concept, see the classmethod builtin.
I want to have a function that will output dcstring of class methods.
I have been learning Python for less than a month, so my knowledge is limited. In the code, I use what I know. I would like to know the solution and get an answer how it works.

How to instantiate a subclass with two existing superclasses from one of the superclasses objects in Python

My question is a bit more complicated as the question described here.
So assuming we have two Superclasses, how can i istantiate the subclass depending on the superclass i passed?
class ASuperClass:
def __init__(self, tediously, many, attributes):
# assign the attributes like "self.attr = attr"
class BSuperClass:
def __init__(self, tediously, many, attributes):
# assign the attributes like "self.attr = attr"
What i tried is:
class SubClass(ASuperClass, BSuperClass):
def __init__(self, id, a_super_class_instance, b_super_class_instance):
self.id = id
if a_super_class_instance:
ASuperClass().__init__(**a_super_class_instance)
elif:
ASuperClass().__init__(**b_super_class_instance)
else:
raise ValueError("At least one of the superclasses have to be passed.")
However, this did not work. My wish is depending on the input, i get the subclass with the params as output.
s1 = SubClass(id, ASubClass)
s2 = SubClass(id, BSubClass)
Actually its farm simpler than i expected, this is the solution:
class SubClass(ASuperClass, BSuperClass):
def __init__(self, id, asubclass=None, bsubclass=None):
self.id = id
if asubclass:
ASuperClass().__init__(self, **(asubclass.__dict__))
elif bsubclass:
BSuperClass().__init__(self, **(bsubclass.__dict__))
else:
raise ValueError("At least one of the superclasses have to be passed.")
s1 = SubClass(id=0, asubclass=a1)
s2 = SubClass(id=1, bsubclass=b1)

In Python, how to get typing right when using a class decorator?

This is my first attempt to make a Python decorator, and I humbly admit to drawing inspiration from a number of StackOverflow posts while doing so. When I scavenged the __instancecheck__ method, the last two asserts stopped triggering, but now PyCharm's built-in linter isn't happy with the very last assert.
Expected type 'Union[type, Tuple[Union[type, Tuple[Any, ...]], ...]]', got 'Multiton' instead.
What is the root of the typing problem, and how can it be fixed?
Addition, after making the __init__ change recommended by a commenter another warning surfaces.
Local variable 'instance' might be referenced before assignment.
class Multiton(object):
""" When init parameters match, reuse an old initialized object instead of making a new one. """
def __init__(self, cls):
# self.__dict__.update({'instances': list(), 'cls': cls})
self.instances = list()
self.cls = cls
def __call__(self, *args, **kwargs):
# make a key with the parameters
key = (args, kwargs)
# search for a matching old instance
found = False
for instance in self.instances:
if instance['key'] == key:
found = True
break
# if not found then create a new instance
if not found:
instance = {'key': key, 'object': self.cls(*args, **kwargs)}
self.instances.append(instance)
return instance['object']
def __instancecheck__(self, other):
return isinstance(other, self.cls)
#Multiton
class YourClass:
def __init__(self, number):
self.number = number
yc_1 = YourClass(1)
yc_2 = YourClass(2)
yc_two = YourClass(2)
assert yc_1 != yc_2
assert yc_2 == yc_two
assert not isinstance(yc_1, Multiton)
assert isinstance(yc_1, YourClass)
The false warnings are PyCharm bugs which hopefully the fine folks at JetBrains will remedy soon.
https://youtrack.jetbrains.com/issue/PY-38590
https://youtrack.jetbrains.com/issue/PY-49966

Function not Defined in Class

I am having trouble with a coding project in which I am trying to use classes in python to make a card game (cheat). However, when creating the player class, one of the functions that was previously defined within the class is shown as undefined. I cannot figure out the reason, and any suggestion is appreciated. Below is the definition of the classes
class card(object):
def __init__(self,rank,suit):
self.rank = rank
self.suit = suit
class player(object):
def __init__ (self):
self.number = number
self.hand = list()
#Here, hand is a list of the card class that was distributed with a suit and a rank
def check_card(self,player_rank,player_suit):
for card in self.hand:
if card.rank == player_rank and card.suit == player_suit:
return True
break
return False
def play_card(self):
suit = input('what is the suit?')
rank = input('what is the rank?')
if check_card(self,rank,suit):
print(True)
else:
print(False)
Here is the actual code that will run it
player = player()
player.play_card()
The following error was received:
NameError: name 'check_card' is not defined
I have been troubleshooting and looking at different solutions, including moving the functions outside the class, but it continues to display the same error. Can anyone point out the mistake? Thanks!
You have the following two issues in your code
The way you passed self to the check_card function is wrong. You must call it in this way
self.check_card(rank,suit)
The second issue is that the number is not defined. Thus I passed it as an argument while initializing the player. Feel free to make changes for that.
This is the corrected code :
class card(object):
def __init__(self,rank,suit):
self.rank = rank
self.suit = suit
class player(object):
def __init__ (self, number):
self.number = number
self.hand = list()
#Here, hand is a list of the card class that was distributed with a suit and a rank
def check_card(self,player_rank,player_suit):
for card in self.hand:
if card.rank == player_rank and card.suit == player_suit:
return True
break
return False
def play_card(self):
suit = input('what is the suit?')
rank = input('what is the rank?')
if self.check_card(rank,suit):
print(True)
else:
print(False)
player = player(3)
player.play_card()
Output :
what is the suit?spade
what is the rank?3
False
Based on this document the function call in python class is self.xxxx(args) (xxxx is denoted function name)
therefore the correct version of play_card function is shown as following.
enter code here
def play_card(self):
suit = input('what is the suit?')
rank = input('what is the rank?')
if self.check_card(rank,suit):
print(True)
else:
print(False)

Python subclass that takes superclass as argument on instantiation?

I am trying to create a wrapper class in Python with the following behaviour:
It should take as an argument an existing class from which it should inherit all methods and attributes
The wrapper class methods should be able to use Python super() to access methods of the superclass (the one passed as an argument)
Because of my second requirement I think the solution here will not suffice (and in any case I am having separate issues deepcopying some of the methods of the superclass' I am trying to inherit from).
I tried this but it's not correct...
class A:
def shout(self):
print("I AM A!")
class B:
def shout(self):
print("My name is B!")
class wrapper:
def __init__(self, super_class):
## Some inheritance thing here ##
# I initially tried this but no success...
super(super_class).__init__() # or similar?
def shout(self):
print('This is a wrapper')
super().shout()
And this is the behaviour I require...
my_wrapper = wrapper(A)
my_wrapper.shout()
# Expected output:
# > This is a wrapper
# > I AM A
my_wrapper = wrapper(B)
my_wrapper.shout()
# Expected output:
# > This is a wrapper
# > My name is B!
Is inheritance the correct approach here, if so am I sniffing in the right direction? Any help is appreciated, thanks :)
Edit for context:
I intend to build multiple wrappers so that all of my ML models have the same API. Generally, models from the same package (sklearn for example) have the same API and should be able to be wrapped by the same wrapper. In doing this I wish to modify/add functionality to the existing methods in these models whilst keeping the same method name.
If wrapper has to be a class then a composition solution would fit much better here.
Keep in mind that I turned the shout methods to staticmethod because in your example you pass the class to wrapper.shout, not an instance.
class A:
#staticmethod
def shout():
print("I AM A!")
class B:
#staticmethod
def shout():
print("My name is B!")
class wrapper:
def __init__(self, super_class):
self._super_class = super_class
def __getattr__(self, item):
try:
return self.__dict__[item].__func__
except KeyError:
return self._super_class.__dict__[item].__func__
def a_wrapper_method(self):
print('a wrapper attribute can still be used')
my_wrapper = wrapper(A)
my_wrapper.shout()
my_wrapper = wrapper(B)
my_wrapper.shout()
my_wrapper.a_wrapper_method()
Outputs
This is a wrapper
I AM A!
This is a wrapper
My name is B!
a wrapper attribute can still be used
So I went for a function in the end. My final solution:
class A:
def shout(self):
print("I AM A!")
class B:
def shout(self):
print("My name is B!")
def wrap_letter_class(to_wrap):
global letterWrapper
class letterWrapper(to_wrap):
def __init__(self):
super().__init__()
def shout(self):
print('This is a wrapper')
super().shout()
def __getstate__(self):
# Add the wrapper to global scope before pickling
global letterWrapper
letterWrapper = self.__class__
return self.__dict__
return letterWrapper()
Which produces the desired behaviour...
In [2]: wrapped = wrap_letter_class(A)
In [3]: wrapped.shout()
This is a wrapper
I AM A!
In [4]: wrapped = wrap_letter_class(B)
In [5]: wrapped.shout()
This is a wrapper
My name is B!
Something not mentioned in my initial question was that I intended to pickle my custom class, this is not possible if the class is not defined in the global scope, hence the __getstate__ and global additions.
Thanks!

Resources