Python automatic class assignment - python

In python. when I write x = 5, x becomes an instance of int automatically. But suppose I have defined a new class say number and I want x to become an instance of number instead of int when I assign it the value 5. Is this possible?
ie, Instead of this -->
>>> x = 5
>>> type(x)
<type 'int'>
Is this possible:
>>> x = 5
>>> type(x)
<type 'number'>

No. You would have to write a monkey patch to achieve this, that is incredibly unpythonic, can you simply not write
x = number(5)
:)

Note that you really should never do something like this. Jakob has the right answer, i.e. use x = number(5).
However, that said, I wanted to try how it could be done in theory, and here's one solution in the form of a decorator:
import types
class number(object):
def __init__(self, value):
self.value = value
def replace_int(x):
if isinstance(x, int):
return number(x)
else:
return x
def custom_numbers(f):
code = f.func_code
consts = tuple(map(replace_int, code.co_consts))
new_code = types.CodeType(code.co_argcount, code.co_nlocals,
code.co_stacksize, code.co_flags,
code.co_code, consts, code.co_names,
code.co_varnames, code.co_filename,
code.co_name, code.co_firstlineno,
code.co_lnotab)
return types.FunctionType(new_code, f.func_globals, f.func_name)
Any function you decorate, will end up using your custom number class:
#custom_numbers
def test():
x = 5
print type(x)
>>> test()
<class '__main__.number'>
The decorator works by replacing integer constants from the function's code-object with instances of the custom class. However, since function.co_code and code.co_consts are both read-only attributes, we have to create new code and function objects with the altered values.
One caveat is, that the values are assumed to be constants, so new instances are not created for each invocation of the function. If you mutate the value, that new value will be reflected in each subsequent call of the function.

You would have to take advantage of Python's language services to compile the statement and then walk the AST replacing the objects as appropriate.

In fact, 5 is an instance of int, x is just pointing to it. All variables in Python are references to objects. Thus, when you write type(x) you get the type of the object which x holds a reference to, in this case it is int.
If you assign another value to x, say x = "string", x will hold a reference to that string object, and type(x) will return <type 'str'>.

Related

How can I convert object attributes in mutable in Python? [duplicate]

