Python: Get the class, which a method belongs to - python

Do python class-methods have a method/member themselves, which indicates the class, they belong to?
For example ...:
# a simple global function dummy WITHOUT any class membership
def global_function():
print('global_function')
# a simple method dummy WITH a membership in a class
class Clazz:
def method():
print('Clazz.method')
global_function() # prints "global_function"
Clazz.method() # prints "Clazz.method"
# until here, everything should be clear
# define a simple replacement
def xxx():
print('xxx')
# replaces a certain function OR method with the xxx-function above
def replace_with_xxx(func, clazz = None):
if clazz:
setattr(clazz, func.__name__, xxx)
else:
func.__globals__[func.__name__] = xxx
# make all methods/functions print "xxx"
replace_with_xxx(global_function)
replace_with_xxx(Clazz.method, Clazz)
# works great:
global_function() # prints "xxx"
Clazz.method() # prints "xxx"
# OK, everything fine!
# But I would like to write something like:
replace_with_xxx(Clazz.method)
# instead of
replace_with_xxx(Clazz.method, Clazz)
# note: no second parameter Clazz!
Now my question is: How is it possible, to get all method/function calls print "xxx", WITHOUT the "clazz = None" argument in the replace_with_xxx function???
Is there something possible like:
def replace_with_xxx(func): # before it was: (func, clazz = None)
if func.has_class(): # something possible like this???
setattr(func.get_class(), func.__name__, xxx) # and this ???
else:
func.__globals__[func.__name__] = xxx
Thank you very much for reading. I hope, i could make it a little bit clear, what i want. Have a nice day! :)

I do not think this is possible and as a simple explanation why we should think about following: you can define a function and attach it to the class without any additional declarations and it will be stored as a field of the class. And you can assign the same function as a class method to 2 or more different classes.
So methods shouldn't contain any information about the class.

Clazz.method will have an attribute im_class, which will tell you what the class is.
However, if you find yourself wanting to do this, it probably means you are doing something the hard way. I don't know what you are trying to accomplish but this is a really bad way to do just about anything unless you have no other option.

For methods wrapped in #classmethod, the method will be bound and contain the reference im_self pointing to the class.

Related

How to avoid parameter type in function's name?

I have a function foo that takes a parameter stuff
Stuff can be something in a database and I'd like to create a function that takes a stuff_id, get the stuff from the db, execute foo.
Here's my attempt to solve it:
1/ Create a second function with suffix from_stuff_id
def foo(stuff):
do something
def foo_from_stuff_id(stuff_id):
stuff = get_stuff(stuff_id)
foo(stuff)
2/ Modify the first function
def foo(stuff=None, stuff_id=None):
if stuff_id:
stuff = get_stuff(stuff_id)
do something
I don't like both ways.
What's the most pythonic way to do it ?
Assuming foo is the main component of your application, your first way. Each function should have a different purpose. The moment you combine multiple purposes into a single function, you can easily get lost in long streams of code.
If, however, some other function can also provide stuff, then go with the second.
The only thing I would add is make sure you add docstrings (PEP-257) to each function to explain in words the role of the function. If necessary, you can also add comments to your code.
I'm not a big fan of type overloading in Python, but this is one of the cases where I might go for it if there's really a need:
def foo(stuff):
if isinstance(stuff, int):
stuff = get_stuff(stuff)
...
With type annotations it would look like this:
def foo(stuff: Union[int, Stuff]):
if isinstance(stuff, int):
stuff = get_stuff(stuff)
...
It basically depends on how you've defined all these functions. If you're importing get_stuff from another module the second approach is more Pythonic, because from an OOP perspective you create functions for doing one particular purpose and in this case when you've already defined the get_stuff you don't need to call it within another function.
If get_stuff it's not defined in another module, then it depends on whether you are using classes or not. If you're using a class and you want to use all these modules together you can use a method for either accessing or connecting to the data base and use that method within other methods like foo.
Example:
from some module import get_stuff
MyClass:
def __init__(self, *args, **kwargs):
# ...
self.stuff_id = kwargs['stuff_id']
def foo(self):
stuff = get_stuff(self.stuff_id)
# do stuff
Or if the functionality of foo depends on the existence of stuff you can have a global stuff and simply check for its validation :
MyClass:
def __init__(self, *args, **kwargs):
# ...
_stuff_id = kwargs['stuff_id']
self.stuff = get_stuff(_stuff_id) # can return None
def foo(self):
if self.stuff:
# do stuff
else:
# do other stuff
Or another neat design pattern for such situations might be using a dispatcher function (or method in class) that delegates the execution to different functions based on the state of stuff.
def delegator(stff, stuff_id):
if stuff: # or other condition
foo(stuff)
else:
get_stuff(stuff_id)

