Python generic type wrapper - python

I am assuming this question has been asked a million times already but I can't seem to make sense of a few things so please bear with me here. I am trying to make do generic inheritance in Python. This is what I want to accomplish: I have a method that takes in a generic type and it returns a class that has been inherited from that parent class
this is what the code looks like
def make_foo(parent):
class Relationship(parent):
# def __init__(self):
#staticmethod
def should_see_this_method(self):
print("Hello here")
return True
return Relationship
Now this is the piece of code I am have
NewType = make_relationship(str)
another_test: NewType = "Hello"
another_test.should_see_this_method()
another_test.capitalize()
Now I am getting AttributeError: 'str' object has no attribute 'should_see_this_method'
I am not sure if this is anti pattern or not but I am just curios to know how I can do this.
thanks

This line:
another_test: NewType = "Hello"
doesn't do what you think it does.
This is a type hint. Hints are used by static type checkers, linters, and the like to check if your code has obvious bugs or is being used incorrectly. It helps you at "compile time" to catch things that are possible sources of errors, but it has no impact on the runtime behavior of the code.
Importantly, it does not construct an object of type NewType. It constructs a str. You can see this easily by calling type(another_test), which indicates this is a str. (It's also in the message of the AttributeError in your question.)
To actually construct that object, you have to do the usual thing:
>>> another_test = NewType("Hello")
>>> isinstance(another_test, NewType)
True
An unrelated problem in your code: staticmethods should not take self as the first argument. They are not bound to any instance. You'll see an error once you actually get to the line which calls the method.

Related

Can Instance Attributes Call Instance Class Methods in Python?

Python noob here, trying to work more with classes and have broken my code down into a more simple example of what I am working with:
Lets say I have a class, with an instance and an attribute associated with that instance
class Foo(object):
def __init__(self, attribute=None):
self.attribute = attribute
def dosomething(self):
print('I did a thing!')
a = Foo()
a.attribute='bar'
Now, running the method from the instance 'a' works as expected
a.dosomething()
Out:
I did a thing!
However, trying to call the method from an attribute of 'a' results in error
a.attribute='bar'
a.attribute.dosomething()
AttributeError: 'str' object has no attribute 'dosomething'
This results in an attribute error, which is expected. 'a.attribute' is no longer a class type of 'Foo' but rather a class type of 'str'. My question is, can I do something inside the class to allow the attribute to use the class methods?
Furthermore, since I have not found any results for this during my interwebs searches, Im assuming that it likely is not recommended and probably not pythonic? (just a guess). I am open to suggestions on how to make this better, but ideally, I would like to keep the attribute the way it is while still being able to call the class methods. The dot syntax of attributes for classes really helps me keep things organized, but it is useless to me if it cannot call the methods in the class from which it originates.
Thanks in advance!
No, this doesn't work. And it really doesn't make sense if you understand how classes work.
That a.attribute is just a name for the string 'bar'. That string doesn't know anything about a, and shouldn't.1 There could be plenty of other names for the same string. For example:
>>> bar = 'bar'
>>> a.attribute = bar
>>> bar.dosomething()
AttributeError: 'str' object has no attribute 'dosomething'
That's exactly what you'd expect, right? But…
>>> a.attribute is bar
True
Since bar is the same object as a.attribute, it clearly has to do the same thing:
>>> a.attribute.dosomething()
AttributeError: 'str' object has no attribute 'dosomething'
1. There are some special cases where something like this would be useful, but they're solved by having the attribute not just be a string, but instead be some kind of smart object that works kind of like a string but also knows its class, instance, or parent. See the enum module in the stdlib for an example—and click on the source code link to see how it's implemented.
In this example the attribute is is a string when you execute a.attribute='bar' so if you were to do type(a.attribute) it would return string. So Python is looking for the attribute dosomething() in the str class and not finding it.
What you seem to be trying to do doesn't really make sense. At a guess, it seems like you've mixed up some concepts related to inheritance with your understanding of python's dot syntax for member reference, when these have nothing to do with each other.
You wrote
'a.attribute' is no longer a class type of 'Foo' but rather a class type of 'str'.
and this indicates a fundamental misunderstanding of what is going on. No state has changed – a is still the instance a, of type Foo. It has a member attribute, which is a string. The expression a.attribute is merely pointing to that string. If you need to call a method on a, you can still do so anywhere you were trying to call it on a.attribute:
>>> a.attribute = 'bar'
>>> a.doSomething()
I did a thing!
The common scenario in which an object of one type invokes a method that is not defined in its class is inheritance:
class Foo(object):
def superclass_method(self):
print "Hi"
class Bar(Foo):
pass
b = Bar()
b.superclass_method() # prints "Hi"
In this case, we say that b, an instance of Bar, is a Foo as well. Therefore any method that Foo defines, a Bar instance has access to.
If you tell us a bit more about what you're trying to accomplish, I can be more specific about whether and how you should be using inheritance. But the dot notation is just a way to talk about values attached to objects. It's literally just looking in the left object's dictionary for a value associated with the name on the right – foo.bar is equivalent to getattr(foo, 'bar').

What is dynamic dispatch and duck typing?

When using Pycharm, It often points out an error, saying:
Unresolved reference 'name'. This inspection detects names that should
resolve but don't. Due to dynamic dispatch and duck typing, this is
possible in a limited but useful number of cases. Top-level and
class-level items are supported better than instance items.
I've snooped around about this, but most questions and information I find is about preventing the message from being shown. what I want to know is:
What is dynamic dispatch/duck typing?
What are (or an example of) these "useful number of cases"?
Python uses a duck typing convention. This means that you do not have to specify what type a name is. Unlike in Java, for example, where you must specify explicitly that variable may be type int or Object. Essentially, type checking is done at runtime.
"If it walks like a duck and it quacks like a duck, then it must be a duck."
In Python everything will seem to work until you use try to manipulate an object in a way that it is not designed to. Basically, an object may not have a certain method or attribute that another might, and you won't find this out until Python throws an error upon trying it.
Dynamic Dispatch is the practice of the compiler or environment choosing which version of a polymorphic function to use at runtime. If you have multiple implementations of a method, you can use them in different ways despite the methods having the same or similar properties/attributes. Here's an example:
class Foo:
def flush():
pass
class Bar:
def flush():
pass
Both classes have a flush() method but the correct name is chosen at runtime.
Python is not the best example of this process since methods can take multiple parameters and don't have to be reimplemented. Java is a better example, but I'm not fluent enough in it to provide a correct example.
The warning means that you're using a variable that PyCharm doesn't recognise, but due to Python's dynamic nature it can't be sure if it's right or you're right.
For example you may have the following code:
class myClass():
def myfunc(self):
print(self.name)
PyCharm will probably complain that self.name can't be resolved. However, you may use the class like this:
my_class = myClass()
my_class.name = "Alastair"
my_class.myfunc()
which is perfectly valid (albeit brittle).
The message goes on to say that it's more confident about attribute and methods that are less ambiguous. For example:
class myClass():
my_instance_var = "Al"
def myfunc(self):
print(self.my_instance_var)
As my_instance_var is defined in the source code (a class attribute), PyCharm can be confident it exists.
(Don't use class attributes unless you know what you're doing!)

PyCharm: List all usages of all methods of a class

I'm aware that I can use 'Find Usages' to find what's calling a method in a class.
Is there a way of doing this for all methods on a given class? (or indeed all methods in file)
Use Case: I'm trying to refactor a god class, that should almost certainly be several classes. It would be nice to be able to see what subset of god class methods, the classes that interact with it use. It seems like PyCharm has done the hard bit of this, but doesn't let me scale it up.
I'm using PyCharm 2016.1.2
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206666319-See-all-callers-of-all-methods-of-a-class
This is possible, but you have to deal with abstraction, otherwise Pycharm doesn't know the method in question belongs to your specific class. AKA - Type Hinting
Any instance of that method being called in an abstraction layer which does not have type hinting will not be found.
Example:
#The class which has the method you're searching for.
class Inst(object):
def mymethod(self):
return
#not the class your looking for, but it too has a method of the same name.
class SomethingElse(object):
def mymethod(self):
return
#Option 1 -- Assert hinting
def foo(inst):
assert isinstance(inst, Inst)
inst.mymethod()
#Option 2 -- docstring hinting
def bar(inst):
"""
:param inst:
:type inst: Inst
:return:
:rtype:
"""
inst.mymethod()
Nowadays it would be rather easy for Pycharm to use Python 3.6 type hints and match function calls "correctly", as type hints are part of Python 3.5/3.6 language. Of course partial type hints in a big software cause some compromises when resolving the targets of the method calls.
Here is an example, how type hints makes it very easy to do type inferencing logic and resolve the correct target of the call.
def an_example():
a: SoftagramAnalysisAction = SoftagramAnalysisAction(
analysis_context=analysis_context,
preprocessors=list(preprocessors),
analyzers=list(analyzers),
analysis_control_params=analysis_control_params)
output = a.run()
In above example, local variable a is specially marked to have type SoftagramAnalysisAction which makes it clear that run() call below targets to the run method of that class (or any of its possible subclasses).
The current version (2018.1) does not resolve these kind of calls correctly but I hope that will change in the future.

Python: Attribute Error When Passing Method as Function Argument

I was sure that there'd be an answer to this question somewhere on stack overflow, but I haven't been able to find one; most of them are in regards to passing functions, and not methods, as arguments to functions.
I'm currently working with Python 2.7.5 and I'm trying to define a function like this:
def func(object, method):
object.method()
that when called like so:
some_object_instance = SomeObject()
func(some_object_instance, SomeObject.some_object_method)
using a class defined like this:
class SomeObject:
def some_object_method(self):
# do something
is basically equivalent to doing this:
some_object_instance.some_object_method()
I, however, keep getting an attribute error--something along the lines of
'SomeObject' has no attribute 'method'
I was under the impression that I could legally pass methods as arguments and have them evaluate correctly when used in the aforementioned manner. What am I missing?
That's not the way method calling works. The foo.bar syntax looks for a method named bar on the foo object. If you already have the method, just call it:
def func(object, method):
method(object)
func(some_object_instance, SomeObject.some_object_method)
SomeObject.some_object_method is what's called an "unbound method": it's a method object without a self bound into it, so you have to explicitly pass the self to it.
This might make more sense with a concrete example:
>>> s = 'ABC'
>>> s_lower = s.lower # bound method
>>> s_lower()
'abc'
>>> str_lower = str.lower # unbound method
>>> str_lower(s)
'abc'
By comparison, some_object_instance.some_object_method is a "bound method", you can just call it as-is, and some_object_instance is already "bound in" as the self argument:
def func2(method):
method()
func2(some_object_instance.some_object_method)
Unbound methods aren't explained in detail the tutorial; they're covered in the section on bound methods. So you have to go to the reference manual for documentation (in [standard type hierarchy] (https://docs.python.org/2/reference/datamodel.html#the-standard-type-hierarchy), way down in the subsection "User-defined methods"), which can be a little bit daunting for novices.
Personally, I didn't really get this until I learned how it worked under the covers. About a year ago, I wrote a blog post How methods work to try to explain it to someone else (but in Python 3.x terms, which is slightly different); it may help. To really get it, you have to get through the Descriptor HOWTO, which may take a few read-throughs and a lot of playing around in the interactive interpreter before it really clicks, but hopefully you can understand the basic concepts behind methods before getting to that point.
Since you are passing an unbound method to the function, you need to call it as:
method(object)
Or better pass the name of the method as string and then use getattr:
getattr(object, method)()

Using globals() to create class object

I'm new in programming so please don't kill me for asking stupid questions.
I've been trying to understand all that class business in Python and I got to the point where could not find answer for my question just by google it.
In my program I need to call a class from within other class based on string returned by function. I found two solutions: one by using getattr() and second one by using globals() / locals().
Decided to go for second solution and got it working but I'm really don't understand how it's working.
So there is the code example:
class Test(object):
def __init__(self):
print "WORKS!"
room = globals()['Test']
room()
type(room()) gives:
<class '__main__.Test'>
type(room) gives:
<type 'type'> # What????
It looks like room() is a class object, but shouldn't that be room instead of room()?
Please help me because it is a little bit silly if I write a code which I don't understand myself.
What happens here is the following:
class Test(object):
def __init__(self):
print "WORKS!"
room = globals()['Test']
Here you got Test as room the way you wanted. Verify this:
room is Test
should give True.
type(room()) gives:
<class '__main__.Test'>
You do one step an go it backwards: room() returns the same as Test() would - an instance of that class. type() "undoes" this step resp. gets the type of the object - this is, of course, Test.
type(room) gives:
<type 'type'> # What????
Of course - it is the type of a (new style) class. The same as type(Test).
Be aware, however, that for
In my program I need to call a class from within other class based on string returned by function. I found two solutions: one by using getattr() and second one by using globals() / locals().
it could be better to create an explicitly separate dict. Here you have full control over which objects/classes/... are allowed in that context and which are not.
First of all, I'd go with getattr instead.
In your example, room equals Test and is a class. Its type is type.
When you call room(), you instantiate Test, so room() evaluates to an instance of Test, whose type is Test.
Classes are objects too, in Python. All this does:
class Test(object):
def __init__(self):
print "WORKS!"
is create a class object and bind it to the name Test. Much as this:
x = []
creates a list object and binds it to the name x.
Test() isn't magic syntax for creating an instance. The Test is perfectly ordinary variable lookup, and the () is perfectly ordinary "call with empty arguments". It just so happens that calling a class will create an instance of that class.
If follows then that your problem of instantiating a class chosen based on having the name of the class as a string boils down to the much simpler problem of finding an object stored in a variable. It's exactly the same problem as getting that list bound to the name x, given the string "x". Once you've got a reference to the class in any old variable, you can simply call it to create your instance.
globals() returns a dictionary mapping the names of globals to their values. So globals()['Test'] will get you the class Test just as easily as globals()['x'] will get you the list. However it's usually not considered great style to use globals() like this; your module probably contains a large number of callables (including a bunch imported from other modules) that you don't want to be accidentally invoked if the function can be made to return their name. Given that classes are just ordinary objects, you can put them in a dictionary of your own making:
classes = {
'Test': Test,
'SomethingElse': Something,
...
}
This involves a bit more typing, but it's also easier to see what the intended usage is, and it gives you a bit more flexibility, since you can also easily pass this dictionary to other modules and have the instantiation take place elsewhere (you could do that with globals(), but then you're getting very weird).
Now, for the type(room) being type. Again, this is just a simple consequence of the fact that classes themselves are also objects. If a class is an object, then it should also be an instance of some class. What class is that? type, the "type of types". Much as any class defines the common behaviour of all its instances, the class type defines the common behaviour of all classes.
And just to make your brain hurt, type is an instance of itself (since type is also a class, and type is the class of classes). And it's a subclass of object (since all type instances are object instances, but not all object instances are type instances), and also an instance of object (since object is the root class of which everything is an instance).
You can generally ignore type as an advanced topic, however. :)

Categories