How can I pass an integer by reference in Python?
I want to modify the value of a variable that I am passing to the function. I have read that everything in Python is pass by value, but there has to be an easy trick. For example, in Java you could pass the reference types of Integer, Long, etc.
How can I pass an integer into a function by reference?
What are the best practices?
It doesn't quite work that way in Python. Python passes references to objects. Inside your function you have an object -- You're free to mutate that object (if possible). However, integers are immutable. One workaround is to pass the integer in a container which can be mutated:
def change(x):
x[0] = 3
x = [1]
change(x)
print x
This is ugly/clumsy at best, but you're not going to do any better in Python. The reason is because in Python, assignment (=) takes whatever object is the result of the right hand side and binds it to whatever is on the left hand side *(or passes it to the appropriate function).
Understanding this, we can see why there is no way to change the value of an immutable object inside a function -- you can't change any of its attributes because it's immutable, and you can't just assign the "variable" a new value because then you're actually creating a new object (which is distinct from the old one) and giving it the name that the old object had in the local namespace.
Usually the workaround is to simply return the object that you want:
def multiply_by_2(x):
return 2*x
x = 1
x = multiply_by_2(x)
*In the first example case above, 3 actually gets passed to x.__setitem__.
Most cases where you would need to pass by reference are where you need to return more than one value back to the caller. A "best practice" is to use multiple return values, which is much easier to do in Python than in languages like Java.
Here's a simple example:
def RectToPolar(x, y):
r = (x ** 2 + y ** 2) ** 0.5
theta = math.atan2(y, x)
return r, theta # return 2 things at once
r, theta = RectToPolar(3, 4) # assign 2 things at once
Not exactly passing a value directly, but using it as if it was passed.
x = 7
def my_method():
nonlocal x
x += 1
my_method()
print(x) # 8
Caveats:
nonlocal was introduced in python 3
If the enclosing scope is the global one, use global instead of nonlocal.
Maybe it's not pythonic way, but you can do this
import ctypes
def incr(a):
a += 1
x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
Really, the best practice is to step back and ask whether you really need to do this. Why do you want to modify the value of a variable that you're passing in to the function?
If you need to do it for a quick hack, the quickest way is to pass a list holding the integer, and stick a [0] around every use of it, as mgilson's answer demonstrates.
If you need to do it for something more significant, write a class that has an int as an attribute, so you can just set it. Of course this forces you to come up with a good name for the class, and for the attribute—if you can't think of anything, go back and read the sentence again a few times, and then use the list.
More generally, if you're trying to port some Java idiom directly to Python, you're doing it wrong. Even when there is something directly corresponding (as with static/#staticmethod), you still don't want to use it in most Python programs just because you'd use it in Java.
Maybe slightly more self-documenting than the list-of-length-1 trick is the old empty type trick:
def inc_i(v):
v.i += 1
x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
A numpy single-element array is mutable and yet for most purposes, it can be evaluated as if it was a numerical python variable. Therefore, it's a more convenient by-reference number container than a single-element list.
import numpy as np
def triple_var_by_ref(x):
x[0]=x[0]*3
a=np.array([2])
triple_var_by_ref(a)
print(a+1)
output:
7
The correct answer, is to use a class and put the value inside the class, this lets you pass by reference exactly as you desire.
class Thing:
def __init__(self,a):
self.a = a
def dosomething(ref)
ref.a += 1
t = Thing(3)
dosomething(t)
print("T is now",t.a)
In Python, every value is a reference (a pointer to an object), just like non-primitives in Java. Also, like Java, Python only has pass by value. So, semantically, they are pretty much the same.
Since you mention Java in your question, I would like to see how you achieve what you want in Java. If you can show it in Java, I can show you how to do it exactly equivalently in Python.
class PassByReference:
def Change(self, var):
self.a = var
print(self.a)
s=PassByReference()
s.Change(5)
class Obj:
def __init__(self,a):
self.value = a
def sum(self, a):
self.value += a
a = Obj(1)
b = a
a.sum(1)
print(a.value, b.value)// 2 2
In Python, everything is passed by value, but if you want to modify some state, you can change the value of an integer inside a list or object that's passed to a method.
integers are immutable in python and once they are created we cannot change their value by using assignment operator to a variable we are making it to point to some other address not the previous address.
In python a function can return multiple values we can make use of it:
def swap(a,b):
return b,a
a,b=22,55
a,b=swap(a,b)
print(a,b)
To change the reference a variable is pointing to we can wrap immutable data types(int, long, float, complex, str, bytes, truple, frozenset) inside of mutable data types (bytearray, list, set, dict).
#var is an instance of dictionary type
def change(var,key,new_value):
var[key]=new_value
var =dict()
var['a']=33
change(var,'a',2625)
print(var['a'])

When to use type() instead of isinstanceof() in python? [duplicate]

This question already has answers here:
What are the differences between type() and isinstance()?
(8 answers)
Closed 2 years ago.
From what I read googling, it seems that isinstanceof() is always better than type().
What are some situations when using type() is better than isinstanceof() in python?
I am using python 3.7.
They do two different things, you can't really compare them directly. What you've probably read is that you should prefer isinstance when checking the type of an object at runtime. But that isn't the only use-case for type (that is the use-case for isinstance, as its name implies).
What may not be obvious is that type is a class. You can think of "type" and "class" as synonymous. Indeed, it is the class of class objects, a metaclass. But it is a class just like int, float, list, dict etc. Or just like a use-defined class, class Foo: pass.
In its single argument form, it returns the class of whatever object you pass in. This is the form that can be used for type-checking. It is essentially equivalent to some_object.__class__.
>>> "a string".__class__
<class 'str'>
>>> type("a string")
<class 'str'>
Note:
>>> type(type) is type
True
You might also find this form useful if you ever wanted access to the type of an object itself for other reasons.
In its three-argument form, type(name, bases, namespace) it returns a new type object, a new class. Just like any other type constructor, just like list() returns a new list.
So instead of:
class Foo:
bar = 42
def __init__(self, val):
self.val = val
You could write:
def _foo_init(self, val):
self.val = val
Foo = type('Foo', (object,), {'bar':42, '__init__': _foo_init})
isinstance is a function which checks if... an object is an instance of some type. It is a function used for introspection.
When you want to introspect on the type of an object, usually you will probably use isintance(some_object, SomeType), but you might also use type(some_object) is SomeType. The key difference is that isinstance will return True if some_object.__class__ is precisely SomeType or any of the other types SomeType inherits from (i.e. in the method resolution order of SomeType, SomeType.mro()).
So, isinstance(some_object, SomeType) is essentially equivalent to some_object.__class__ is SomeType or some_object.__class__ in SomeType.mro()
Whereas if you use type(some_object) is SomeType, you are only asking some_object.__class__ is SomeType.
Here's a practical example of when you might want to use type instead of isinstance, suppose you wanted to distinguish between int and bool objects. In Python, bool inherits from int, so:
>>> issubclass(bool, int)
True
So that means:
>>> some_boolean = True
>>> isinstance(some_boolean, int)
True
but
>>> type(some_boolean) is int
False
type says the type of variable:
a = 10
type(a)
It will give its type as 'int'
isinstance() says if variable is related to specified type
class b:
def __init__(self):
print('Hi')
c = b()
m = isinstance(c, b)
It will return True because object c is of class type a otherwise it will return False.

Can a Python class differentiate input types?

For example in a Python class can I have two different add methods that can detect whether I am adding an object to an integer, or an object to another object, or an object and a string, etc?
Take a look at the multipledispatch module.
Here is a rough but simple example of its use. You can see that it can dispatch to different methods depending on the argument types. It can also handle different numbers of arguments.
from multipledispatch import dispatch
class Adder(object):
#dispatch(object, int)
def add(o, i):
print 'add(object, int):'
return int(o) + i
#dispatch(object, basestring)
def add(o, s):
print 'add(object, string):'
return str(o) + s
#dispatch(int, int)
def pow(a, b):
print 'pow(int, int):'
return a**b
#dispatch(int, int, int)
def pow(a, b, c):
print 'pow(int, int, int):'
return a**b**c
>>> a = Adder()
>>> a.add(1, ' one')
add(object, string):
'1 one'
>>> a.add(100, 1)
add(object, int):
101
>>> a.pow(2, 2)
pow(int, int):
4
>>> a.pow(2, 2, 2)
pow(int, int, int):
16
Python objects have special methods. Special methods are just methods that come packaged with a type. For example an int type has an __add__() special method that takes one argument. int.__add__(5) which will add 5 to that int (an actual number is a bad example for an object, but int is an object type which can work for this example). You often see this in code like this:
a = 10 + 5
which is kind of like
a = 10.__add__(5)
Not the best example, I know.
You can create your own class with a method
__add__(self, value)
and in that method you can check against what type value is, usually with isinstance(). If you check for all sorts of types in your __add__() method you are kind of doing polymorphism. Polymorphism like this is typically frowned upon in Python world. Why?
Well if you have a class called Car and an instance of that class called car, what does car = car + 5 mean? And if we add car + 'Sammy drives', what should print(car) print?
If you need to apply data of one type to an object and data of another type to the same object, then usually if is more clear to apply each data type to a specific attribute of that object. Like so:
car.speed = car.speed + 5
car.driver = 'Sammy'
Also I'd recommend getting to know about ducktyping. If you are good at it, checking for object types in your code kind of goes away.
Yes, you can use isinstance to check if an object is of a particular type.

Python: function and variable with the same name

Why can't I call the function again? Or, how can I make it?
Suppose I have this function:
def a(x, y, z):
if x:
return y
else:
return z
and I call it with:
print a(3>2, 4, 5)
I get 4.
But imagine that I declare a variable with the same name that the function (by mistake):
a=2
Now, if I try to do:
a=a(3>4, 4, 5)
or:
a(3>4, 4, 5)
I will get this error: "TypeError: 'int' object is not callable"
Is it not possible to assign the variable 'a' to the function?
After you do this:
a = 2
a is no longer a function, it's just an integer (you reassigned it!). So naturally the interpreter will complain if you try to invoke it as if it were a function, because you're doing this:
2()
=> TypeError: 'int' object is not callable
Bottom line: you can't have two things simultaneously with the same name, be it a function, an integer, or any other object in Python. Just use a different name.
names in Python are typically identifiers for a specific type, more like naming a box which stores a variable/function/method or any object in Python. When you are reassigning, you are just renaming a box.
You can find that out by doing the below.
Initially, a is assigned a value 9, at location 140515915925784.
As soon as I use the same identifier for a function , a now refers to a box containing the address of that function in 4512942512
Reassigning a to 3 again points a to refer to a different address.
>>> a = 9
>>> id(a)
140515915925784
>>> def a(x):
... return x
...
>>> id(a)
4512942512
>>> a
<function a at 0x10cfe09b0>
>>>
>>>
>>>
>>> a = 3
>>> id(a)
140515915925928
>>> a
3
>>>
You're assigning the name a to a function definition, and then reassigning it to an integer.
It's syntactically correct, but it's not what you want.
It's best to give functions semantic names that describe what you're doing with the arguments being passed to them, and to give variables semantic names that describe what object they're pointing to. If you do that, you'll have more readable code and you certainly won't make this mistake again.

How to check a dictionary for a class object value?

I have a dictionary, named
descendDict
And it contains 4 keys which are class objects, which have values that are both letters and other class objects.
Now what I'm trying to do is sort through the dictionary, and call out different actions if the value brought up in the dictionary is a class object, or if it is a letter:
for x in descendDict:
print x, descendDict[x]
for y in descendDict[x][0]:
if y != (classObject?):
#Action
for x in descendDict:
for z in descendDict[x][0]:
if z != (classObject?):
if y == z:
dist = 0
else:
dist = float(nodeDict[y]) + float(nodeDict[z])
In the if statements:
if... != (classObject?):
I am trying to determine whether the variable in the dictionary is, or is not a class object, but i just dont know how to do this.
Here is one the entries:
<__main__.Node instance at 0xb6738> ([<__main__.Node instance at 0xb6710>, 'A', <__main__.Node instance at 0xb6760>], '0.1')
I am sorting through it's first keys list, but i am trying to figure out if the values in the list are a class object, or a letter.
Not sure what you mean by "class object" since everything in Python is a first-class object. If you're trying to figure out if it's an instance of a specific class you can just use isinstance
if isinstance(y, someClass):
# do stuff
its better to define a method in your class then say
if hasattr(d[x],myClassMethodName):#then do this
else:#not a member
this method of checking allows much greater flexibility
for #RussellBorogove
try:
d[x].myMethod(*args,**kwargs)
except:
print "This is not an instance of my class and maybe a letter"
You probably want isinstance(x,type):
x = str
isinstance(x, type)
#=> True
class x(object):pass
isinstance(x, type)
#=> True
class x:pass
isinstance(x, type)
#=> False
x = "foo"
isinstance(x, type)
#=> False
Obviously, you'll have to stick to new-style classes, but you should be anyway.
However, it sounds like you're somehow trying to create your own object dispatch system. I strongly recommend that you move to some kind of common base class for all of your objects, and use method dispatch combined with higher-order methods to achieve whatever you're trying to do.
In Python it's common to use the "easier to ask forgiveness than permission" (EAFP) model, which looks like:
for y in collection:
try:
# treat it like it's a Node
y.actionMethod()
except AttributeError:
# that method doesn't exist, so it's not a Node
# do something else with it
print y
This is preferred over using isinstance(), because it allows you to define several otherwise unrelated classes each with their own actionMethod() without having to change this dispatch code.

Categories