Python: mocks in unittests

I have situation similar to:
class BaseClient(object):
def __init__(self, api_key):
self.api_key = api_key
# Doing some staff.
class ConcreteClient(BaseClient):
def get_some_basic_data(self):
# Doing something.
def calculate(self):
# some staff here
self.get_some_basic_data(param)
# some calculations
Then I want to test calculate function using mocking of get_some_basic_data function.
I'm doing something like this:
import unittest
from my_module import ConcreteClient
def my_fake_data(param):
return [{"key1": "val1"}, {"key2": "val2"}]
class ConcreteClientTest(unittest.TestCase):
def setUp(self):
self.client = Mock(ConcreteClient)
def test_calculate(self):
patch.object(ConcreteClient, 'get_some_basic_data',
return_value=my_fake_data).start()
result = self.client.calculate(42)
But it doesn't work as I expect.. As I thought, self.get_some_basic_data(param) returns my list from my_fake_data function, but it looks like it's still an Mock object, which is not expected for me.
What is wrong here?
There are two main problems that you are facing here. The primary issue that is raising the current problem you are experiencing is because of how you are actually mocking. Now, since you are actually patching the object for ConcreteClient, you want to make sure that you are still using the real ConcreteClient but mocking the attributes of the instance that you want to mock when testing. You can actually see this illustration in the documentation. Unfortunately there is no explicit anchor for the exact line, but if you follow this link:
https://docs.python.org/3/library/unittest.mock-examples.html
The section that states:
Where you use patch() to create a mock for you, you can get a
reference to the mock using the “as” form of the with statement:
The code in reference is:
class ProductionClass:
def method(self):
pass
with patch.object(ProductionClass, 'method') as mock_method:
mock_method.return_value = None
real = ProductionClass()
real.method(1, 2, 3)
mock_method.assert_called_with(1, 2, 3)
The critical item to notice here is how the everything is being called. Notice that the real instance of the class is created. In your example, when you are doing this:
self.client = Mock(ConcreteClient)
You are creating a Mock object that is specced on ConcreteClient. So, ultimately this is just a Mock object that holds the attributes for your ConcreteClient. You will not actually be holding the real instance of ConcreteClient.
To solve this problem. simply create a real instance after you patch your object. Also, to make your life easier so you don't have to manually start/stop your patch.object, use the context manager, it will save you a lot of hassle.
Finally, your second problem, is your return_value. Your return_value is actually returning the uncalled my_fake_data function. You actually want the data itself, so it needs to be the return of that function. You could just put the data itself as your return_value.
With these two corrections in mind, your test should now just look like this:
class ConcreteClientTest(unittest.TestCase):
def test_calculate(self):
with patch.object(ConcreteClient, 'get_some_basic_data',
return_value=[{"key1": "val1"}, {"key2": "val2"}]):
concrete_client = ConcreteClient(Mock())
result = concrete_client.calculate()
self.assertEqual(
result,
[{"key1": "val1"}, {"key2": "val2"}]
)
I took the liberty of actually returning the result of get_some_basic_data in calculate just to have something to compare to. I'm not sure what your real code looks like. But, ultimately, the structure of your test in how you should be doing this, is illustrated above.

Calling python dictionary of function from class

I'm relatively new to python and would like to make a class that has a dictionary that corresponds to different methods in the class. I currently have :
class Test:
functions = {"Test1":test1, "Test2":test2}
def test1(self, arg1):
print "test1"
def test2(self, arg1):
print "test2" + arg1
def call_me(self, arg):
self.functions[arg](arg)
Then in my main.py I have the following:
from Test import Test
t = Test()
t.call_me('Test1')
When I call this function I get an error saying name test1 is not defined. Can anyone tell me what I am doing wrong? Any help would be greatly appreciated.
You've got multiple problems here.
First, in this line:
functions = {"Test1":test1, "Test2":test2}
At the time Python executes this line of code, there is nothing called test1 or test2, so you're going to get an immediate NameError. If you want to do things this way, you're going to have define functions after all of the functions have been defined, not before.
Next, on the same line, test1 and test2 at this point are plain-old functions. But you're trying to call them as if they were methods, with the magic self and everything. That isn't going to work. If you understand how methods work, it should be obvious that you can work around this in the call_me method:
def call_me(self, arg): self.functions[arg].__get__(self, type(self))(arg)
(In this case, you can also get away with just explicitly passing self as an extra argument. But make sure you understand why before doing that.)
Finally, you're trying to call call_me with the function test1, instead of the name 'Test1'. Presumably the whole reason you've created this mapping is so that you can use the names (dynamically, as strings), so let's actually use them:
t.call_me('Test1')
Note that if the only reason you can't use getattr is that the runtime names you want to look up aren't the same as the method names you want to define, you can always have a map of strings to strings, and look up the resulting strings with getattr, which avoids all the other problems here. Borrowing from aruisdante's answer, adding in the name lookup and remembering to pass arg:
functions = {"Test1": "test1", "Test2": "test2"}
def call_me(self, arg):
return getattr(self, self.functions[arg])(arg)
You need string quotes around your argument, and the T needs to be capitalized:
t.call_me('Test1')
However, python already has the functionality you're trying to replicate built into it via the getattr method. I.E. you can just do:
def call_me(self, arg):
return getattr(self, arg)()
Note that in this case, the name must be exactly the same as the method name or it will raise an AttributeError, so it would be:
t.call_me('test1')
UPDATE
So now that you've edited your question, it's clear what the problem is:
class Test:
functions = {"Test1":test1, "Test2":test2}
This is defining functions at the static/class scope. At this point, test1 and test2 haven't actually been created yet, and they aren't bound to a class instance (so no way to know what self should be). The 'correct' solution if you wanted to have arbitrary mappings (so getattr doesn't fit the bill) would be to move this inside an __init__():
class Test:
def __init__(self):
self._functions = {"Test1":self.test1, "Test2":self.test2}
def call_me(self, arg):
return self._functions[arg](arg)
In your dict, "Test1" and "Test2" are capitalized, while the corresponding functions are not. Change the dict keys to lowercase and everything should work.

Python executing functions in Classes

I'm struggling a little understanding how to use classes effectively. I have written a program which I hope to count the number of occurrences of a phrase or word in a .txt file.
I'm not quite sure how to call the function properly, any help would be much appreciated.
Thanks.
class WordCounter:
def The_Count(self):
print "Counting words..."
txt_doc = open("file")
for line in txt_doc:
if "word" in txt_doc:
word_freq = word_freq + 1
return word_freq
print "Frequency of word: %s" % word_freq
WordCounter.The_Count
Using classes is a little different than what you have tried to do here. Think of it more in terms of preserving variables and state of objects in code. To accomplish your task, something more like the following would work:
class CountObject(object):
"""Instance of CountObject for measuring file lengths"""
def __init__(self, filename):
self.filename = filename
def getcount(self, word):
count = 0
infile = open(self.filename,'r')
for line in infile.readlines():
x = line.count(word)
count = count + x
return count
mycounter = CountObject('C:\list.txt')
print 'The occcurence of awesome is %s' %(str(mycounter.getcount('in')))
First, just to agree on the names, a function inside a class is called a method of that class.
In your example, your method performs the action of counting occurrences of words, so to make it clearer, you could simply call your method count. Note also that in Python, it is a convention to have method names start with a lower case.
Also, it is good practice to use so called new-style classes which are simply classes that inherits from object.
Finally, in Python, a method needs to have at least one parameter, which is by convention called self and which should be an instance of the class.
So if we apply these changes, we get something like:
class WordCounter(object):
def count(self):
print "Counting words..."
# Rest of your code
# ...
Now that your class has a method, you first need to create an instance of your class before you can call that method on it. So, to create an instance of a class Foo in Python, you simply need to call Foo(). Once you have your instance, you can then call your method. Using your example
# Create an instance of your class and save it in a variable
my_word_counter = WordCounter()
# Call your method on the instance you have just created
my_word_counter.count()
Note that you don't need to pass in an argument for self because the Python interpreter will replace self with the value of word_counter for you, i.e. it calls WordCounter.count(my_word_counter).
A note on OO
Has noted by others, your example is not a great use of classes in Python. OO classes aim at putting together behaviours (instance methods) along with the data they interact with (instance attributes). You example being a simple one, there is no real internal data associated with your class. A good warning could be the fact that you never use self inside your method.
For behaviour that is not tied to some particular data, Python gives you the flexibility to write module-level functions - Java, in opposition, forces you to put absolutely everything inside classes.
As suggested by others too, to make your example more OO, you could pass the filename as a param to __init__ and save it as self.filename. Probably even better would be to have your WordCounter expect a file-like object, so that it is not responsible for opening/closing the file itself. Something like:
class WordCounter(object):
def __init__(self, txt_doc):
self.word_file = txt_doc
def count(self):
print "Counting words..."
for line in self.txt_doc:
# Rest of your code
# ...
with open(filename) as f:
word_counter = WordCounter(f)
word_counter.count()
Finally, if you want more details on classes in Python, a good source of information is always the official documentation.
you have several problems here, the code you posted isn't correct python. class methods should take a reference to self as an argument:
def The_Count(self):
you need to initialize word_freq for the case where there are no words to count:
word_freq = 0
as others have mentioned, you can call your function this way:
counter = WordCounter()
print(counter.The_Count())
It's not really idiomatic python to wrap these kinds of stateless functions in classes, as you might do in Java or something. I would separate this function into a module, and let the calling class handle the file I/O, etc.
To call a method in a class, first you have to create an instance of that class:
c = WordCounter()
Then you call the method on that instance:
c.TheCount()
However, in this case you don't really need classes; this can just be a top-level function. Classes are most useful when you want each object to have its own internal state.
For such a small program, using classes may not be necessary. You could simply define the function and then call it.
However, if you wanted to implement a class design you could use (after class definition):
if __name__ == "__main__":
wc = WordCounter() #create instance
wc.TheCount() #call method
The use of a class design would use better design principles while increasing the readability/flexibility of your code if you wanted to further expand the capabilities of the class later.
In this case, you'd have to change the code to this:
class WordCounter:
def CountWords(self):
# For functions inside classes, the first parameter must always be `self`
# I'm sure there are exceptions to that rule, but none you should worry about
# right now.
print "Counting words..."
txt_doc = open("file")
word_freq = 0
for line in txt_doc:
if "word" in line: # I'm assuming you mean to use 'line' instead of 'txt_doc'
word_freq += 1
# count all the words first before returning it
txt_doc.close() # Always close files after you open them.
# (also, consider learning about the 'with' keyword)
# Either print the frequency
print "Frequency of word: %s" % word_freq
# ...or return it.
return word_freq
...then to call it, you would do....
>>> foo = WordCounter() # create an instance of the class
>>> foo.CountWords() # run the function
As other posters have noted, this is not the most effective uses of classes. It would be better if you made this into a top-level function, and changed it to this:
def CountWords(filename, word):
with open(filename) as txt_doc:
word_freq = 0
for line in txt_doc:
if word in line:
word_freq += 1
return word_freq
...and called it like this:
>>> output = CountWords("file.txt", "cat")
>>> print "Frequency of word: %s" % output
39
It would make a bit more sense to use a class if you had something like the below, where you have a bunch of variables and functions all related to one conceptual 'object':
class FileStatistics:
def init(self, filename):
self.filename = filename
def CountWords(self, word):
pass # Add code here...
def CountNumberOfLetters(self):
pass
def AverageLineLength(self):
pass
# ...etc.

Given a class type how do I create an instance in Python?

Let's say I have this :
class whatever(object):
def __init__(self):
pass
and this function:
def create_object(type_name):
# create an object of type_name
I'd like to be able to call the create_object like this:
inst = create_object(whatever)
and get back an instance of whatever. I think this should be doable without using eval, I'd like to know how to do this. Please notice that I'm NOT using a string as a parameter for create_object.
The most obvious way:
def create_object(type_name):
return type_name()
def create_object(typeobject):
return typeobject()
As you so explicitly say that the arg to create_object is NOT meant to be a string, I assume it's meant to be the type object itself, just like in the create_object(whatever) example you give, in which whatever is indeed the type itself.
If I understand correctly, what you want is:
def create_object(type_name, *args):
# create an object of type_name
return type_name(*args)
inst = create_object(whatever)
I don't really know why you want to do this, but would be interesting to hear from you what are your reasons to need such a construct.
def create_object(type_name):
return type_name()
you can of course skip the function altogether and create the instance of whatever like this:
inst = whatever()

Categories

Resources